ATEN Token

The ATEN token contract follows the standard ERC-20 specification, including the use of 18 decimal places. The contract also includes an additional transferAndCall feature, which allows direct smart contract interactions without relying on the typical approve/transferFrom mechanism.

TransferAndCall

Besides the standard ERC20 token features (transfer(), balanceOf(), allowance(), etc), the following transferAndCall feature is also available:

function transferAndCall(
    address to,
    uint256 amount,
    bytes calldata data
) public returns (bool)

Send tokens to a contract address along with call data

Parameters:

NameTypeDescription

to

address

destination address for the transfer

amount

uint256

amount to be sent

data

bytes

supplementary data to be provided to the receiving contract

The receiving contract must implement the ITokenCallReceiver interface in order to receive the tokens and execute the desired call.

interface ITokenCallReceiver {
  function onTokenTransfer(
    address from,
    uint256 amount,
    bytes calldata data
  ) external returns (bool);
}

Example

The following example demonstrates how to use the transferAndCall function to send tokens to a contract and execute a specific function:

import { ethers } from 'ethers';

// Placeholder values
const providerUrl = 'YOUR_RPC_PROVIDER_URL';
const privateKey = 'YOUR_PRIVATE_KEY';
const contractAddress = '0xYourContractAddress';
const recipientAddress = '0xRecipientAddress';
const transferAmount = ethers.BigNumber.from('1000000000000000000'); // 1 ETH
const stakeAmount = ethers.BigNumber.from('500000000000000000'); // 0.5 ETH

// Setup provider and wallet
const provider = new ethers.providers.JsonRpcProvider(providerUrl);
const wallet = new ethers.Wallet(privateKey, provider);

// ABI definitions
const transferAndCallAbi = [
  "function transferAndCall(address to, uint256 amount, bytes calldata data) public returns (bool)"
];
const stakeAbi = [
  "function stake(uint256 amount) public"
];

// Encode stake data
const stakeInterface = new ethers.utils.Interface(stakeAbi);
const stakeData = stakeInterface.encodeFunctionData('stake', [stakeAmount]);

// Encode transferAndCall data
const transferAndCallInterface = new ethers.utils.Interface(transferAndCallAbi);
const calldata = transferAndCallInterface.encodeFunctionData('transferAndCall', [recipientAddress, transferAmount, stakeData]);

// Create contract instance
const contract = new ethers.Contract(contractAddress, transferAndCallAbi, wallet);

async function sendTransaction() {
  try {
    const tx = await contract.transferAndCall(recipientAddress, transferAmount, stakeData);
    const receipt = await tx.wait();
    console.log("Transaction confirmed");
  } catch (error) {
    console.error('Transaction failed:', error);
  }
}

// Send the transaction
sendTransaction();

On the receiving contract side, the onTokenTransfer function should be implemented to handle the incoming tokens and execute the desired logic:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

interface ITokenCallReceiver {
    function onTokenTransfer(
        address from,
        uint256 amount,
        bytes calldata data
    ) external returns (bool);
}

contract TokenReceiver is ITokenCallReceiver {
    // Define function selectors as constants
    bytes4 private constant STAKE_SELECTOR = bytes4(keccak256("stake(uint256)"));

    // Implement the onTokenTransfer function
    function onTokenTransfer(
        address from,
        uint256 amount,
        bytes calldata data
    ) external override returns (bool) {
        // Extract the function selector
        bytes4 selector;
        assembly {
            selector := calldataload(data.offset)
        }

        // Decode the function call data based on the selector
        if (selector == STAKE_SELECTOR) {
            // Extract the parameters for the stake function
            (uint256 stakeAmount) = abi.decode(data[4:], (uint256)); // Skip the 4-byte function selector

            // Handle the stake function logic
            stake(stakeAmount);
        } else {
            revert("Unsupported function selector");
        }

        // Return success
        return true;
    }

    // Example stake function that could be called
    function stake(uint256 amount) public {
        // Handle the staking logic here
    }
}

Last updated