Skip to content

Commit

Permalink
added deployment tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Foivos committed Jan 10, 2025
1 parent 8d7f80f commit a09628e
Showing 1 changed file with 255 additions and 1 deletion.
256 changes: 255 additions & 1 deletion test/InterchainTokenFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,22 @@ const {
utils: { defaultAbiCoder, keccak256, toUtf8Bytes, arrayify },
} = ethers;
const { deployAll, deployContract } = require('../scripts/deploy');
const { getRandomBytes32, expectRevert } = require('./utils');
const { getRandomBytes32, expectRevert, gasReporter } = require('./utils');
const {
MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN,
NATIVE_INTERCHAIN_TOKEN,
LOCK_UNLOCK,
MINTER_ROLE,
OPERATOR_ROLE,
FLOW_LIMITER_ROLE,
MINT_BURN,
MINT_BURN_FROM,
LOCK_UNLOCK_FEE_ON_TRANSFER,
} = require('./constants');
const { getBytecodeHash } = require('@axelar-network/axelar-chains-config');

const reportGas = gasReporter('Interchain Token Factory');

describe('InterchainTokenFactory', () => {
let wallet, otherWallet;
let service, gateway, gasService, tokenFactory;
Expand Down Expand Up @@ -617,5 +622,254 @@ describe('InterchainTokenFactory', () => {
.and.to.emit(gateway, 'ContractCall')
.withArgs(service.address, destinationChain, service.address, keccak256(payload), payload);
});

describe('Custom Token Manager Deployment', () => {
const tokenName = 'Token Name';
const tokenSymbol = 'TN';
const tokenDecimals = 13;
let token, salt, tokenId;
let tokenManagerProxy;
let factorySalt;

before(async () => {
salt = getRandomBytes32();
tokenId = await tokenFactory.linkedTokenId(wallet.address, salt);
token = await deployContract(wallet, 'TestInterchainTokenStandard', [
tokenName,
tokenSymbol,
tokenDecimals,
service.address,
tokenId,
]);
factorySalt = await tokenFactory.linkedTokenDeploySalt(wallet.address, salt);
});

it('Should revert on deploying an invalid token manager', async () => {
await expectRevert((gasOptions) => tokenFactory.linkToken(salt, '', token.address, 6, wallet.address, 0, gasOptions));
});

it('Should revert on deploying a local token manager with invalid params', async () => {
await expectRevert(
(gasOptions) => tokenFactory.linkToken(salt, '', token.address, NATIVE_INTERCHAIN_TOKEN, '0x', 0, gasOptions),
service,
'CannotDeploy',
);
});

it('Should revert on deploying a local token manager with interchain token manager type', async () => {
await expectRevert(
(gasOptions) => tokenFactory.linkToken(salt, '', token.address, NATIVE_INTERCHAIN_TOKEN, wallet.address, 0, gasOptions),
service,
'CannotDeploy',
[NATIVE_INTERCHAIN_TOKEN],
);
});

it('Should revert on deploying a remote token manager with interchain token manager type', async () => {
await expectRevert(
(gasOptions) =>
tokenFactory.linkToken(
salt,
destinationChain,
token.address,
NATIVE_INTERCHAIN_TOKEN,
wallet.address,
0,
gasOptions,
),
service,
'CannotDeploy',
[NATIVE_INTERCHAIN_TOKEN],
);
});

it('Should revert on deploying a token manager if token handler post deploy fails', async () => {
await expectRevert(
(gasOptions) => tokenFactory.linkToken(salt, '', AddressZero, LOCK_UNLOCK, wallet.address, 0, gasOptions),
service,
'PostDeployFailed',
);
});

it('Should deploy a lock_unlock token manager', async () => {
const tokenManagerAddress = await service.tokenManagerAddress(tokenId);
const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]);

await expect(
reportGas(
tokenFactory.linkToken(salt, '', token.address, LOCK_UNLOCK, wallet.address, 0),
'Call deployTokenManager on source chain',
),
)
.to.emit(service, 'InterchainTokenIdClaimed')
.withArgs(tokenId, AddressZero, factorySalt)
.to.emit(service, 'TokenManagerDeployed')
.withArgs(tokenId, tokenManagerAddress, LOCK_UNLOCK, params);

expect(tokenManagerAddress).to.not.equal(AddressZero);
const tokenManager = await getContractAt('TokenManager', tokenManagerAddress, wallet);

expect(await tokenManager.isOperator(wallet.address)).to.be.true;
expect(await tokenManager.isOperator(service.address)).to.be.true;
expect(await tokenManager.isFlowLimiter(wallet.address)).to.be.true;
expect(await tokenManager.isFlowLimiter(service.address)).to.be.true;

const tokenAddress = await service.registeredTokenAddress(tokenId);
expect(tokenAddress).to.eq(token.address);

tokenManagerProxy = await getContractAt('TokenManagerProxy', tokenManagerAddress, wallet);

const [implementation, tokenAddressFromProxy] = await tokenManagerProxy.getImplementationTypeAndTokenAddress();
expect(implementation).to.eq(LOCK_UNLOCK);
expect(tokenAddressFromProxy).to.eq(token.address);
});

it('Should revert when deploying a custom token manager twice', async () => {
const revertData = keccak256(toUtf8Bytes('AlreadyDeployed()')).substring(0, 10);
await expectRevert(
(gasOptions) => tokenFactory.linkToken(salt, '', token.address, LOCK_UNLOCK, wallet.address, 0, gasOptions),
service,
'TokenManagerDeploymentFailed',
[revertData],
);
});

it('Should revert when calling unsupported functions directly on the token manager implementation', async () => {
const implementationAddress = await tokenManagerProxy.implementation();
const implementationContract = await getContractAt('TokenManager', implementationAddress, wallet);
await expectRevert((gasOptions) => implementationContract.tokenAddress(gasOptions), implementationContract, 'NotSupported');
await expectRevert(
(gasOptions) => implementationContract.interchainTokenId(gasOptions),
implementationContract,
'NotSupported',
);
await expectRevert(
(gasOptions) => implementationContract.implementationType(gasOptions),
implementationContract,
'NotSupported',
);
});

it('Should deploy a mint_burn token manager', async () => {
const salt = getRandomBytes32();
const tokenId = await tokenFactory.linkedTokenId(wallet.address, salt);
const tokenManagerAddress = await service.tokenManagerAddress(tokenId);
const token = await deployContract(wallet, 'TestInterchainTokenStandard', [
tokenName,
tokenSymbol,
tokenDecimals,
service.address,
tokenId,
]);
const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]);

const tx = tokenFactory.linkToken(salt, '', token.address, MINT_BURN, wallet.address, 0);
const expectedTokenManagerAddress = await service.tokenManagerAddress(tokenId);
await expect(tx).to.emit(service, 'TokenManagerDeployed').withArgs(tokenId, expectedTokenManagerAddress, MINT_BURN, params);

expect(tokenManagerAddress).to.not.equal(AddressZero);
const tokenManager = await getContractAt('TokenManager', tokenManagerAddress, wallet);

expect(await tokenManager.isOperator(wallet.address)).to.be.true;
expect(await tokenManager.isOperator(service.address)).to.be.true;
expect(await tokenManager.isFlowLimiter(wallet.address)).to.be.true;
expect(await tokenManager.isFlowLimiter(service.address)).to.be.true;

const tokenAddress = await service.registeredTokenAddress(tokenId);
expect(tokenAddress).to.eq(token.address);

const tokenManagerProxy = await getContractAt('TokenManagerProxy', tokenManagerAddress, wallet);

const [implementation, tokenAddressFromProxy] = await tokenManagerProxy.getImplementationTypeAndTokenAddress();
expect(implementation).to.eq(MINT_BURN);
expect(tokenAddressFromProxy).to.eq(token.address);
});

