Skip to content

Commit

Permalink
feat(erc20): implement Burnable extension (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
bidzyyys committed Apr 4, 2024
1 parent 2337f60 commit 59dd8f7
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 7 deletions.
5 changes: 3 additions & 2 deletions contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ wavm-shims = { path = "../lib/wavm-shims" }
default = []
erc20 = []
erc20_metadata = ["erc20"]
erc20_burnable = ["erc20"]
erc721 = []

[lib]
Expand All @@ -42,9 +43,9 @@ erc721 = []
# SDK. We don't set `lib` here because our contracts are meant to be used as an
# addition to other contracts. For this use case, the abi of those contracts
# will contain ours.
#
#
# The trade-off is being able to run `cargo test` with conditional compilation
# vs being able to run `cargo stylus export-abi`.
#
#
# This may change in the future, so this behavior should not be relied upon.
crate-type = ["cdylib"]
60 changes: 60 additions & 0 deletions contracts/src/erc20/extensions/burnable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use stylus_sdk::{
alloy_primitives::{Address, U256},
msg,
prelude::*,
};

use crate::erc20::{Error, ERC20};

sol_storage! {
pub struct ERC20Burnable {
ERC20 erc20;
}
}

#[external]
#[inherit(ERC20)]
impl ERC20Burnable {
/// Destroys a `value` amount of tokens from the caller.
/// lowering the total supply.
///
/// Relies on the `update` mechanism.
///
/// # Arguments
///
/// * `value` - Amount to be burnt.
///
/// If the `from` address doesn't have enough tokens, then the error
/// [`Error::InsufficientBalance`] is returned.
pub fn burn(&mut self, value: U256) -> Result<(), Error> {
self.erc20._burn(msg::sender(), value)
}

/// Destroys a `value` amount of tokens from `account`,
/// lowering the total supply.
///
/// Relies on the `update` mechanism.
///
/// # Arguments
///
/// * `account` - Owner's address.
/// * `value` - Amount to be burnt.
///
/// If not enough allowance is available, then the error
/// [`Error::InsufficientAllowance`] is returned.
/// * If the `from` address is `Address::ZERO`, then the error
/// [`Error::InvalidSender`] is returned.
/// If the `from` address doesn't have enough tokens, then the error
/// [`Error::InsufficientBalance`] is returned.
pub fn burn_from(
&mut self,
account: Address,
value: U256,
) -> Result<(), Error> {
self.erc20._spend_allowance(account, msg::sender(), value)?;
self.erc20._burn(account, value)
}
}

#[cfg(test)]
mod tests {}
3 changes: 3 additions & 0 deletions contracts/src/erc20/extensions/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
#[cfg(any(test, erc20_metadata))]
pub mod metadata;

#[cfg(any(test, erc20_burnable))]
pub mod burnable;
44 changes: 40 additions & 4 deletions contracts/src/erc20/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ sol! {
#[derive(Debug)]
error ERC20InvalidSpender(address spender);

/// Indicates a failure where an overflow error in math occured. Used in
/// Indicates a failure where an overflow error in math occurred. Used in
/// `_update`.
#[derive(Debug)]
error ERC20Overflow();
Expand All @@ -86,7 +86,7 @@ pub enum Error {
/// Indicates a failure with the `spender` to be approved. Used in
/// approvals.
InvalidSpender(ERC20InvalidSpender),
/// Indicates a failure where an overflow error in math occured. Used in
/// Indicates a failure where an overflow error in math occurred. Used in
/// `_update`.
Overflow(ERC20Overflow),
}
Expand Down Expand Up @@ -268,6 +268,10 @@ impl ERC20 {
///
/// # Errors
///
/// * If the `from` address is `Address::ZERO`, then the error
/// [`Error::InvalidSender`] is returned.
/// * If the `to` address is `Address::ZERO`, then the error
/// [`Error::InvalidReceiver`] is returned.
/// If the `from` address doesn't have enough tokens, then the error
/// [`Error::InsufficientBalance`] is returned.
fn _transfer(
Expand Down Expand Up @@ -303,9 +307,12 @@ impl ERC20 {
/// * `to` - Recipient's address.
/// * `value` - Amount to be transferred.
///
/// # Events
/// # Errors
///
/// * `Transfer`
/// If a math overflow error occurs, then the error
/// [`Error::Overflow`] is returned.
/// If the `from` address doesn't have enough tokens, then the error
/// [`Error::InsufficientBalance`] is returned.
pub fn _update(
&mut self,
from: Address,
Expand Down Expand Up @@ -356,6 +363,35 @@ impl ERC20 {
Ok(())
}

/// Destroys a `value` amount of tokens from `account`,
/// lowering the total supply.
///
/// Relies on the `update` mechanism.
///
/// # Arguments
///
/// * `account` - Owner's address.
/// * `value` - Amount to be burnt.
///
/// # Errors
///
/// * If the `from` address is `Address::ZERO`, then the error
/// [`Error::InvalidSender`] is returned.
/// If the `from` address doesn't have enough tokens, then the error
/// [`Error::InsufficientBalance`] is returned.
pub fn _burn(
&mut self,
account: Address,
value: U256,
) -> Result<(), Error> {
if account == Address::ZERO {
return Err(Error::InvalidSender(ERC20InvalidSender {
sender: Address::ZERO,
}));
}
self._update(account, Address::ZERO, value)
}

/// Updates `owner`'s allowance for `spender` based on spent `value`.
///
/// Does not update the allowance value in the case of infinite allowance.
Expand Down
1 change: 0 additions & 1 deletion docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
* xref:index.adoc[Overview]
* xref:crypto.adoc[Cryptography]

0 comments on commit 59dd8f7

Please sign in to comment.