Skip to content

Commit

Permalink
test: add TestDirtyStateAttack2
Browse files Browse the repository at this point in the history
  • Loading branch information
k-yang committed Jan 22, 2025
1 parent 9d231c3 commit dfe0f08
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "TestDirtyStateAttack2",
"sourceName": "contracts/TestDirtyStateAttack2.sol",
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "erc20_",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "address payable",
"name": "sendRecipient",
"type": "address"
},
{
"internalType": "string",
"name": "bech32Recipient",
"type": "string"
}
],
"name": "attack",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x608060405234801561001057600080fd5b50604051610960380380610960833981810160405281019061003291906100db565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610108565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006100a88261007d565b9050919050565b6100b88161009d565b81146100c357600080fd5b50565b6000815190506100d5816100af565b92915050565b6000602082840312156100f1576100f0610078565b5b60006100ff848285016100c6565b91505092915050565b610849806101176000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063e655beb414610030575b600080fd5b61004a6004803603810190610045919061046d565b61004c565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83620f42406040518363ffffffff1660e01b81526004016100aa92919061056d565b6020604051808303816000875af11580156100c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100ed91906105ce565b61012c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161012390610658565b60405180910390fd5b600061080073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16628954408460405160240161017f93929190610716565b6040516020818303038152906040527fe77a47bf000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610209919061079b565b6000604051808303816000865af19150503d8060008114610246576040519150601f19603f3d011682016040523d82523d6000602084013e61024b565b606091505b505090508060405160200161025f906107d8565b604051602081830303815290604052906102af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102a691906107f1565b60405180910390fd5b50505050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102f4826102c9565b9050919050565b610304816102e9565b811461030f57600080fd5b50565b600081359050610321816102fb565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61037a82610331565b810181811067ffffffffffffffff8211171561039957610398610342565b5b80604052505050565b60006103ac6102b5565b90506103b88282610371565b919050565b600067ffffffffffffffff8211156103d8576103d7610342565b5b6103e182610331565b9050602081019050919050565b82818337600083830152505050565b600061041061040b846103bd565b6103a2565b90508281526020810184848401111561042c5761042b61032c565b5b6104378482856103ee565b509392505050565b600082601f83011261045457610453610327565b5b81356104648482602086016103fd565b91505092915050565b60008060408385031215610484576104836102bf565b5b600061049285828601610312565b925050602083013567ffffffffffffffff8111156104b3576104b26102c4565b5b6104bf8582860161043f565b9150509250929050565b6000819050919050565b60006104ee6104e96104e4846102c9565b6104c9565b6102c9565b9050919050565b6000610500826104d3565b9050919050565b6000610512826104f5565b9050919050565b61052281610507565b82525050565b6000819050919050565b6000819050919050565b600061055761055261054d84610528565b6104c9565b610532565b9050919050565b6105678161053c565b82525050565b60006040820190506105826000830185610519565b61058f602083018461055e565b9392505050565b60008115159050919050565b6105ab81610596565b81146105b657600080fd5b50565b6000815190506105c8816105a2565b92915050565b6000602082840312156105e4576105e36102bf565b5b60006105f2848285016105b9565b91505092915050565b600082825260208201905092915050565b7f4552432d3230207472616e73666572206661696c656400000000000000000000600082015250565b60006106426016836105fb565b915061064d8261060c565b602082019050919050565b6000602082019050818103600083015261067181610635565b9050919050565b6000610683826102c9565b9050919050565b61069381610678565b82525050565b6106a281610532565b82525050565b600081519050919050565b60005b838110156106d15780820151818401526020810190506106b6565b60008484015250505050565b60006106e8826106a8565b6106f281856105fb565b93506107028185602086016106b3565b61070b81610331565b840191505092915050565b600060608201905061072b600083018661068a565b6107386020830185610699565b818103604083015261074a81846106dd565b9050949350505050565b600081519050919050565b600081905092915050565b600061077582610754565b61077f818561075f565b935061078f8185602086016106b3565b80840191505092915050565b60006107a7828461076a565b915081905092915050565b7f4661696c656420746f2063616c6c2073656e64546f42616e6b00000000000000815250565b60006107e3826107b2565b601982019150819050919050565b6000602082019050818103600083015261080b81846106dd565b90509291505056fea2646970667358221220f7c1135bb3f393a158817da7f32fcaeb3d691627a2718c4344d6401ed4e4d4a064736f6c63430008180033",
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063e655beb414610030575b600080fd5b61004a6004803603810190610045919061046d565b61004c565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83620f42406040518363ffffffff1660e01b81526004016100aa92919061056d565b6020604051808303816000875af11580156100c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100ed91906105ce565b61012c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161012390610658565b60405180910390fd5b600061080073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16628954408460405160240161017f93929190610716565b6040516020818303038152906040527fe77a47bf000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610209919061079b565b6000604051808303816000865af19150503d8060008114610246576040519150601f19603f3d011682016040523d82523d6000602084013e61024b565b606091505b505090508060405160200161025f906107d8565b604051602081830303815290604052906102af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102a691906107f1565b60405180910390fd5b50505050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102f4826102c9565b9050919050565b610304816102e9565b811461030f57600080fd5b50565b600081359050610321816102fb565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61037a82610331565b810181811067ffffffffffffffff8211171561039957610398610342565b5b80604052505050565b60006103ac6102b5565b90506103b88282610371565b919050565b600067ffffffffffffffff8211156103d8576103d7610342565b5b6103e182610331565b9050602081019050919050565b82818337600083830152505050565b600061041061040b846103bd565b6103a2565b90508281526020810184848401111561042c5761042b61032c565b5b6104378482856103ee565b509392505050565b600082601f83011261045457610453610327565b5b81356104648482602086016103fd565b91505092915050565b60008060408385031215610484576104836102bf565b5b600061049285828601610312565b925050602083013567ffffffffffffffff8111156104b3576104b26102c4565b5b6104bf8582860161043f565b9150509250929050565b6000819050919050565b60006104ee6104e96104e4846102c9565b6104c9565b6102c9565b9050919050565b6000610500826104d3565b9050919050565b6000610512826104f5565b9050919050565b61052281610507565b82525050565b6000819050919050565b6000819050919050565b600061055761055261054d84610528565b6104c9565b610532565b9050919050565b6105678161053c565b82525050565b60006040820190506105826000830185610519565b61058f602083018461055e565b9392505050565b60008115159050919050565b6105ab81610596565b81146105b657600080fd5b50565b6000815190506105c8816105a2565b92915050565b6000602082840312156105e4576105e36102bf565b5b60006105f2848285016105b9565b91505092915050565b600082825260208201905092915050565b7f4552432d3230207472616e73666572206661696c656400000000000000000000600082015250565b60006106426016836105fb565b915061064d8261060c565b602082019050919050565b6000602082019050818103600083015261067181610635565b9050919050565b6000610683826102c9565b9050919050565b61069381610678565b82525050565b6106a281610532565b82525050565b600081519050919050565b60005b838110156106d15780820151818401526020810190506106b6565b60008484015250505050565b60006106e8826106a8565b6106f281856105fb565b93506107028185602086016106b3565b61070b81610331565b840191505092915050565b600060608201905061072b600083018661068a565b6107386020830185610699565b818103604083015261074a81846106dd565b9050949350505050565b600081519050919050565b600081905092915050565b600061077582610754565b61077f818561075f565b935061078f8185602086016106b3565b80840191505092915050565b60006107a7828461076a565b915081905092915050565b7f4661696c656420746f2063616c6c2073656e64546f42616e6b00000000000000815250565b60006107e3826107b2565b601982019150819050919050565b6000602082019050818103600083015261080b81846106dd565b90509291505056fea2646970667358221220f7c1135bb3f393a158817da7f32fcaeb3d691627a2718c4344d6401ed4e4d4a064736f6c63430008180033",
"linkReferences": {},
"deployedLinkReferences": {}
}
37 changes: 37 additions & 0 deletions x/evm/embeds/contracts/TestDirtyStateAttack2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

// Uncomment this line to use console.log
// import "hardhat/console.sol";
import "./IFunToken.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract TestDirtyStateAttack2 {
address erc20;

constructor(address erc20_) {
erc20 = erc20_;
}

function attack(
address payable sendRecipient,
string memory bech32Recipient
) public {
require(
ERC20(erc20).transfer(sendRecipient, 1e6), // 1 WNIBI
"ERC-20 transfer failed"
);

(bool success, ) = FUNTOKEN_PRECOMPILE_ADDRESS.call(
abi.encodeWithSignature(
"sendToBank(address,uint256,string)",
erc20,
uint256(9e6), // 9 WNIBI
bech32Recipient
)
);

require(success, string.concat("Failed to call sendToBank"));
}
}
8 changes: 8 additions & 0 deletions x/evm/embeds/embeds.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ var (
testPrecompileSendToBankThenERC20Transfer []byte
//go:embed artifacts/contracts/TestDirtyStateAttack1.sol/TestDirtyStateAttack1.json
testDirtyStateAttack1 []byte
//go:embed artifacts/contracts/TestDirtyStateAttack2.sol/TestDirtyStateAttack2.json
testDirtyStateAttack2 []byte
)

var (
Expand Down Expand Up @@ -161,6 +163,11 @@ var (
Name: "TestDirtyStateAttack1.sol",
EmbedJSON: testDirtyStateAttack1,
}
// SmartContract_TestDirtyStateAttack2 is a test contract that sends to bank then calls ERC20 transfer
SmartContract_TestDirtyStateAttack2 = CompiledEvmContract{
Name: "TestDirtyStateAttack2.sol",
EmbedJSON: testDirtyStateAttack2,
}
)

