-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: test hardcoded constants (#119)
* renamed folder and changed version * npmignore * npmignore * change version * using include pattern instead. * Fixed most of the things least auhority suggested. * made lint happy * Apply suggestions from code review * fixed some bugs * added events * rename set to transfer for distributor and operator * changed standardized token to always allow token managers to mint/burn it. * using immutable storage for remoteAddressValidator address to save gas * Added some recommended changes * added milap's suggested changes * Fixed some names and some minor gas optimizations * prettier and lint * stash * import .env in hardhat.config * trying to fix .env.example * Added some getters in IRemoteAddressValidator and removed useless check for distributor in the InterchainTokenService. * removed ternary operators * made lint happy * made lint happy * Added a new token manager to handle fee on transfer and added some tests for it as well * fixed the liquidity pool check. * fix a duplication bug * lint * added some more tests * Added more tests * Added proper re-entrancy protection for fee on transfer token managers. * change to tx.origin for refunds * Added support for more kinds of addresses. * some minor gas opts * some more gas optimizations. * Added a getter for chain name to the remote address validator. * moved the tokenManager getter functionality to a separate contract which saves almost a kilobyte of codesize. * made lint happy * Removed tokenManagerGetter and put params into tokenManagers * Added separate tokenManager interfaces * addressed ackeeblockchains's 3.0 report * prettier * added interchain transfer methods to the service and unified receiving tokens a bit. * made lint happy * rename sendToken to interchainTransfer * changed sendToken everywhere * changed from uint256.max to a const * change setting to zero to delete for storage slots. * rearange storage variables to save a bit of gas. * Removed unecesairy casts * made as many event params inexed as possible * Removed unused imports * domain separator is calculated each time. * added some natspec * added an example for using pre-existing custom tokens. * added a comment * feat: improved test coverage part one * feat: live testnet support * fix: remove exclusive mocha test * fix: remove hardcoded gas options * feat: increased test coverage part two * fix: remove comment * feat: add test * feat: increased test coverage part three * fix(InvalidStandardizedToken): imports * feat: address comments * feat: test hardcoded constants * fix: ITS tests * fix: deployed bytecode * fix: tests * fix: tests * fix: remove broken test * feat: add tests * feat: temp file rename * feat: capitalize test file names * fix: remove duplicate lockUnlockFee deploy functions * fix: re-add hardcoded constants utils tests --------- Co-authored-by: Foivos <[email protected]> Co-authored-by: Milap Sheth <[email protected]> Co-authored-by: Dean Amiel <[email protected]> Co-authored-by: Kiryl Yermakou <[email protected]>
- Loading branch information
1 parent
d4e26d4
commit dad864f
Showing
6 changed files
with
299 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
import { TokenManagerLiquidityPool } from '../token-manager/implementations/TokenManagerLiquidityPool.sol'; | ||
import { Distributable } from '../utils/Distributable.sol'; | ||
import { FlowLimit } from '../utils/FlowLimit.sol'; | ||
import { NoReEntrancy } from '../utils/NoReEntrancy.sol'; | ||
import { Operatable } from '../utils/Operatable.sol'; | ||
import { Pausable } from '../utils/Pausable.sol'; | ||
|
||
contract TestTokenManager is TokenManagerLiquidityPool { | ||
string public constant NAME = 'TestTokenManager'; | ||
|
||
constructor(address interchainTokenService_) TokenManagerLiquidityPool(interchainTokenService_) { | ||
require(TOKEN_ADDRESS_SLOT == uint256(keccak256('token-address')) - 1, 'invalid constant'); | ||
require(LIQUIDITY_POOL_SLOT == uint256(keccak256('liquidity-pool-slot')) - 1, 'invalid constant'); | ||
} | ||
} | ||
|
||
contract TestDistributable is Distributable { | ||
string public constant NAME = 'TestDistributable'; | ||
|
||
constructor() { | ||
require(DISTRIBUTOR_SLOT == uint256(keccak256('distributor')) - 1, 'invalid constant'); | ||
require(PROPOSED_DISTRIBUTOR_SLOT == uint256(keccak256('proposed-distributor')) - 1, 'invalid constant'); | ||
} | ||
} | ||
|
||
contract TestFlowLimit is FlowLimit { | ||
string public constant NAME = 'TestFlowLimit'; | ||
|
||
constructor() { | ||
require(FLOW_LIMIT_SLOT == uint256(keccak256('flow-limit')) - 1, 'invalid constant'); | ||
} | ||
} | ||
|
||
contract TestNoReEntrancy is NoReEntrancy { | ||
string public constant NAME = 'TestNoReEntrancy'; | ||
|
||
constructor() { | ||
require(ENTERED_SLOT == uint256(keccak256('entered')) - 1, 'invalid constant'); | ||
} | ||
} | ||
|
||
contract TestOperatable is Operatable { | ||
string public constant NAME = 'TestOperatable'; | ||
|
||
constructor() { | ||
require(OPERATOR_SLOT == uint256(keccak256('operator')) - 1, 'invalid constant'); | ||
require(PROPOSED_OPERATOR_SLOT == uint256(keccak256('proposed-operator')) - 1, 'invalid constant'); | ||
} | ||
} | ||
|
||
contract TestPausable is Pausable { | ||
string public constant NAME = 'TestPausable'; | ||
|
||
constructor() { | ||
require(PAUSE_SLOT == uint256(keccak256('paused')) - 1, 'invalid constant'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
'use strict'; | ||
|
||
const chai = require('chai'); | ||
const { ethers } = require('hardhat'); | ||
const { | ||
Contract, | ||
utils: { keccak256, toUtf8Bytes }, | ||
} = ethers; | ||
const { expect } = chai; | ||
const { getRandomBytes32, expectRevert, getGasOptions } = require('./utils'); | ||
const { deployContract } = require('../scripts/deploy'); | ||
|
||
const StandardizedToken = require('../artifacts/contracts/token-implementations/StandardizedToken.sol/StandardizedToken.json'); | ||
const StandardizedTokenProxy = require('../artifacts/contracts/proxies/StandardizedTokenProxy.sol/StandardizedTokenProxy.json'); | ||
|
||
describe('StandardizedToken', () => { | ||
let standardizedToken, standardizedTokenDeployer; | ||
|
||
const name = 'tokenName'; | ||
const symbol = 'tokenSymbol'; | ||
const decimals = 18; | ||
const mintAmount = 123; | ||
|
||
let token; | ||
let tokenProxy; | ||
|
||
let owner; | ||
|
||
before(async () => { | ||
const wallets = await ethers.getSigners(); | ||
owner = wallets[0]; | ||
|
||
standardizedToken = await deployContract(owner, 'StandardizedToken'); | ||
standardizedTokenDeployer = await deployContract(owner, 'StandardizedTokenDeployer', [standardizedToken.address]); | ||
|
||
const salt = getRandomBytes32(); | ||
|
||
const tokenAddress = await standardizedTokenDeployer.deployedAddress(salt); | ||
|
||
token = new Contract(tokenAddress, StandardizedToken.abi, owner); | ||
tokenProxy = new Contract(tokenAddress, StandardizedTokenProxy.abi, owner); | ||
|
||
await standardizedTokenDeployer | ||
.deployStandardizedToken(salt, owner.address, owner.address, name, symbol, decimals, mintAmount, owner.address) | ||
.then((tx) => tx.wait()); | ||
}); | ||
|
||
describe('Standardized Token Proxy', () => { | ||
it('should revert if standardized token implementation is invalid', async () => { | ||
const invalidStandardizedToken = await deployContract(owner, 'InvalidStandardizedToken'); | ||
standardizedTokenDeployer = await deployContract(owner, 'StandardizedTokenDeployer', [invalidStandardizedToken.address]); | ||
|
||
const salt = getRandomBytes32(); | ||
|
||
await expect( | ||
standardizedTokenDeployer.deployStandardizedToken( | ||
salt, | ||
owner.address, | ||
owner.address, | ||
name, | ||
symbol, | ||
decimals, | ||
mintAmount, | ||
owner.address, | ||
getGasOptions(), | ||
), | ||
).to.be.reverted; | ||
}); | ||
|
||
it('should revert if standardized token setup fails', async () => { | ||
const params = '0x1234'; | ||
await expectRevert( | ||
(gasOptions) => deployContract(owner, 'StandardizedTokenProxy', [standardizedToken.address, params, gasOptions]), | ||
tokenProxy, | ||
'SetupFailed', | ||
); | ||
}); | ||
|
||
it('should return the correct contract ID', async () => { | ||
const contractID = await token.contractId(); | ||
const hash = keccak256(toUtf8Bytes('standardized-token')); | ||
expect(contractID).to.equal(hash); | ||
}); | ||
}); | ||
|
||
describe('Standardized Token', () => { | ||
it('revert on setup if not called by the proxy', async () => { | ||
const implementationAddress = await tokenProxy.implementation(); | ||
const implementation = new Contract(implementationAddress, StandardizedToken.abi, owner); | ||
|
||
const params = '0x'; | ||
await expectRevert((gasOptions) => implementation.setup(params, gasOptions), token, 'NotProxy'); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
'use strict'; | ||
|
||
const chai = require('chai'); | ||
const { ethers } = require('hardhat'); | ||
const { | ||
utils: { toUtf8Bytes, defaultAbiCoder }, | ||
constants: { AddressZero }, | ||
} = ethers; | ||
const { expect } = chai; | ||
const { expectRevert } = require('./utils'); | ||
const { deployContract } = require('../scripts/deploy'); | ||
|
||
describe('Token Manager', () => { | ||
let owner, user, token, service, liquidityPool; | ||
let tokenManagerLockUnlock, tokenManagerMintBurn, tokenManagerLiquidityPool, tokenManagerLockUnlockFeeOnTransfer; | ||
|
||
before(async () => { | ||
[owner, user, token, service, liquidityPool] = await ethers.getSigners(); | ||
|
||
tokenManagerLockUnlock = await deployContract(owner, `TokenManagerLockUnlock`, [service.address]); | ||
tokenManagerMintBurn = await deployContract(owner, `TokenManagerMintBurn`, [service.address]); | ||
tokenManagerLiquidityPool = await deployContract(owner, `TokenManagerLiquidityPool`, [service.address]); | ||
tokenManagerLockUnlockFeeOnTransfer = await deployContract(owner, `TokenManagerLockUnlockFee`, [service.address]); | ||
}); | ||
|
||
it('Should calculate hardcoded constants correctly', async () => { | ||
await expect(deployContract(owner, `TestTokenManager`, [service.address])).to.not.be.reverted; | ||
}); | ||
|
||
it('Should revert on token manager deployment with invalid service address', async () => { | ||
await expectRevert( | ||
(gasOptions) => deployContract(owner, `TokenManagerLockUnlock`, [AddressZero, gasOptions]), | ||
tokenManagerLockUnlock, | ||
'TokenLinkerZeroAddress', | ||
); | ||
}); | ||
|
||
it('Should revert on setup if not called by the proxy', async () => { | ||
const params = '0x'; | ||
await expectRevert((gasOptions) => tokenManagerLockUnlock.setup(params, gasOptions), tokenManagerLockUnlock, 'NotProxy'); | ||
}); | ||
|
||
it('Should revert on transmitInterchainTransfer if not called by the token', async () => { | ||
const sender = owner.address; | ||
const destinationChain = 'Dest Chain'; | ||
const destinationAddress = toUtf8Bytes(user.address); | ||
const amount = 10; | ||
const metadata = '0x00000000'; | ||
|
||
await expectRevert( | ||
(gasOptions) => | ||
tokenManagerLockUnlock.transmitInterchainTransfer( | ||
sender, | ||
destinationChain, | ||
destinationAddress, | ||
amount, | ||
metadata, | ||
gasOptions, | ||
), | ||
tokenManagerLockUnlock, | ||
'NotToken', | ||
); | ||
}); | ||
|
||
it('Should revert on giveToken if not called by the service', async () => { | ||
const destinationAddress = user.address; | ||
const amount = 10; | ||
|
||
await expectRevert( | ||
(gasOptions) => tokenManagerLockUnlock.giveToken(destinationAddress, amount, gasOptions), | ||
tokenManagerLockUnlock, | ||
'NotService', | ||
); | ||
}); | ||
|
||
it('Should revert on takeToken if not called by the service', async () => { | ||
const sourceAddress = user.address; | ||
const amount = 10; | ||
|
||
await expectRevert( | ||
(gasOptions) => tokenManagerLockUnlock.takeToken(sourceAddress, amount, gasOptions), | ||
tokenManagerLockUnlock, | ||
'NotService', | ||
); | ||
}); | ||
|
||
it('Should revert on setFlowLimit if not called by the operator', async () => { | ||
const flowLimit = 100; | ||
|
||
await expectRevert( | ||
(gasOptions) => tokenManagerLockUnlock.setFlowLimit(flowLimit, gasOptions), | ||
tokenManagerLockUnlock, | ||
'NotOperator', | ||
); | ||
}); | ||
|
||
it('Should return the correct parameters for lock/unlock token manager', async () => { | ||
const expectedParams = defaultAbiCoder.encode(['bytes', 'address'], [toUtf8Bytes(owner.address), token.address]); | ||
const params = await tokenManagerLockUnlock.getParams(toUtf8Bytes(owner.address), token.address); | ||
expect(expectedParams).to.eq(params); | ||
}); | ||
|
||
it('Should return the correct parameters for mint/burn token manager', async () => { | ||
const expectedParams = defaultAbiCoder.encode(['bytes', 'address'], [toUtf8Bytes(owner.address), token.address]); | ||
const params = await tokenManagerMintBurn.getParams(toUtf8Bytes(owner.address), token.address); | ||
expect(expectedParams).to.eq(params); | ||
}); | ||
|
||
it('Should return the correct parameters for liquidity pool token manager', async () => { | ||
const expectedParams = defaultAbiCoder.encode( | ||
['bytes', 'address', 'address'], | ||
[toUtf8Bytes(owner.address), token.address, liquidityPool.address], | ||
); | ||
const params = await tokenManagerLiquidityPool.getParams(toUtf8Bytes(owner.address), token.address, liquidityPool.address); | ||
expect(expectedParams).to.eq(params); | ||
}); | ||
|
||
it('Should return the correct parameters for fee on transfer token manager', async () => { | ||
const expectedParams = defaultAbiCoder.encode(['bytes', 'address'], [toUtf8Bytes(owner.address), token.address]); | ||
const params = await tokenManagerLockUnlockFeeOnTransfer.getParams(toUtf8Bytes(owner.address), token.address); | ||
expect(expectedParams).to.eq(params); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters