Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: SafeErc20 utility #289

Merged
merged 87 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
98e0660
Add SafeErc20 + safe_transfer
0xNeshi Sep 17, 2024
025dc51
Add transfer param types when calc. selector
0xNeshi Sep 17, 2024
3db1217
Merge branch 'main' into safe-erc20
0xNeshi Sep 17, 2024
2287251
Add gas_left + fix has code check
0xNeshi Sep 18, 2024
eb779f1
Use RawCall with no value instead of Call
0xNeshi Sep 18, 2024
3182cc6
Remove unused imports
0xNeshi Sep 18, 2024
a3a4673
Add safe_transfer happy path test
0xNeshi Sep 19, 2024
05b235f
Fix test balance assertions
0xNeshi Sep 19, 2024
9e449f4
Mock erc20 contract address in raw call
0xNeshi Sep 19, 2024
025564a
Use function_selector to get the appropriate value
0xNeshi Sep 19, 2024
019ef51
Use Call instead of RawCall
0xNeshi Sep 19, 2024
33ef805
Use Call:new instead of new_in
0xNeshi Sep 19, 2024
ef2b0c8
Revert to RawCall
0xNeshi Sep 19, 2024
8041c47
Add safe_transfer_from
0xNeshi Sep 19, 2024
e4ba4e5
Format
0xNeshi Sep 19, 2024
1a47709
Update logic (removes safe_transfer_from)
0xNeshi Sep 19, 2024
e978a6b
Initialize tests
0xNeshi Sep 19, 2024
6e10c60
Fix token address in SafeErc20FailedOperation error
0xNeshi Sep 19, 2024
970e3cf
Use receipt instead of send
0xNeshi Sep 19, 2024
22092da
SafeErc20Example.safe_transfer_token->safe_transfer
0xNeshi Sep 19, 2024
1ed10b1
Simplify ERC20Mock
0xNeshi Sep 19, 2024
429b42d
Revert e2e-tests.sh
0xNeshi Sep 20, 2024
1348579
Add additional failure tests
0xNeshi Sep 20, 2024
3542d32
Use inherited ERC20 functions + remove redundant src/ERC20Mock.sol
0xNeshi Sep 23, 2024
b6ccccf
Rename reject-on-error test
0xNeshi Sep 23, 2024
c42aa9d
Add safe_transfer_from_+ tests + fix eoa rejection tests (fix alice a…
0xNeshi Sep 23, 2024
89240e6
Merge branch 'main' into safe-erc20
0xNeshi Sep 24, 2024
282e9f9
Fixed tests
0xNeshi Sep 24, 2024
23ca2af
Add stubs for the rest of ERC20-related safe-functions
0xNeshi Sep 24, 2024
53ab7f0
Add all required erc20 mocks
0xNeshi Sep 24, 2024
bcf1374
Simplify SafeErc20Example
0xNeshi Sep 24, 2024
29ea3b4
Extract has_no_code tests + Create the rest of has_no_code tests
0xNeshi Sep 25, 2024
423743b
Revert to using low level call
0xNeshi Sep 25, 2024
d47db5a
Implement forceApprove
0xNeshi Sep 25, 2024
bf1915a
Merge branch 'main' into safe-erc20
0xNeshi Sep 30, 2024
2b79af1
Implement safe_increase_allowance
0xNeshi Sep 30, 2024
306ec74
Refactor allowance-related fns
0xNeshi Sep 30, 2024
b88ee72
refactor
0xNeshi Sep 30, 2024
19f3448
IMplement safe_decrease_allowance
0xNeshi Sep 30, 2024
a7dd96d
Refactor arg encoding
0xNeshi Sep 30, 2024
bc7dc15
Fail with SafeErc20FailedDecreaseAllowance on failing to decrease all…
0xNeshi Sep 30, 2024
d3bb6ec
Implement return_false tests
0xNeshi Sep 30, 2024
8dd894e
Check whether return is true in call_optional_return
0xNeshi Sep 30, 2024
8739ec6
Use RawCall to limit the amount of returned data
0xNeshi Sep 30, 2024
5db49ad
Implement tests for USDT approval behavior
0xNeshi Sep 30, 2024
8ed5249
Add approvals test with zero init allowance
0xNeshi Oct 2, 2024
c90bee0
Add approvals test with non-zero init allowance
0xNeshi Oct 2, 2024
03f1777
Nest transfer-related tests into separate module
0xNeshi Oct 2, 2024
3168ec2
Fix call_optional_return Ok logic
0xNeshi Oct 2, 2024
e5736ff
Add erc20_that_doesnt_return tests
0xNeshi Oct 2, 2024
05f3e1a
Give more descriptive test file names
0xNeshi Oct 2, 2024
a5e803c
Merge branch 'main' into safe-erc20
0xNeshi Oct 2, 2024
e3b2782
Revert changes to e2e-tests.sh
0xNeshi Oct 2, 2024
ef3dba3
Fix comments
0xNeshi Oct 2, 2024
86f352c
Format constructor.sol
0xNeshi Oct 2, 2024
7034914
Merge branch 'main' into safe-erc20
0xNeshi Oct 3, 2024
a4c21fb
Remove empty constructor.sol
0xNeshi Oct 3, 2024
34eda9f
Align Cargo.toml deps
0xNeshi Oct 3, 2024
fde3b18
Fix typos
0xNeshi Oct 3, 2024
06d8112
Format with nightly
0xNeshi Oct 3, 2024
08d5ac6
Fix docs link to Erc20
0xNeshi Oct 3, 2024
ee6beb4
Add underscore prefix to call_optional_return->_call_optional_return
0xNeshi Oct 8, 2024
e325745
Move contract docs to the top of file
0xNeshi Oct 9, 2024
839517b
Refactor er20_that_doesnt_return tests
0xNeshi Oct 15, 2024
f006d42
Refactor all tests
0xNeshi Oct 15, 2024
6aa5d0d
Merge branch 'main' into safe-erc20
bidzyyys Oct 29, 2024
b4f78b1
Run format
0xNeshi Oct 29, 2024
e8b19a2
Merge branch 'OpenZeppelin:main' into safe-erc20
0xNeshi Oct 30, 2024
3b2bf2b
Merge branch 'main' into safe-erc20
bidzyyys Nov 5, 2024
b40b097
fix: compilation error
bidzyyys Nov 6, 2024
2e9169d
ref: add ISafeErc20 trait
bidzyyys Nov 6, 2024
b8f04ec
ref: improve code style
bidzyyys Nov 6, 2024
6f3f69e
ref: abi encode based on solidity interface
bidzyyys Nov 6, 2024
56e8c77
Merge branch 'main' into safe-erc20
bidzyyys Nov 6, 2024
caf1abb
Apply comment update suggestions from code review
0xNeshi Nov 6, 2024
4986938
ref: optimize the code
bidzyyys Nov 6, 2024
a52c2c0
docs: add Rust docs
bidzyyys Nov 6, 2024
d28435b
docs: update docs
bidzyyys Nov 6, 2024
95f4d08
test: add unit tests
bidzyyys Nov 6, 2024
7aa0539
test: check events in E2E tests
bidzyyys Nov 6, 2024
925e01a
test: E2E tests for failed internal Erc20 operations
bidzyyys Nov 6, 2024
b48ea0e
test: E2E check for math overflow
bidzyyys Nov 7, 2024
b765521
docs: update CHANGELOG
bidzyyys Nov 7, 2024
893a5b6
fix: apply clippy comments
bidzyyys Nov 7, 2024
9a26dbf
grammar fixes
qalisander Nov 7, 2024
1fe32cb
add dots on comments
qalisander Nov 7, 2024
6c447e1
Merge branch 'main' into safe-erc20
bidzyyys Nov 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ members = [
"examples/basic/token",
"examples/basic/script",
"examples/ecdsa",
"examples/safe-erc20",
"benches",
]
default-members = [
Expand All @@ -30,6 +31,7 @@ default-members = [
"examples/erc721",
"examples/erc721-consecutive",
"examples/erc721-metadata",
"examples/safe-erc20",
"examples/merkle-proofs",
"examples/ownable",
"examples/access-control",
Expand Down
1 change: 1 addition & 0 deletions contracts/src/token/erc20/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use stylus_sdk::{
};

pub mod extensions;
pub mod utils;

sol! {
/// Emitted when `value` tokens are moved from one account (`from`) to
Expand Down
4 changes: 4 additions & 0 deletions contracts/src/token/erc20/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//! Utilities for the ERC-20 standard.
pub mod safe_erc20;

pub use safe_erc20::SafeErc20;
131 changes: 131 additions & 0 deletions contracts/src/token/erc20/utils/safe_erc20.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
//! Wrappers around ERC-20 operations that throw on failure.

use alloy_primitives::{Address, U256};
use alloy_sol_types::sol;
use stylus_proc::{public, sol_interface, sol_storage, SolidityError};
use stylus_sdk::{call::Call, storage::TopLevelStorage, types::AddressVM};

use crate::token::erc20;

sol! {
/// An operation with an ERC-20 token failed.
bidzyyys marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Debug)]
#[allow(missing_docs)]
error SafeErc20FailedOperation(address token);

/// Indicates a failed `decreaseAllowance` request.
#[derive(Debug)]
#[allow(missing_docs)]
error SafeErc20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
bidzyyys marked this conversation as resolved.
Show resolved Hide resolved
}

/// A SafeErc20 error
bidzyyys marked this conversation as resolved.
Show resolved Hide resolved
#[derive(SolidityError, Debug)]
pub enum Error {
/// Error type from [`Erc20`] contract [`erc20::Error`].
Erc20(erc20::Error),
/// An operation with an ERC-20 token failed.
SafeErc20FailedOperation(SafeErc20FailedOperation),
/// Indicates a failed `decreaseAllowance` request.
SafeErc20FailedDecreaseAllowance(SafeErc20FailedDecreaseAllowance),
}

sol_interface! {
/// Interface of the ERC-20 standard as defined in the ERC.
interface IERC20 {
/// Moves a `value` amount of tokens from the caller's account to `to`.
///
/// Returns a boolean value indicating whether the operation succeeded.
///
/// Emits a {Transfer} event.
function transfer(address to, uint256 amount) external returns (bool);

/// Moves a `value` amount of tokens from `from` to `to` using the
/// allowance mechanism. `value` is then deducted from the caller's
/// allowance.
///
/// Returns a boolean value indicating whether the operation succeeded.
///
/// Emits a {Transfer} event.
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
}

sol_storage! {
/// Wrappers around ERC-20 operations that throw on failure (when the token
/// contract returns false). Tokens that return no value (and instead revert or
/// throw on failure) are also supported, non-reverting calls are assumed to be
/// successful.
/// To use this library you can add a `using SafeERC20 for IERC20;` statement to
/// your contract, which allows you to call the safe operations as
/// `token.safeTransfer(...)`, etc.
pub struct SafeErc20 {}
}

/// NOTE: Implementation of [`TopLevelStorage`] to be able use `&mut self` when
/// calling other contracts and not `&mut (impl TopLevelStorage +
/// BorrowMut<Self>)`. Should be fixed in the future by the Stylus team.
unsafe impl TopLevelStorage for SafeErc20 {}

#[public]
impl SafeErc20 {
bidzyyys marked this conversation as resolved.
Show resolved Hide resolved
/// Transfer `value` amount of `token` from the calling contract to `to`. If
/// `token` returns no value, non-reverting calls are assumed to be
/// successful.
pub fn safe_transfer(
bidzyyys marked this conversation as resolved.
Show resolved Hide resolved
&mut self,
token: Address,
to: Address,
value: U256,
) -> Result<(), Error> {
let erc20 = IERC20::new(token);
let call = Call::new_in(self);

match erc20.transfer(call, to, value) {
Ok(data) => {
if data && !Address::has_code(&token) {
return Err(Error::SafeErc20FailedOperation(
SafeErc20FailedOperation { token },
));
}
}
Err(_) => {
return Err(Error::SafeErc20FailedOperation(
SafeErc20FailedOperation { token },
))
}
}

Ok(())
}

/// Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
/// calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
pub fn safe_transfer_from(
bidzyyys marked this conversation as resolved.
Show resolved Hide resolved
&mut self,
token: Address,
from: Address,
to: Address,
value: U256,
) -> Result<(), Error> {
let erc20 = IERC20::new(token);
let call = Call::new_in(self);

match erc20.transfer_from(call, from, to, value) {
Ok(data) => {
if data && !Address::has_code(&token) {
return Err(Error::SafeErc20FailedOperation(
SafeErc20FailedOperation { token },
));
}
}
Err(_) => {
return Err(Error::SafeErc20FailedOperation(
SafeErc20FailedOperation { token },
))
}
}

Ok(())
}
}
26 changes: 26 additions & 0 deletions examples/safe-erc20/Cargo.toml
0xNeshi marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "safe-erc20-example"
edition.workspace = true
license.workspace = true
repository.workspace = true
publish = false
version = "0.0.0"

[dependencies]
openzeppelin-stylus = { path = "../../contracts" }
alloy-primitives = { workspace = true, features = ["tiny-keccak"] }
stylus-sdk.workspace = true
stylus-proc.workspace = true
mini-alloc.workspace = true

[dev-dependencies]
alloy.workspace = true
eyre.workspace = true
tokio.workspace = true
e2e = { path = "../../lib/e2e" }

[features]
e2e = []

[lib]
crate-type = ["lib", "cdylib"]
5 changes: 5 additions & 0 deletions examples/safe-erc20/src/constructor.sol
0xNeshi marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

contract SafeErc20Example {
}
29 changes: 29 additions & 0 deletions examples/safe-erc20/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#![cfg_attr(not(test), no_main, no_std)]
bidzyyys marked this conversation as resolved.
Show resolved Hide resolved
extern crate alloc;

use alloy_primitives::{Address, U256};
use openzeppelin_stylus::token::erc20::utils::safe_erc20::{Error, SafeErc20};
use stylus_sdk::prelude::{entrypoint, public, sol_storage};

sol_storage! {
#[entrypoint]
struct SafeErc20Example {
#[borrow]
SafeErc20 safe_erc20;
}
}

#[public]
#[inherit(SafeErc20)]
impl SafeErc20Example {
// Add token minting feature.
pub fn safe_transfer(
&mut self,
token: Address,
to: Address,
value: U256,
) -> Result<(), Error> {
self.safe_erc20.safe_transfer(token, to, value)?;
Ok(())
}
}
13 changes: 13 additions & 0 deletions examples/safe-erc20/tests/abi/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#![allow(dead_code)]
use alloy::sol;

sol!(
#[sol(rpc)]
contract SafeErc20 {
function safeTransfer(address token, address to, uint256 value) external;
function safeTransferFrom(address token, address from, address to, uint256 value) external;

error SafeErc20FailedOperation(address token);
error SafeErc20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
}
);
40 changes: 40 additions & 0 deletions examples/safe-erc20/tests/mock/erc20.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#![allow(dead_code)]
#![cfg(feature = "e2e")]
use alloy::{primitives::Address, sol};
use e2e::Wallet;

sol! {
#[allow(missing_docs)]
// Built with Remix IDE; solc v0.8.21+commit.d9974bed
#[sol(rpc, bytecode="608060405234801562000010575f80fd5b506040518060400160405280600781526020017f4d79546f6b656e000000000000000000000000000000000000000000000000008152506040518060400160405280600381526020017f4d544b000000000000000000000000000000000000000000000000000000000081525081600390816200008e91906200030d565b508060049081620000a091906200030d565b505050620003f1565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200012557607f821691505b6020821081036200013b576200013a620000e0565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026200019f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000162565b620001ab868362000162565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f620001f5620001ef620001e984620001c3565b620001cc565b620001c3565b9050919050565b5f819050919050565b6200021083620001d5565b620002286200021f82620001fc565b8484546200016e565b825550505050565b5f90565b6200023e62000230565b6200024b81848462000205565b505050565b5b818110156200027257620002665f8262000234565b60018101905062000251565b5050565b601f821115620002c1576200028b8162000141565b620002968462000153565b81016020851015620002a6578190505b620002be620002b58562000153565b83018262000250565b50505b505050565b5f82821c905092915050565b5f620002e35f1984600802620002c6565b1980831691505092915050565b5f620002fd8383620002d2565b9150826002028217905092915050565b6200031882620000a9565b67ffffffffffffffff811115620003345762000333620000b3565b5b6200034082546200010d565b6200034d82828562000276565b5f60209050601f83116001811462000383575f84156200036e578287015190505b6200037a8582620002f0565b865550620003e9565b601f198416620003938662000141565b5f5b82811015620003bc5784890151825560018201915060208501945060208101905062000395565b86831015620003dc5784890151620003d8601f891682620002d2565b8355505b6001600288020188555050505b505050505050565b610efb80620003ff5f395ff3fe608060405234801561000f575f80fd5b506004361061009c575f3560e01c806340c10f191161006457806340c10f191461015a57806370a082311461017657806395d89b41146101a6578063a9059cbb146101c4578063dd62ed3e146101f45761009c565b806306fdde03146100a0578063095ea7b3146100be57806318160ddd146100ee57806323b872dd1461010c578063313ce5671461013c575b5f80fd5b6100a8610224565b6040516100b59190610b74565b60405180910390f35b6100d860048036038101906100d39190610c25565b6102b4565b6040516100e59190610c7d565b60405180910390f35b6100f66102c7565b6040516101039190610ca5565b60405180910390f35b61012660048036038101906101219190610cbe565b6102d0565b6040516101339190610c7d565b60405180910390f35b6101446102e5565b6040516101519190610d29565b60405180910390f35b610174600480360381019061016f9190610c25565b6102ed565b005b610190600480360381019061018b9190610d42565b6102fb565b60405161019d9190610ca5565b60405180910390f35b6101ae61030c565b6040516101bb9190610b74565b60405180910390f35b6101de60048036038101906101d99190610c25565b61039c565b6040516101eb9190610c7d565b60405180910390f35b61020e60048036038101906102099190610d6d565b6103af565b60405161021b9190610ca5565b60405180910390f35b60606003805461023390610dd8565b80601f016020809104026020016040519081016040528092919081815260200182805461025f90610dd8565b80156102aa5780601f10610281576101008083540402835291602001916102aa565b820191905f5260205f20905b81548152906001019060200180831161028d57829003601f168201915b5050505050905090565b5f6102bf8383610431565b905092915050565b5f600254905090565b5f6102dc848484610453565b90509392505050565b5f6012905090565b6102f78282610481565b5050565b5f61030582610500565b9050919050565b60606004805461031b90610dd8565b80601f016020809104026020016040519081016040528092919081815260200182805461034790610dd8565b80156103925780601f1061036957610100808354040283529160200191610392565b820191905f5260205f20905b81548152906001019060200180831161037557829003601f168201915b5050505050905090565b5f6103a78383610545565b905092915050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f8061043b610567565b905061044881858561056e565b600191505092915050565b5f8061045d610567565b905061046a858285610580565b610475858585610612565b60019150509392505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036104f1575f6040517fec442f050000000000000000000000000000000000000000000000000000000081526004016104e89190610e17565b60405180910390fd5b6104fc5f8383610702565b5050565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b5f8061054f610567565b905061055c818585610612565b600191505092915050565b5f33905090565b61057b838383600161091b565b505050565b5f61058b84846103af565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811461060c57818110156105fd578281836040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526004016105f493929190610e30565b60405180910390fd5b61060b84848484035f61091b565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610682575f6040517f96c6fd1e0000000000000000000000000000000000000000000000000000000081526004016106799190610e17565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036106f2575f6040517fec442f050000000000000000000000000000000000000000000000000000000081526004016106e99190610e17565b60405180910390fd5b6106fd838383610702565b505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610752578060025f8282546107469190610e92565b92505081905550610820565b5f805f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050818110156107db578381836040517fe450d38c0000000000000000000000000000000000000000000000000000000081526004016107d293929190610e30565b60405180910390fd5b8181035f808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610867578060025f82825403925050819055506108b1565b805f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161090e9190610ca5565b60405180910390a3505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361098b575f6040517fe602df050000000000000000000000000000000000000000000000000000000081526004016109829190610e17565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036109fb575f6040517f94280d620000000000000000000000000000000000000000000000000000000081526004016109f29190610e17565b60405180910390fd5b8160015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508015610ae4578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610adb9190610ca5565b60405180910390a35b50505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610b21578082015181840152602081019050610b06565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610b4682610aea565b610b508185610af4565b9350610b60818560208601610b04565b610b6981610b2c565b840191505092915050565b5f6020820190508181035f830152610b8c8184610b3c565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610bc182610b98565b9050919050565b610bd181610bb7565b8114610bdb575f80fd5b50565b5f81359050610bec81610bc8565b92915050565b5f819050919050565b610c0481610bf2565b8114610c0e575f80fd5b50565b5f81359050610c1f81610bfb565b92915050565b5f8060408385031215610c3b57610c3a610b94565b5b5f610c4885828601610bde565b9250506020610c5985828601610c11565b9150509250929050565b5f8115159050919050565b610c7781610c63565b82525050565b5f602082019050610c905f830184610c6e565b92915050565b610c9f81610bf2565b82525050565b5f602082019050610cb85f830184610c96565b92915050565b5f805f60608486031215610cd557610cd4610b94565b5b5f610ce286828701610bde565b9350506020610cf386828701610bde565b9250506040610d0486828701610c11565b9150509250925092565b5f60ff82169050919050565b610d2381610d0e565b82525050565b5f602082019050610d3c5f830184610d1a565b92915050565b5f60208284031215610d5757610d56610b94565b5b5f610d6484828501610bde565b91505092915050565b5f8060408385031215610d8357610d82610b94565b5b5f610d9085828601610bde565b9250506020610da185828601610bde565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680610def57607f821691505b602082108103610e0257610e01610dab565b5b50919050565b610e1181610bb7565b82525050565b5f602082019050610e2a5f830184610e08565b92915050565b5f606082019050610e435f830186610e08565b610e506020830185610c96565b610e5d6040830184610c96565b949350505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610e9c82610bf2565b9150610ea783610bf2565b9250828201905080821115610ebf57610ebe610e65565b5b9291505056fea26469706673582212204b0d5b8c644aa4b312a9bee1615964e800240731dcc271c19c1615f2940a1ed564736f6c63430008150033")]
// SPDX-License-Identifier: MIT
contract ERC20Mock is ERC20 {
constructor() ERC20("MyToken", "MTK") {}

function approve(address spender, uint256 value) public override returns (bool) {
return super.approve(spender, value);
}

function balanceOf(address account) public override view returns (uint256) {
return super.balanceOf(account);
}

function mint(address account, uint256 value) public {
super._mint(account, value);
}

function transfer(address to, uint256 amount) public override returns (bool) {
return super.transfer(to, amount);
0xNeshi marked this conversation as resolved.
Show resolved Hide resolved
}

function transferFrom(address from, address to, uint256 value) public override returns (bool) {
return super.transferFrom(from, to, value);
}
}
}

pub async fn deploy(wallet: &Wallet) -> eyre::Result<Address> {
// Deploy the contract.
let contract = ERC20Mock::deploy(wallet).await?;
Ok(*contract.address())
}
1 change: 1 addition & 0 deletions examples/safe-erc20/tests/mock/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod erc20;
Loading