it('Should deploy a mint_burn_from token manager', async () => {
const salt = getRandomBytes32();
const tokenId = await tokenFactory.linkedTokenId(wallet.address, salt);
const tokenManagerAddress = await service.tokenManagerAddress(tokenId);
const token = await deployContract(wallet, 'TestInterchainTokenStandard', [
tokenName,
tokenSymbol,
tokenDecimals,
service.address,
tokenId,
]);
const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]);

const tx = tokenFactory.linkToken(salt, '', token.address, MINT_BURN_FROM, wallet.address, 0);
const expectedTokenManagerAddress = await service.tokenManagerAddress(tokenId);
await expect(tx)
.to.emit(service, 'TokenManagerDeployed')
.withArgs(tokenId, expectedTokenManagerAddress, MINT_BURN_FROM, params);

expect(tokenManagerAddress).to.not.equal(AddressZero);
const tokenManager = await getContractAt('TokenManager', tokenManagerAddress, wallet);

expect(await tokenManager.isOperator(wallet.address)).to.be.true;
expect(await tokenManager.isOperator(service.address)).to.be.true;
expect(await tokenManager.isFlowLimiter(wallet.address)).to.be.true;
expect(await tokenManager.isFlowLimiter(service.address)).to.be.true;

const tokenAddress = await service.registeredTokenAddress(tokenId);
expect(tokenAddress).to.eq(token.address);

