Skip to content

Commit

Permalink
Add safe_transfer_from
Browse files Browse the repository at this point in the history
  • Loading branch information
0xNeshi committed Sep 19, 2024
1 parent ef2b0c8 commit a054e7e
Showing 1 changed file with 49 additions and 0 deletions.
49 changes: 49 additions & 0 deletions contracts/src/token/erc20/utils/safe_erc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ pub trait SafeErc20 {
to: Address,
value: U256,
) -> Result<(), Self::Error>;

/// 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.
fn safe_transfer_from(
&self,
from: Address,
to: Address,
value: U256,
) -> Result<(), Self::Error>;
}

impl SafeErc20 for Erc20 {
Expand All @@ -74,6 +83,23 @@ impl SafeErc20 for Erc20 {

self.call_optional_return(calldata)
}

fn safe_transfer_from(
&self,
from: Address,
to: Address,
value: U256,
) -> Result<(), Self::Error> {
type TransferType = (SOLAddress, SOLAddress, Uint<256>);
let tx_data = (from, to, value);
let data = TransferType::abi_encode_params(&tx_data);
let hashed_function_selector =
function_selector!("transferFrom", Address, Address, U256);
// Combine function selector and input data (use abi_packed way)
let calldata = [&hashed_function_selector[..4], &data].concat();

self.call_optional_return(calldata)
}
}

/// NOTE: Implementation of [`TopLevelStorage`] to be able use `&mut self` when
Expand Down Expand Up @@ -150,4 +176,27 @@ mod tests {
assert_eq!(initial_alice_balance + one, contract.balance_of(alice));
assert_eq!(initial_supply, contract.total_supply());
}

#[motsu::test]
fn transfers_from(contract: Erc20) {
let alice = address!("A11CEacF9aa32246d767FCCD72e02d6bCbcC375d");
let bob = address!("B0B0cB49ec2e96DF5F5fFB081acaE66A2cBBc2e2");
let sender = msg::sender();

// Alice approves `msg::sender`.
let one = uint!(1_U256);
contract._allowances.setter(alice).setter(sender).set(one);

// Mint some tokens for Alice.
let two = uint!(2_U256);
contract._update(Address::ZERO, alice, two).unwrap();
assert_eq!(two, contract.balance_of(alice));

let result = contract.safe_transfer_from(alice, bob, one);
assert!(result.is_ok());

assert_eq!(one, contract.balance_of(alice));
assert_eq!(one, contract.balance_of(bob));
assert_eq!(U256::ZERO, contract.allowance(alice, sender));
}
}

0 comments on commit a054e7e

Please sign in to comment.