func init() {
Expand All @@ -181,6 +188,7 @@ func init() {
SmartContract_TestBytes32Metadata.MustLoad()
SmartContract_TestPrecompileSendToBankThenERC20Transfer.MustLoad()
SmartContract_TestDirtyStateAttack1.MustLoad()
SmartContract_TestDirtyStateAttack2.MustLoad()
}

type CompiledEvmContract struct {
Expand Down
94 changes: 90 additions & 4 deletions x/evm/keeper/funtoken_from_coin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ func (s *FunTokenFromCoinSuite) TestPrecompileSendToBankThenErc20Transfer() {
Account: bob.EthAddr,
BalanceBank: big.NewInt(0),
BalanceERC20: big.NewInt(0),
Description: "Charles has 0 NIBI / 0 WNIBI",
Description: "Bob has 0 NIBI / 0 WNIBI",
}.Assert(s.T(), deps, evmObj)

evmtest.FunTokenBalanceAssert{
Expand Down Expand Up @@ -822,11 +822,8 @@ func (s *FunTokenFromCoinSuite) TestDirtyStateAttack1() {
))
})

// Create Alice and Bob. Contract will try to send Alice native coins and
// send Bob ERC20 tokens.
alice := evmtest.NewEthPrivAcc()

s.T().Log("call test contract")
s.Run("call test contract", func() {
contractInput, err := embeds.SmartContract_TestDirtyStateAttack1.ABI.Pack(
"attack",
Expand Down Expand Up @@ -872,6 +869,95 @@ func (s *FunTokenFromCoinSuite) TestDirtyStateAttack1() {
})
}

// TestDirtyStateAttack2
// 1. Creates a funtoken from coin.
// 2. Calls the test contract
// a. erc20 transfer 1 WNIBI to Alice
// b. FunToken.sendToBank 9 WNIBI to Alice
//
// INITIAL STATE:
// - Test contract funds: 10 WNIBI
// CONTRACT CALL:
// - Sends 1 WNIBI to Alice via erc20 transfer
// - Sends 9 WNIBI to Alice via FunToken.sendToBank
// EXPECTED:
// - Test contract funds: 0 WNIBI
// - Alice: 9 NIBI, 1 WNIBI
// - Module account: 1 NIBI escrowed
func (s *FunTokenFromCoinSuite) TestDirtyStateAttack2() {
deps := evmtest.NewTestDeps()

// Initial setup
funToken := s.fundAndCreateFunToken(deps, 10e6)

s.T().Log("Deploy Test Contract")
deployResp, err := evmtest.DeployContract(
&deps,
embeds.SmartContract_TestDirtyStateAttack2,
funToken.Erc20Addr.Address,
)
s.Require().NoError(err)
testContractAddr := deployResp.ContractAddr

s.Run("Convert bank coin to erc-20: give test contract 10 WNIBI (erc20)", func() {
_, err = deps.EvmKeeper.ConvertCoinToEvm(
sdk.WrapSDKContext(deps.Ctx),
&evm.MsgConvertCoinToEvm{
Sender: deps.Sender.NibiruAddr.String(),
BankCoin: sdk.NewCoin(evm.EVMBankDenom, sdk.NewInt(10e6)),
ToEthAddr: eth.EIP55Addr{Address: testContractAddr},
},
)
s.Require().NoError(err)
})

alice := evmtest.NewEthPrivAcc()

s.Run("call test contract", func() {
contractInput, err := embeds.SmartContract_TestDirtyStateAttack2.ABI.Pack(
"attack",
alice.EthAddr,
alice.NibiruAddr.String(),
)
s.Require().NoError(err)
evmObj, _ := deps.NewEVM()
_, err = deps.EvmKeeper.CallContractWithInput(
deps.Ctx,
evmObj,
deps.Sender.EthAddr,
&testContractAddr,
true,
contractInput,
evmtest.FunTokenGasLimitSendToEvm,
)
s.Require().NoError(err)

evmtest.FunTokenBalanceAssert{
FunToken: funToken,
Account: alice.EthAddr,
BalanceBank: big.NewInt(9e6),
BalanceERC20: big.NewInt(1e6),
Description: "Alice has 9 NIBI / 1 WNIBI",
}.Assert(s.T(), deps, evmObj)

evmtest.FunTokenBalanceAssert{
FunToken: funToken,
Account: testContractAddr,
BalanceBank: big.NewInt(0),
BalanceERC20: big.NewInt(0),
Description: "Test contract has 0 WNIBI / 0 NIBI",
}.Assert(s.T(), deps, evmObj)

evmtest.FunTokenBalanceAssert{
FunToken: funToken,
Account: evm.EVM_MODULE_ADDRESS,
BalanceBank: big.NewInt(1e6),
BalanceERC20: big.NewInt(0),
Description: "Module account has 1 NIBI escrowed",
}.Assert(s.T(), deps, evmObj)
})
}

// fundAndCreateFunToken creates initial setup for tests
func (s *FunTokenFromCoinSuite) fundAndCreateFunToken(deps evmtest.TestDeps, unibiAmount int64) evm.FunToken {
bankDenom := evm.EVMBankDenom
Expand Down

0 comments on commit dfe0f08

Please sign in to comment.