Skip to content

Commit

Permalink
chore: its custom token example refactor (#195)
Browse files Browse the repository at this point in the history
  • Loading branch information
benjamin852 authored Jul 25, 2024
1 parent 457f37c commit 6c03476
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 26 deletions.
33 changes: 23 additions & 10 deletions examples/evm/its-custom-token/CustomToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,53 @@
pragma solidity ^0.8.0;

import { InterchainTokenStandard } from '@axelar-network/interchain-token-service/contracts/interchain-token/InterchainTokenStandard.sol';
// Any ERC20 implementation can be used here, we chose OZ since it is quite well known.
import { IInterchainTokenService } from '@axelar-network/interchain-token-service/contracts/interfaces/IInterchainTokenService.sol';

// Any ERC20 implementation can be used here, we chose OZ since it is quite well known.
import { ERC20 } from '@openzeppelin/contracts/token/ERC20/ERC20.sol';

import { Minter } from '@axelar-network/interchain-token-service/contracts/utils/Minter.sol';

/**
* @title InterchainToken
* @notice This contract implements an interchain token which extends InterchainToken functionality.
* @dev This contract also inherits Minter and Implementation logic.
*/
contract CustomToken is InterchainTokenStandard, ERC20, Minter {
uint8 internal immutable decimals_;
bytes32 internal tokenId;
bytes32 internal itsSalt;
address internal immutable interchainTokenService_;

uint256 internal constant UINT256_MAX = 2 ** 256 - 1;
address public deployer;

/**
* @notice Constructs the InterchainToken contract.
* @dev Makes the implementation act as if it has been setup already to disallow calls to init() (even though that would not achieve anything really).
*/
constructor(string memory name_, string memory symbol_, uint8 decimalsValue, address interchainTokenServiceAddress) ERC20(name_, symbol_) {
constructor(
string memory name_,
string memory symbol_,
uint8 decimalsValue,
address interchainTokenServiceAddress
) ERC20(name_, symbol_) {
decimals_ = decimalsValue;
interchainTokenService_ = interchainTokenServiceAddress;

_addMinter(msg.sender);
deployer = msg.sender;
}

function decimals() public view override returns (uint8) {
return decimals_;
}

function setTokenId(bytes32 tokenId_) public {
tokenId = tokenId_;
/**
* @notice set ITS salt needed to calculate interchainTokenId
* @param salt_ the salt being sent
*/
function setItsSalt(bytes32 salt_) external onlyRole(uint8(Roles.MINTER)) {
itsSalt = salt_;
}

/**
Expand All @@ -48,10 +62,9 @@ contract CustomToken is InterchainTokenStandard, ERC20, Minter {

/**
* @notice Returns the tokenId for this token.
* @return bytes32 The token manager contract.
*/
function interchainTokenId() public view override returns (bytes32) {
return tokenId;
function interchainTokenId() public view override returns (bytes32 tokenId) {
tokenId = IInterchainTokenService(interchainTokenService_).interchainTokenId(deployer, itsSalt);
}

/**
Expand Down Expand Up @@ -82,11 +95,11 @@ contract CustomToken is InterchainTokenStandard, ERC20, Minter {
* @notice A method to be overwritten that will decrease the allowance of the `spender` from `sender` by `amount`.
* @dev Needs to be overwritten. This provides flexibility for the choice of ERC20 implementation used. Must revert if allowance is not sufficient.
*/
function _spendAllowance(address sender, address spender, uint256 amount) internal override (ERC20, InterchainTokenStandard) {
function _spendAllowance(address sender, address spender, uint256 amount) internal override(ERC20, InterchainTokenStandard) {
uint256 _allowance = allowance(sender, spender);

if (_allowance != UINT256_MAX) {
_approve(sender, spender, _allowance - amount);
}
}
}
}
17 changes: 9 additions & 8 deletions examples/evm/its-custom-token/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ const { keccak256, defaultAbiCoder } = require('ethers/lib/utils');
const { interchainTransfer } = require('../../../scripts/libs/its-utils');

const CustomToken = rootRequire('./artifacts/examples/evm/its-custom-token/CustomToken.sol/CustomToken.json');
const ITokenManager = rootRequire('./artifacts/@axelar-network/interchain-token-service/contracts/interfaces/ITokenManager.sol/ITokenManager.json');
const ITokenManager = rootRequire(
'./artifacts/@axelar-network/interchain-token-service/contracts/interfaces/ITokenManager.sol/ITokenManager.json',
);
const CUSTOM_MINT_BURN = 4;

async function deploy(chain, wallet) {
Expand All @@ -19,16 +21,13 @@ async function deploy(chain, wallet) {
console.log(`Deployed CustomToken for ${chain.name} at ${chain.customToken.address}.`);
}



async function execute(chains, wallet, options) {
const args = options.args || [];
const { source, destination, calculateBridgeFee } = options;
const { source, destination, calculateBridgeFee } = options;

const amount = args[2] || 1000;
const salt = args[3] || keccak256(defaultAbiCoder.encode(['uint256', 'uint256'], [process.pid, process.ppid]));


const fee = await calculateBridgeFee(source, destination);

async function deployTokenManager(chain, salt) {
Expand All @@ -37,12 +36,14 @@ async function execute(chains, wallet, options) {
const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, chain.customToken.address]);
const its = new Contract(chain.interchainTokenService, IInterchainTokenService.abi, wallet.connect(chain.provider));
await (await its.deployTokenManager(salt, '', CUSTOM_MINT_BURN, params, 0)).wait();
await chain.customToken.setItsSalt(salt);

const tokenId = await its.interchainTokenId(wallet.address, salt);
const tokenManagerAddress = await its.tokenManagerAddress(tokenId);
const tokenManager = new Contract(tokenManagerAddress, ITokenManager.abi, wallet.connect(chain.provider));
await (await chain.customToken.addMinter(tokenManagerAddress)).wait();
return tokenManager;
}
}

const tokenManager = await deployTokenManager(source, salt);
await deployTokenManager(destination, salt);
Expand All @@ -58,4 +59,4 @@ async function execute(chains, wallet, options) {
module.exports = {
deploy,
execute,
};
};
23 changes: 15 additions & 8 deletions examples/evm/its-mint-burn-from/BurnableToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pragma solidity ^0.8.0;

import { InterchainTokenStandard } from '@axelar-network/interchain-token-service/contracts/interchain-token/InterchainTokenStandard.sol';
import { IInterchainTokenService } from '@axelar-network/interchain-token-service/contracts/interfaces/IInterchainTokenService.sol';
import { ERC20Burnable } from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol';
import { ERC20 } from '@openzeppelin/contracts/token/ERC20/ERC20.sol';

Expand All @@ -15,8 +16,9 @@ import { Minter } from '@axelar-network/interchain-token-service/contracts/utils
*/
contract BurnableToken is InterchainTokenStandard, ERC20Burnable, Minter {
uint8 internal immutable decimals_;
bytes32 internal tokenId;
bytes32 internal itsSalt;
address internal immutable interchainTokenService_;
address public deployer;

uint256 internal constant UINT256_MAX = 2 ** 256 - 1;

Expand All @@ -34,16 +36,13 @@ contract BurnableToken is InterchainTokenStandard, ERC20Burnable, Minter {
interchainTokenService_ = interchainTokenServiceAddress;

_addMinter(msg.sender);
deployer = msg.sender;
}

function decimals() public view override returns (uint8) {
return decimals_;
}

function setTokenId(bytes32 tokenId_) public {
tokenId = tokenId_;
}

/**
* @notice Returns the interchain token service
* @return address The interchain token service contract
Expand All @@ -52,12 +51,20 @@ contract BurnableToken is InterchainTokenStandard, ERC20Burnable, Minter {
return interchainTokenService_;
}

/**
* @notice set ITS salt needed to calculate interchainTokenId
* @param salt_ the salt being sent
*/
function setItsSalt(bytes32 salt_) external onlyRole(uint8(Roles.MINTER)) {
itsSalt = salt_;
}

/**
* @notice Returns the tokenId for this token.
* @return bytes32 The token manager contract.
* @return tokenId the token id.
*/
function interchainTokenId() public view override returns (bytes32) {
return tokenId;
function interchainTokenId() public view override returns (bytes32 tokenId) {
tokenId = IInterchainTokenService(interchainTokenService_).interchainTokenId(deployer, itsSalt);
}

/**
Expand Down
1 change: 1 addition & 0 deletions examples/evm/its-mint-burn-from/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ async function execute(chains, wallet, options) {
const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, chain.burnableToken.address]);
its = new Contract(chain.interchainTokenService, IInterchainTokenService.abi, wallet.connect(chain.provider));
await (await its.deployTokenManager(salt, '', MINT_BURN_FROM, params, 0)).wait();
await chain.burnableToken.setItsSalt(salt);
const tokenId = await its.interchainTokenId(wallet.address, salt);
const tokenManagerAddress = await its.tokenManagerAddress(tokenId);
const tokenManager = new Contract(tokenManagerAddress, ITokenManager.abi, wallet.connect(chain.provider));
Expand Down

0 comments on commit 6c03476

Please sign in to comment.