Skip to content

Latest commit

 

History

21 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

transfer-sim

🧪 Simulate ERC20 transfers via state overrides to detect fee-on-transfer tokens.

⚡ Install

go get github.com/orbs-network/transfer-sim

✅ Usage

client, _ := ethclient.Dial("https://eth-mainnet.alchemyapi.io/v2/YOUR-API-KEY")
token := common.HexToAddress("0x...")
from := common.HexToAddress("0x...")
to := common.HexToAddress("0x...")
amount := big.NewInt(1000000000000000000) // 1 token (18 decimals)

received, err := transfersim.TransferSim(client, token, from, to, amount)
if err != nil {
    // On error, received == amount. Treat as unknown.
    fmt.Printf("Simulation error: %v\n", err)
    return
}

if received.Cmp(amount) == 0 {
    fmt.Println("No fee on transfer detected")
} else {
    fee := new(big.Int).Sub(amount, received)
    fmt.Printf("Fee on transfer detected: %s tokens\n", fee.String())
}

Node.js Usage

The Go library is the canonical implementation. A Node.js translation is provided in js/transfer-sim.js for convenience.

const Web3 = require("web3");
const { transferSim } = require("./js/transfer-sim");

const web3 = new Web3(process.env.ETH_RPC_URL);

const token = "0x...";
const from = "0x...";
const to = "0x...";
const amount = 10n ** 18n;

(async () => {
  const { received, error } = await transferSim(web3, token, from, to, amount);
  if (error) {
    console.warn("Simulation error:", error.message || error);
  }
  console.log("received:", received.toString());
})();
  • Requires from to approve to to spend amount on-chain.
  • Requires an RPC that supports eth_call with state overrides.

🧰 API

func TransferSim(
    client *ethclient.Client,
    token, from, to common.Address,
    amount *big.Int,
) (*big.Int, error)
  • Returns the actual amount received by to (balance delta).
  • If amount is nil/0, returns 0 without calling RPC.
  • On failure, returns amount alongside the error.
  • Requires from to approve to to spend amount.
  • Uses eth_call with state overrides (no on-chain tx).

🧪 Tests

npm test

Requires Node.js, Go, and Foundry (forge and anvil). Forge downloads Solidity 0.8.21 on the first run if needed.

The E2E suite starts a fresh local Anvil node, deploys a token fixture, and runs the same scenarios through both JS and Go over real JSON-RPC. It executes the receiver bytecode using state overrides and checks full transfers, 2.5% and 100% fees, large amounts, insufficient balances, and insufficient allowances. Every simulation must preserve the original balances, allowances, and receiver code. Scenarios are defined once in test/e2e.test.js; test/runner only adapts Go to that shared harness.

Unit tests cover only cases outside E2E: zero amounts without RPC, JS transport errors, and Go panic recovery. No user wallet, external RPC, or live-chain funds are used. The local node and temporary build artifacts are cleaned up after testing.

Run npm run test:e2e for E2E only.

Run npm run build for JS syntax and Go compilation checks.

About

Simulate offchain transfers to detect fee on transfer tokens

Resources

Code of conduct

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages