# 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:

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

Send tokens to a contract address along with call data

Parameters:

| Name   | Type    | Description                                                 |
| ------ | ------- | ----------------------------------------------------------- |
| 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.

```solidity
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:

```ts
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:

```solidity
// 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
    }
}
```
