Skip to content

Commit 98ef15c

Browse files
dchatzieleftheriou-bcpaulo-bc
authored andcommitted
Adds custom address_reference
# Conflicts: # rust/tw_evm/src/modules/tx_builder.rs
1 parent 221584f commit 98ef15c

8 files changed

Lines changed: 87 additions & 4 deletions

File tree

rust/tw_evm/src/abi/function.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,11 @@ impl Function {
6464
}
6565
}
6666

67+
// Note: the `short_signature` methods only takes the `input_param_types` which come from the ERC20 abi (see erc20.abi.json)
68+
// as a result it will create the correct signature regardless of the passed Tokens,
69+
// Any extra Token that do not appear on the ERC20 Abi json will be ignored!
6770
let signed = short_signature(&self.name, &input_param_types);
71+
// this encodes all the given Tokens
6872
let encoded = encode_tokens(tokens);
6973
Ok(signed.into_iter().chain(encoded).collect())
7074
}

rust/tw_evm/src/abi/prebuild/erc20.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,13 @@ lazy_static! {
2121
pub struct Erc20;
2222

2323
impl Erc20 {
24-
pub fn transfer(recipient: Address, amount: U256) -> AbiResult<Data> {
24+
pub fn transfer(recipient: Address, amount: U256, address_reference: Option<Address>) -> AbiResult<Data> {
2525
let func = ERC20.function("transfer")?;
26-
func.encode_input(&[Token::Address(recipient), Token::u256(amount)])
26+
if let Some(address_ref) = address_reference {
27+
func.encode_input(&[Token::Address(recipient), Token::u256(amount), Token::Address(address_ref)])
28+
} else {
29+
func.encode_input(&[Token::Address(recipient), Token::u256(amount)])
30+
}
2731
}
2832

2933
pub fn approve(spender: Address, amount: U256) -> AbiResult<Data> {

rust/tw_evm/src/modules/tx_builder.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ impl<Context: EvmContext> TxBuilder<Context> {
5959
let contract_address =
6060
Self::parse_address(&input.to_address).context("Invalid Contract address")?;
6161

62-
let payload = Erc20::transfer(token_to_address, token_amount)
62+
let token_address_reference = Self::parse_address_optional(&erc20_transfer.address_reference)?;
63+
64+
let payload = Erc20::transfer(token_to_address, token_amount, token_address_reference)
6365
.map_err(abi_to_signing_error)?;
6466
(U256::zero(), payload, Some(contract_address))
6567
},

rust/tw_evm/tests/barz.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ fn test_barz_batched_account_deployed() {
141141
{
142142
let recipient = Address::from("0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789");
143143
let amount = U256::from(0x8AC7_2304_89E8_0000_u64);
144-
let payload = Erc20::transfer(recipient, amount).unwrap();
144+
let address_ref: Option<Address> = None;
145+
let payload = Erc20::transfer(recipient, amount, address_ref).unwrap();
145146

146147
calls.push(Proto::mod_Transaction::mod_Batch::BatchedCall {
147148
address: contract_address.into(),

rust/tw_evm/tests/signer.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ fn test_sign_transaction_non_typed_erc20_transfer() {
1919
let erc20_transfer = Proto::mod_Transaction::ERC20Transfer {
2020
to: "0x5322b34c88ed0691971bf52a7047448f0f4efc84".into(),
2121
amount: U256::encode_be_compact(2_000_000_000_000_000_000),
22+
address_reference: Cow::default()
2223
};
2324

2425
let input = Proto::SigningInput {
@@ -52,6 +53,48 @@ fn test_sign_transaction_non_typed_erc20_transfer() {
5253
);
5354
}
5455

56+
#[test]
57+
fn test_sign_transaction_non_typed_erc20_transfer_address_ref() {
58+
let private =
59+
hex::decode("0x608dcb1742bb3fb7aec002074e3420e4fab7d00cced79ccdac53ed5b27138151").unwrap();
60+
61+
let erc20_transfer = Proto::mod_Transaction::ERC20Transfer {
62+
to: "0x5322b34c88ed0691971bf52a7047448f0f4efc84".into(),
63+
amount: U256::encode_be_compact(2_000_000_000_000_000_000),
64+
address_reference: "0x3535353535353535353535353535353535353535".into()
65+
};
66+
67+
let input = Proto::SigningInput {
68+
chain_id: U256::encode_be_compact(1),
69+
tx_mode: TransactionMode::Legacy,
70+
// 42000000000
71+
gas_price: U256::encode_be_compact(0x09_c765_2400),
72+
// 78009
73+
gas_limit: U256::encode_be_compact(0x01_30B9),
74+
// DAI
75+
to_address: "0x6b175474e89094c44da98b954eedeac495271d0f".into(),
76+
transaction: Some(Proto::Transaction {
77+
transaction_oneof: Proto::mod_Transaction::OneOftransaction_oneof::erc20_transfer(
78+
erc20_transfer,
79+
),
80+
}),
81+
private_key: private.into(),
82+
..Proto::SigningInput::default()
83+
};
84+
85+
let output = Signer::<StandardEvmContext>::sign_proto(input);
86+
assert_eq!(output.error, SigningErrorType::OK);
87+
assert!(output.error_message.is_empty());
88+
89+
let expected = "f8ca808509c7652400830130b9946b175474e89094c44da98b954eedeac495271d0f80b864a9059cbb0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000001bc16d674ec80000000000000000000000000000353535353535353535353535353535353535353525a04bf4664fc9a274a5b8cfa0d6ee7c904787c02825856d25896d225aff4efd3802a04e174f780c13a4b99ac1ee9528cef4e22dc475be68d4eb4944b7c61bd016be60";
90+
assert_eq!(hex::encode(output.encoded, false), expected);
91+
92+
assert_eq!(
93+
hex::encode(output.data, false),
94+
"a9059cbb0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000001bc16d674ec800000000000000000000000000003535353535353535353535353535353535353535"
95+
);
96+
}
97+
5598
#[test]
5699
fn test_sign_transaction_non_typed_native() {
57100
let private =
@@ -247,6 +290,7 @@ fn test_sign_transaction_eip1559_erc20_transfer() {
247290
let erc20_transfer = Proto::mod_Transaction::ERC20Transfer {
248291
to: "0x5322b34c88ed0691971bf52a7047448f0f4efc84".into(),
249292
amount: U256::encode_be_compact(2_000_000_000_000_000_000),
293+
address_reference: Cow::default(),
250294
};
251295

252296
let input = Proto::SigningInput {
@@ -468,6 +512,7 @@ fn test_sign_transaction_non_typed_erc20_transfer_invalid_address() {
468512
let erc20_transfer = Proto::mod_Transaction::ERC20Transfer {
469513
to: "0x5322b34c88ed0691971bf52a7047448f0f4efc84".into(),
470514
amount: U256::encode_be_compact(2_000_000_000_000_000_000),
515+
address_reference: Cow::default()
471516
};
472517

473518
let input = Proto::SigningInput {

rust/tw_proto/tests/proto_tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ fn test_serialize_deserialize() {
6464
let expected_erc20 = Ethereum::Proto::mod_Transaction::ERC20Transfer {
6565
to: Cow::from("0x5322b34c88ed0691971bf52a7047448f0f4efc84"),
6666
amount: Cow::Borrowed(&[27u8, 193, 109, 103, 78, 200, 0, 0]),
67+
address_reference: Cow::default(),
6768
};
6869
let expected_tx = Ethereum::Proto::Transaction {
6970
transaction_oneof: Ethereum::Proto::mod_Transaction::OneOftransaction_oneof::erc20_transfer(

src/proto/Ethereum.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ message Transaction {
2323

2424
// Amount to send (uint256, serialized big endian)
2525
bytes amount = 2;
26+
27+
// Optional address
28+
string address_reference = 3;
2629
}
2730

2831
// ERC20 approve transaction

swift/Tests/Blockchains/EthereumTests.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,29 @@ class EthereumTests: XCTestCase {
6262
XCTAssertEqual(output.encoded.hexString, "f8aa808509c7652400830130b9946b175474e89094c44da98b954eedeac495271d0f80b844a9059cbb0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000001bc16d674ec8000025a0724c62ad4fbf47346b02de06e603e013f26f26b56fdc0be7ba3d6273401d98cea0032131cae15da7ddcda66963e8bef51ca0d9962bfef0547d3f02597a4a58c931")
6363
XCTAssertEqual(output.data.hexString, "a9059cbb0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000001bc16d674ec80000")
6464
}
65+
66+
func testSignERC20Transfer_addressReference() {
67+
let input = EthereumSigningInput.with {
68+
$0.chainID = Data(hexString: "01")!
69+
$0.nonce = Data(hexString: "00")!
70+
// txMode not set, Legacy is the default
71+
$0.gasPrice = Data(hexString: "09c7652400")! // 42000000000
72+
$0.gasLimit = Data(hexString: "0130B9")! // 78009
73+
$0.toAddress = "0x6b175474e89094c44da98b954eedeac495271d0f" // DAI
74+
$0.privateKey = Data(hexString: "0x608dcb1742bb3fb7aec002074e3420e4fab7d00cced79ccdac53ed5b27138151")!
75+
$0.transaction = EthereumTransaction.with {
76+
$0.erc20Transfer = EthereumTransaction.ERC20Transfer.with {
77+
$0.to = "0x5322b34c88ed0691971bf52a7047448f0f4efc84"
78+
$0.amount = Data(hexString: "1bc16d674ec80000")! // 2000000000000000000
79+
$0.addressReference = "0x3535353535353535353535353535353535353535"
80+
}
81+
}
82+
}
83+
let output: EthereumSigningOutput = AnySigner.sign(input: input, coin: .ethereum)
84+
85+
XCTAssertEqual(output.encoded.hexString, "f8ca808509c7652400830130b9946b175474e89094c44da98b954eedeac495271d0f80b864a9059cbb0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000001bc16d674ec80000000000000000000000000000353535353535353535353535353535353535353525a04bf4664fc9a274a5b8cfa0d6ee7c904787c02825856d25896d225aff4efd3802a04e174f780c13a4b99ac1ee9528cef4e22dc475be68d4eb4944b7c61bd016be60")
86+
XCTAssertEqual(output.data.hexString, "a9059cbb0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000001bc16d674ec800000000000000000000000000003535353535353535353535353535353535353535")
87+
}
6588

6689
func testSignERC20Transfer_1559() {
6790
let input = EthereumSigningInput.with {

0 commit comments

Comments
 (0)