Skip to content

Commit

Permalink
parse call data from Card Manager
Browse files Browse the repository at this point in the history
  • Loading branch information
kevtechi committed Jul 7, 2024
1 parent fcc72f7 commit bf6a436
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 15 deletions.
60 changes: 45 additions & 15 deletions internal/common/calldata.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ var (
ErrNotTransfer = errors.New("not a transfer")

executeSigSingle = crypto.Keccak256([]byte("execute(address,uint256,bytes)"))[:4]
transferSig = crypto.Keccak256([]byte("transfer(address,uint256)"))[:4]

transferSig = crypto.Keccak256([]byte("transfer(address,uint256)"))[:4]
withdrawSig = crypto.Keccak256([]byte("withdraw(bytes32,address,address,uint256)"))[:4]
)

// ParseERC20Transfer parses the calldata of an ERC20 transfer from a smart contract Execute function
Expand All @@ -41,24 +43,52 @@ func ParseERC20Transfer(calldata []byte) (common.Address, common.Address, *big.I
// The third argument is the funcData, which starts 96 bytes offset from the start of the args
funcData := args[128:132]

// The first 4 bytes of the funcData is the transfer function selector
trfFuncSelector := funcData[:4]
if !bytes.Equal(trfFuncSelector, transferSig) {
return common.Address{}, common.Address{}, nil, ErrNotTransfer
}

funcArgs := args[132:]
// Depending on the function selector, the arguments are in different positions
switch string(trfFuncSelector) {
case string(transferSig):
// Standard ERC20 transfer
funcArgs := args[132:]

// The first argument of the funcData is the to address, which is 32 bytes offset from the start of the funcData
to := common.BytesToAddress(funcArgs[32-20 : 32])
if len(to.Bytes()) == 0 {
return common.Address{}, common.Address{}, nil, ErrInvalidCalldata
}
// The first argument of the funcData is the to address, which is 32 bytes offset from the start of the funcData
to := common.BytesToAddress(funcArgs[32-20 : 32])
if len(to.Bytes()) == 0 {
return common.Address{}, common.Address{}, nil, ErrInvalidCalldata
}

// The second argument of the funcData is the amount, which is 64 bytes offset from the start of the funcData
amount := new(big.Int).SetBytes(funcArgs[64-32 : 64])
if amount.Cmp(big.NewInt(0)) == 0 {
return common.Address{}, common.Address{}, nil, ErrInvalidCalldata
// The second argument of the funcData is the amount, which is 64 bytes offset from the start of the funcData
amount := new(big.Int).SetBytes(funcArgs[64-32 : 64])
if amount.Cmp(big.NewInt(0)) == 0 {
return common.Address{}, common.Address{}, nil, ErrInvalidCalldata
}

return dest, to, amount, nil
case string(withdrawSig):
// Withdraw function from the Card Manager
funcArgs := args[132:]

// The second argument of the funcData is the token address, which is 64 bytes offset from the start of the funcData
dest := common.BytesToAddress(funcArgs[64-20 : 64])
if len(dest.Bytes()) == 0 {
return common.Address{}, common.Address{}, nil, ErrInvalidCalldata
}

// The third argument of the funcData is the to address, which is 96 bytes offset from the start of the funcData
to := common.BytesToAddress(funcArgs[96-20 : 96])
if len(to.Bytes()) == 0 {
return common.Address{}, common.Address{}, nil, ErrInvalidCalldata
}

// The fourth argument of the funcData is the amount, which is 128 bytes offset from the start of the funcData
amount := new(big.Int).SetBytes(funcArgs[128-32 : 128])
if amount.Cmp(big.NewInt(0)) == 0 {
return common.Address{}, common.Address{}, nil, ErrInvalidCalldata
}

return dest, to, amount, nil
}

return dest, to, amount, nil
return common.Address{}, common.Address{}, nil, ErrNotTransfer
}
6 changes: 6 additions & 0 deletions internal/common/calldata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ var testCases = []string{
"0x",
"0xb61d27f60000000000000000000000005815e61ef72c9e6107b5c5a05fd121f334f7a7f1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044a9059cbb00000000000000000000000029d755c17df3ed2ecae6e42d694fb4f7e2ff6010000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000",
"0xb61d27f6000000000000000000000000eec0f3257369c6bcd2fd8755cbef8a95b12bc4c90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c49d91dd7d000000000000000000000000d5e60a846ab25f73a5b405dfca83de1ba98fe99720202020202020202020202020202020202020202020202020207861766965720000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002e516d50316d786637354250794a76367434657833666248626153784874716d4470444b454d55514b44504d48707600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"0xb61d27f6000000000000000000000000c0f9e0907c8de79fd5902b61e463dfedc5dc85700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000848e0cc176437a77d18f8574e019c1e2754adcd7848f6b9b701d8d6db261ea6b979bf6c80d0000000000000000000000005815e61ef72c9e6107b5c5a05fd121f334f7a7f1000000000000000000000000cfa21b33d304d57c4e964e3819588eb5ac06b4d900000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000",
}

type caseResult struct {
Expand Down Expand Up @@ -38,6 +39,11 @@ var expected = []caseResult{
Amount: big.NewInt(0),
Err: ErrNotTransfer,
},
{
Dest: common.HexToAddress("0x5815E61eF72c9E6107b5c5A05FD121F334f7a7f1"),
To: common.HexToAddress("0xcfa21B33D304D57c4E964e3819588Eb5ac06B4D9"),
Amount: big.NewInt(1000000),
},
}

func TestParseERC20Transfer(t *testing.T) {
Expand Down

0 comments on commit bf6a436

Please sign in to comment.