Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/test-stellar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,12 @@ jobs:
- name: ITS Flow Limit Remove
run: ts-node stellar/its.js remove-flow-limit ${{ steps.env_vars.outputs.tokenId }}

- name: ITS Freeze Token
run: ts-node stellar/its.js freeze-token ${{ steps.env_vars.outputs.tokenId }}

- name: ITS Unfreeze Token
run: ts-node stellar/its.js unfreeze-token ${{ steps.env_vars.outputs.tokenId }}

###### Command: Operators ######

- name: Operator
Expand Down
120 changes: 64 additions & 56 deletions evm/its.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
const { ethers } = require('hardhat');
const {
getDefaultProvider,
utils: { hexZeroPad, toUtf8Bytes, keccak256, parseUnits },
utils: { hexZeroPad, toUtf8Bytes, keccak256, parseUnits, formatUnits },
Contract,
} = ethers;
const { Command, Option, Argument } = require('commander');
Expand Down Expand Up @@ -95,6 +95,17 @@ async function handleTx(tx, chain, contract, action, firstEvent, secondEvent) {
}
}

async function tokenManagerAndMetadata(interchainTokenService, tokenId, wallet) {
const tokenManagerAddress = await interchainTokenService.deployedTokenManager(tokenId);
const tokenManager = new Contract(tokenManagerAddress, ITokenManager.abi, wallet);

const tokenAddress = await interchainTokenService.registeredTokenAddress(tokenId);
const token = new Contract(tokenAddress, getContractJSON('ERC20').abi, wallet);
const [symbol, decimals] = await Promise.all([token.symbol(), token.decimals()]);

return { tokenManager, tokenManagerAddress, tokenAddress, symbol, decimals };
}

async function getTrustedChains(chains, interchainTokenService, version) {
const chainIds = Object.values(chains)
.filter((chain) => chain.contracts.InterchainTokenService !== undefined)
Expand Down Expand Up @@ -260,37 +271,36 @@ async function processCommand(_axelar, chain, chains, action, options) {

validateTokenIds(interchainTokenService, [tokenId]);

const tokenManagerAddress = await interchainTokenService.deployedTokenManager(tokenId);
const tokenManager = new Contract(tokenManagerAddress, ITokenManager.abi, wallet);

const { tokenManager, symbol, decimals } = await tokenManagerAndMetadata(interchainTokenService, tokenId, wallet);
const flowLimit = await tokenManager.flowLimit();
printInfo(`Flow limit for tokenId ${tokenId}`, flowLimit);

printInfo(`Flow limit for tokenId ${tokenId}`, `${formatUnits(flowLimit, decimals)} ${symbol}`);
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated

break;
}

case 'flow-out-amount': {
const [tokenId] = args;
validateTokenIds(interchainTokenService, [tokenId]);

const tokenManagerAddress = await interchainTokenService.deployedTokenManager(tokenId);
const tokenManager = new Contract(tokenManagerAddress, ITokenManager.abi, wallet);
validateTokenIds(interchainTokenService, [tokenId]);

const { tokenManager, symbol, decimals } = await tokenManagerAndMetadata(interchainTokenService, tokenId, wallet);
const flowOutAmount = await tokenManager.flowOutAmount();
printInfo(`Flow out amount for tokenId ${tokenId}`, flowOutAmount);

printInfo(`Flow out amount for tokenId ${tokenId}`, `${formatUnits(flowOutAmount, decimals)} ${symbol}`);

break;
}

case 'flow-in-amount': {
const [tokenId] = args;
validateTokenIds(interchainTokenService, [tokenId]);

const tokenManagerAddress = await interchainTokenService.deployedTokenManager(tokenId);
const tokenManager = new Contract(tokenManagerAddress, ITokenManager.abi, wallet);
validateTokenIds(interchainTokenService, [tokenId]);

const { tokenManager, symbol, decimals } = await tokenManagerAndMetadata(interchainTokenService, tokenId, wallet);
const flowInAmount = await tokenManager.flowInAmount();
printInfo(`Flow in amount for tokenId ${tokenId}`, flowInAmount);

printInfo(`Flow in amount for tokenId ${tokenId}`, `${formatUnits(flowInAmount, decimals)} ${symbol}`);

break;
}
Expand Down Expand Up @@ -344,29 +354,26 @@ async function processCommand(_axelar, chain, chains, action, options) {
});

const tokenIdBytes32 = hexZeroPad(tokenId.startsWith('0x') ? tokenId : '0x' + tokenId, 32);

const tokenManager = new Contract(
await interchainTokenService.deployedTokenManager(tokenIdBytes32),
getContractJSON('ITokenManager').abi,
wallet,
);
const token = new Contract(
await interchainTokenService.registeredTokenAddress(tokenIdBytes32),
getContractJSON('InterchainToken').abi,
const { tokenManager, tokenAddress, symbol, decimals } = await tokenManagerAndMetadata(
interchainTokenService,
tokenIdBytes32,
wallet,
);

await printTokenInfo(await interchainTokenService.registeredTokenAddress(tokenIdBytes32), provider);
const token = new Contract(tokenAddress, getContractJSON('InterchainToken').abi, wallet);

const implementationType = (await tokenManager.implementationType()).toNumber();
const decimals = await token.decimals();
const amountInUnits = parseUnits(amount, decimals);
const balance = await token.balanceOf(wallet.address);

if (balance.lt(amountInUnits)) {
throw new Error(`Insufficient balance for transfer. Balance: ${balance}, amount: ${amountInUnits}`);
throw new Error(
`Insufficient balance. Balance: ${formatUnits(balance, decimals)} ${symbol}, required: ${amount} ${symbol}`,
);
}

printInfo(`Token address`, tokenAddress);
printInfo(`Transfer amount`, `${amount} ${symbol}`);

if (implementationType !== tokenManagerTypes.MINT_BURN && implementationType !== tokenManagerTypes.NATIVE_INTERCHAIN_TOKEN) {
printInfo('Approving ITS for a transfer for token with token manager type', implementationType);
await token.approve(interchainTokenService.address, amountInUnits, gasOptions).then((tx) => tx.wait());
Expand Down Expand Up @@ -414,9 +421,14 @@ async function processCommand(_axelar, chain, chains, action, options) {
const [tokenId, flowLimit] = args;

validateTokenIds(interchainTokenService, [tokenId]);
validateParameters({ isValidNumber: { flowLimit } });
validateParameters({ isValidDecimal: { flowLimit } });
Comment thread
milapsheth marked this conversation as resolved.

const tx = await interchainTokenService.setFlowLimits([tokenId], [flowLimit], gasOptions);
const { tokenAddress, symbol, decimals } = await tokenManagerAndMetadata(interchainTokenService, tokenId, wallet);
await printTokenInfo(tokenAddress, provider);
const flowLimitInUnits = parseUnits(flowLimit, decimals);
printInfo(`Setting flow limit for tokenId ${tokenId}`, `${flowLimit} ${symbol}`);

const tx = await interchainTokenService.setFlowLimits([tokenId], [flowLimitInUnits], gasOptions);
await handleTx(tx, chain, interchainTokenService, action);
break;
}
Expand Down Expand Up @@ -483,9 +495,9 @@ async function processCommand(_axelar, chain, chains, action, options) {
validateParameters({ isNonEmptyString: { itsChain } });

if (await isTrustedChain(itsChain, interchainTokenService, itsVersion)) {
printInfo(`${itsChain} is a trusted chain`);
printInfo(`${itsChain}`, 'Trusted');
} else {
printInfo(`${itsChain} is not a trusted chain`);
printWarn(`${itsChain}`, 'Not trusted');
}

break;
Expand Down Expand Up @@ -764,20 +776,17 @@ async function processCommand(_axelar, chain, chains, action, options) {
validateParameters({ isValidTokenId: { tokenId }, isValidAddress: { to }, isValidNumber: { amount } });

const tokenIdBytes32 = hexZeroPad(tokenId.startsWith('0x') ? tokenId : '0x' + tokenId, 32);

// Get token manager address
const tokenManagerAddress = await interchainTokenService.deployedTokenManager(tokenIdBytes32);
const { tokenManager, tokenManagerAddress, tokenAddress, symbol, decimals } = await tokenManagerAndMetadata(
interchainTokenService,
tokenIdBytes32,
wallet,
);
printInfo(`TokenManager address for tokenId: ${tokenId}`, tokenManagerAddress);

// Get token address
const tokenAddress = await interchainTokenService.registeredTokenAddress(tokenIdBytes32);
printInfo(`Token address for tokenId: ${tokenId}`, tokenAddress);

const tokenManager = new Contract(tokenManagerAddress, ITokenManager.abi, wallet);

const amountInUnits = ethers.BigNumber.from(amount.toString());

if (prompt(`Proceed with minting ${amount} to ${to}?`, yes)) {
if (prompt(`Proceed with minting ${formatUnits(amountInUnits, decimals)} ${symbol} to ${to}?`, yes)) {
return;
}

Expand All @@ -793,22 +802,19 @@ async function processCommand(_axelar, chain, chains, action, options) {
validateParameters({ isValidTokenId: { tokenId }, isValidAddress: { spender }, isValidNumber: { amount } });

const tokenIdBytes32 = hexZeroPad(tokenId.startsWith('0x') ? tokenId : '0x' + tokenId, 32);

// Get token address
const tokenAddress = await interchainTokenService.registeredTokenAddress(tokenIdBytes32);
const { tokenAddress, symbol, decimals } = await tokenManagerAndMetadata(interchainTokenService, tokenIdBytes32, wallet);
printInfo(`Token address for tokenId: ${tokenId}`, tokenAddress);

// Create token contract instance
const token = new Contract(tokenAddress, getContractJSON('InterchainToken').abi, wallet);

const amountInUnits = ethers.BigNumber.from(amount.toString());
printInfo(`Approving ${spender} to spend ${amount} of token ${tokenId}`);
const formattedAmount = `${formatUnits(amountInUnits, decimals)} ${symbol}`;

printInfo(`Approving ${spender} to spend`, formattedAmount);

if (prompt(`Proceed with approving ${spender} to spend ${amount}?`, yes)) {
if (prompt(`Proceed with approving ${spender} to spend ${formattedAmount}?`, yes)) {
return;
}

// Execute approval
const tx = await token.approve(spender, amountInUnits, gasOptions);
await handleTx(tx, chain, token, action, 'Approval');

Expand Down Expand Up @@ -1038,7 +1044,7 @@ if (require.main === module) {
.command('set-flow-limit')
.description('Set flow limit for a token')
.argument('<token-id>', 'Token ID')
.argument('<flow-limit>', 'Flow limit')
.argument('<flow-limit>', 'Flow limit in token units (e.g. 100.5)')
.action((tokenId, flowLimit, options, cmd) => {
return main(cmd.name(), [tokenId, flowLimit], options);
});
Expand Down Expand Up @@ -1083,32 +1089,29 @@ if (require.main === module) {
return main(cmd.name(), [itsChain], options);
});

const setTrustedChainsCommand = program
const setTrustedChainsCmd = program
.command('set-trusted-chains')
.description('Set trusted chains')
.argument('<chains...>', 'Chains to trust')
.action((chains, options, cmd) => {
return main(cmd.name(), chains, options);
});
addGovernanceOptions(setTrustedChainsCommand);

const removeTrustedChainsCommand = program
const removeTrustedChainsCmd = program
.command('remove-trusted-chains')
.description('Remove trusted chains')
.argument('<chains...>', 'Chains to not trust')
.action((chains, options, cmd) => {
return main(cmd.name(), chains, options);
});
addGovernanceOptions(removeTrustedChainsCommand);

const setPauseStatusCommand = program
const setPauseStatusCmd = program
.command('set-pause-status')
.description('Set pause status')
.argument(new Argument('<pause-status>', 'Pause status (true/false)').choices(['true', 'false']))
.action((pauseStatus, options, cmd) => {
return main(cmd.name(), [pauseStatus], options);
});
addGovernanceOptions(setPauseStatusCommand);

program
.command('execute')
Expand All @@ -1128,14 +1131,13 @@ if (require.main === module) {
return main(cmd.name(), [], options);
});

const migrateInterchainTokenCommand = program
const migrateInterchainTokenCmd = program
.command('migrate-interchain-token')
.description('Migrate interchain token')
.argument('<token-id>', 'Token ID')
.action((tokenId, options, cmd) => {
return main(cmd.name(), [tokenId], options);
});
addGovernanceOptions(migrateInterchainTokenCommand);

program
.command('mint-token')
Expand Down Expand Up @@ -1182,6 +1184,12 @@ if (require.main === module) {

addOptionsToCommands(program, addEvmOptions, { address: true, salt: true });

// Add governance options only to commands that handle them
addGovernanceOptions(setTrustedChainsCmd);
addGovernanceOptions(removeTrustedChainsCmd);
addGovernanceOptions(setPauseStatusCmd);
addGovernanceOptions(migrateInterchainTokenCmd);

program.parseAsync().then(() => process.exit(0));
}

Expand Down
Loading
Loading