Skip to content

Transfer multiple asset types (native, ERC-20, -721, -1155) to multiple recipients within one transaction.

License

Notifications You must be signed in to change notification settings

BuildOnBeam/tokenbeamer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TokenBeamer

Solidity smart contract for transferring multiple asset types (native currency, ERC-20, -721, -1155) to multiple recipients within one transaction, and checking approval states of different tokens with a single call.

Developer guide

Deploy and verify

  • install and run pnpm to fetch dependencies
  • set up your environment: copy .env.example to .env and add your mnemonic
  • deploy contract (e.g. to Beam network):
npx hardhat --network beam deploy --tags TokenBeamer
  • verify contract:
# verify on Sourcify:
npx hardhat --network beam sourcify

# verify on Etherscan & Co on supported networks:
npx hardhat --network ethereum etherscan-verify

Admin functionality

  • use setTipRecipient(newRecipient) to change the tip recipient address
  • use disableUpgrades()to permanently disable the upgradeability of the smart contract
  • use recoverFunds(to, token, type_, id, value) to transfer funds stuck in the contract

Unit tests

Running the tests requires to install the latest version of foundry (tested using the described foundryup method).

  • Run the test using
pnpm test
  • The coverage can be checked by running
pnpm coverage
  • The following command generates a graphical coverage report in the report directory on Linux machines. It requires the packages lcov and genhtml to be installed.
pnpm coverage:report

User guide

The following examples use viem, please refer to the viem docs on how to instantiate your TokenBeamer contract instance.

Multi-transfer Tokens

TokenBeamer can be used to transfer native currency, different ERC-20 tokens, and ERC-721 and 1155 NFTs to one or multiple recipients within one transaction. The owner needs to approve all tokens to the TokenBeamer contract first.

  • Send ERC20 tokens (18 decimals) - 600 $AAA to Alice, 400 $BBB to Bob:
await contract.write.beamTokens([
  // recipients
  [
    "0x00000000000000000000000000000000000a71CE",
    "0x0000000000000000000000000000000000000B0b",
  ],
  // token contract addresses
  [
    "0xAAA0000000000000000000000000000000000AAA",
    "0xBBB0000000000000000000000000000000000BBB",
  ],
  [20n, 20n], // use type `20` for ERC-20
  [0n, 0n], // use token id 0
  [parseEther("600"), parseEther("400")], // values to transfer
]);
  • Send 600 units of native currency (e.g. ETH) to Alice, and 400 to Bob:
await contract.write.beamTokens(
  [
    // recipients
    [
      "0x00000000000000000000000000000000000a71CE",
      "0x0000000000000000000000000000000000000B0b",
    ],
    // use zero-address for native currency
    [
      "0x0000000000000000000000000000000000000000",
      "0x0000000000000000000000000000000000000000",
    ],
    [0n, 0n], // use type 0
    [0n, 0n], // use token id 0
    [parseEther("600"), parseEther("400")], // values to transfer
  ],
  // sum of native currency to transfer
  {
    value: parseEther("1000"),
  },
);
  • Send NFTs - two ERC-721 to Alice, 100 ERC-1155 to Bob:
await contract.write.beamTokens([
  // recipients
  [
    "0x00000000000000000000000000000000000a71CE",
    "0x00000000000000000000000000000000000a71CE",
    "0x0000000000000000000000000000000000000B0b",
  ],
  // token contract addresses
  [
    "0x7210000000000000000000000000000000000721",
    "0x7210000000000000000000000000000000000721",
    "0x1155000000000000000000000000000000001155",
  ],
  [721n, 721n, 1155n], // token types
  [42n, 69n, 420n], // token ids
  [1n, 1n, 100n], // values to transfer
]);
  • Send ERC-20, ERC-712 and ERC-1155 to Alice
await contract.write.beamTokens([
  // one recipient for all tokens
  ["0x00000000000000000000000000000000000a71CE"],
  // token contract addresses
  [
    "0x2000000000000000000000000000000000000020",
    "0x7210000000000000000000000000000000000721",
    "0x1155000000000000000000000000000000001155",
  ],
  [20n, 721n, 1155n], // token types
  [0n, 69n, 420n], // token ids
  [parseEther("600"), 1n, 100n], // values to transfer
]);

Bulk token approval check

Additionally, the TokenBeamer contract offers a convenience method to check approval states for multiple ERC-20, -721 and -1155 tokens for a given owner and operator, before attempting to send them.

  • Read approval state for different token types:
const areContractsApproved: boolean[] = await contract.read.getApprovals([
  // owner of tokens
  "0x0000000000000000000000000000000000000B0b",
  // operator to check approvals for (e.g. the TokenBeamer contract)
  "0x09e2a70200000000000000000000000000000000",
  // token contract addresses
  [
    "0x2000000000000000000000000000000000000020",
    "0x7210000000000000000000000000000000000721",
    "0x1155000000000000000000000000000000001155",
  ],
  [20n, 721n, 1155n], // token types
  [parseEther("600"), 0n, 0n], // values to transfer (only relevant for ERC-20)
]);

// returns the approval states for each token as an array of booleans, e.g.:
// -> [ true, true, false ]
// request approval for each token contract that returns `false` before sending
  • If only checking NFTs (ERC-721, ERC-1155), you can drop token types and values completely:
const areContractsApproved: boolean[] = await contract.read.getApprovals([
  // owner of tokens
  "0x00000000000000000000000000000000000a71CE",
  // approved operator
  "0x09e2a70200000000000000000000000000000000",
  // token contract addresses
  [
    "0x7210000000000000000000000000000000000721",
    "0x1155000000000000000000000000000000001155",
  ],
  [], // leave token types empty
  [], // leave values empty
]);

License

GPL v3

About

Transfer multiple asset types (native, ERC-20, -721, -1155) to multiple recipients within one transaction.

Topics

Resources

License

Stars

Watchers

Forks

Contributors 3

  •  
  •  
  •