const tokenManagerProxy = await getContractAt('TokenManagerProxy', tokenManagerAddress, wallet);

const [implementation, tokenAddressFromProxy] = await tokenManagerProxy.getImplementationTypeAndTokenAddress();
expect(implementation).to.eq(MINT_BURN_FROM);
expect(tokenAddressFromProxy).to.eq(token.address);
});

it('Should deploy a lock_unlock_with_fee token manager', async () => {
const salt = getRandomBytes32();
const tokenId = await tokenFactory.linkedTokenId(wallet.address, salt);
const tokenManagerAddress = await service.tokenManagerAddress(tokenId);
const token = await deployContract(wallet, 'TestFeeOnTransferToken', [
tokenName,
tokenSymbol,
tokenDecimals,
service.address,
tokenId,
]);
const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]);

const tx = tokenFactory.linkToken(salt, '', token.address, LOCK_UNLOCK_FEE_ON_TRANSFER, wallet.address, 0);
const expectedTokenManagerAddress = await service.tokenManagerAddress(tokenId);
await expect(tx)
.to.emit(service, 'TokenManagerDeployed')
.withArgs(tokenId, expectedTokenManagerAddress, LOCK_UNLOCK_FEE_ON_TRANSFER, params);

expect(tokenManagerAddress).to.not.equal(AddressZero);
const tokenManager = await getContractAt('TokenManager', tokenManagerAddress, wallet);

expect(await tokenManager.isOperator(wallet.address)).to.be.true;
expect(await tokenManager.isOperator(service.address)).to.be.true;
expect(await tokenManager.isFlowLimiter(wallet.address)).to.be.true;
expect(await tokenManager.isFlowLimiter(service.address)).to.be.true;

const tokenAddress = await service.registeredTokenAddress(tokenId);
expect(tokenAddress).to.eq(token.address);

const tokenManagerProxy = await getContractAt('TokenManagerProxy', tokenManagerAddress, wallet);

const [implementation, tokenAddressFromProxy] = await tokenManagerProxy.getImplementationTypeAndTokenAddress();
expect(implementation).to.eq(LOCK_UNLOCK_FEE_ON_TRANSFER);
expect(tokenAddressFromProxy).to.eq(token.address);
});

it('Should revert when deploying a custom token manager if paused', async () => {
await service.setPauseStatus(true).then((tx) => tx.wait);

await expectRevert(
(gasOptions) => tokenFactory.linkToken(salt, '', token.address, LOCK_UNLOCK, wallet.address, 0, gasOptions),
service,
'Pause',
);

await service.setPauseStatus(false).then((tx) => tx.wait);
});
});
});
});

0 comments on commit a09628e

Please sign in to comment.