Skip to content
This repository was archived by the owner on Apr 4, 2025. It is now read-only.

Commit 7a0c6f7

Browse files
authored
Merge pull request #43 from code-423n4/saleMod
Allow for new token sale, check for buyer vest schedule, cap sale recipient amount
2 parents bae376b + 3615c7c commit 7a0c6f7

File tree

12 files changed

+472
-141
lines changed

12 files changed

+472
-141
lines changed

contracts/ArenaTokenSale.sol renamed to contracts/TokenSale.sol

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pragma solidity 0.8.10;
44
import "@openzeppelin/contracts/access/Ownable.sol";
55
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
66

7-
import "../interfaces/IRevokableTokenLock.sol";
7+
import "../interfaces/ITokenLockVestReader.sol";
88

99
/**
1010
* @dev Sells a token at a predetermined price to whitelisted buyers. The number of tokens each address can buy can be regulated.
@@ -15,22 +15,25 @@ contract TokenSale is Ownable {
1515
/// token to give out (ARENA)
1616
ERC20 public immutable tokenOut;
1717
/// time when tokens can be first purchased
18-
uint64 public immutable saleStart;
18+
uint64 public saleStart;
1919
/// duration of the token sale, cannot purchase afterwards
2020
uint64 public immutable saleDuration;
21-
/// address receiving the proceeds of the sale
22-
address internal saleRecipient;
21+
/// address receiving a defined portion proceeds of the sale
22+
address internal immutable saleRecipient;
23+
/// amount receivable by sale recipient
24+
uint256 public remainingSaleRecipientAmount;
2325
/// vesting contract
24-
IRevokableTokenLock public tokenLock;
26+
ITokenLockVestReader public immutable tokenLock;
2527
/// vesting duration
26-
uint256 public vestDuration;
28+
uint256 public immutable vestDuration;
2729

2830
/// how many `tokenOut`s each address may buy
2931
mapping(address => uint256) public whitelistedBuyersAmount;
3032
/// tokenIn per tokenOut price. precision is in tokenInDecimals - tokenOutDecimals + 18
3133
/// i.e., it should be provided as tokenInAmount * 1e18 / tokenOutAmount
3234
uint256 public immutable tokenOutPrice;
3335

36+
event BuyerWhitelisted(address indexed buyer, uint256 amount);
3437
event Sale(address indexed buyer, uint256 amountIn, uint256 amountOut);
3538

3639
/**
@@ -40,9 +43,10 @@ contract TokenSale is Ownable {
4043
* @param _saleStart The time when tokens can be first purchased
4144
* @param _saleDuration The duration of the token sale
4245
* @param _tokenOutPrice The tokenIn per tokenOut price. precision should be in tokenInDecimals - tokenOutDecimals + 18
43-
* @param _saleRecipient The address receiving the proceeds of the sale
46+
* @param _saleRecipient The address receiving a portion proceeds of the sale
4447
* @param _tokenLock The contract in which _tokenOut will be vested in
4548
* @param _vestDuration Token vesting duration
49+
* @param _saleRecipientAmount Amount receivable by sale recipient
4650
*/
4751
constructor(
4852
ERC20 _tokenIn,
@@ -52,7 +56,8 @@ contract TokenSale is Ownable {
5256
uint256 _tokenOutPrice,
5357
address _saleRecipient,
5458
address _tokenLock,
55-
uint256 _vestDuration
59+
uint256 _vestDuration,
60+
uint256 _saleRecipientAmount
5661
) {
5762
require(block.timestamp <= _saleStart, "TokenSale: start date may not be in the past");
5863
require(_saleDuration > 0, "TokenSale: the sale duration must not be zero");
@@ -70,9 +75,9 @@ contract TokenSale is Ownable {
7075
saleDuration = _saleDuration;
7176
tokenOutPrice = _tokenOutPrice;
7277
saleRecipient = _saleRecipient;
73-
74-
tokenLock = IRevokableTokenLock(_tokenLock);
78+
tokenLock = ITokenLockVestReader(_tokenLock);
7579
vestDuration = _vestDuration;
80+
remainingSaleRecipientAmount = _saleRecipientAmount;
7681
}
7782

7883
/**
@@ -86,10 +91,31 @@ contract TokenSale is Ownable {
8691
require(_tokenOutAmount > 0, "TokenSale: non-whitelisted purchaser or have already bought");
8792
whitelistedBuyersAmount[msg.sender] = 0;
8893
tokenInAmount_ = (_tokenOutAmount * tokenOutPrice) / 1e18;
89-
require(
90-
tokenIn.transferFrom(msg.sender, saleRecipient, tokenInAmount_),
91-
"TokenSale: tokenIn transfer failed"
92-
);
94+
95+
// saleRecipient will receive proceeds first, until fully allocated
96+
if (tokenInAmount_ <= remainingSaleRecipientAmount) {
97+
remainingSaleRecipientAmount -= tokenInAmount_;
98+
require(
99+
tokenIn.transferFrom(msg.sender, saleRecipient, tokenInAmount_),
100+
"TokenSale: tokenIn transfer failed"
101+
);
102+
} else {
103+
// saleRecipient will either be receiving or have received full allocation
104+
// portion will go to owner
105+
uint256 ownerAmount = tokenInAmount_ - remainingSaleRecipientAmount;
106+
require(
107+
tokenIn.transferFrom(msg.sender, owner(), ownerAmount),
108+
"TokenSale: tokenIn transfer failed"
109+
);
110+
if (remainingSaleRecipientAmount > 0) {
111+
uint256 saleRecipientAmount = remainingSaleRecipientAmount;
112+
remainingSaleRecipientAmount = 0;
113+
require(
114+
tokenIn.transferFrom(msg.sender, saleRecipient, saleRecipientAmount),
115+
"TokenSale: tokenIn transfer failed"
116+
);
117+
}
118+
}
93119

94120
uint256 claimableAmount = (_tokenOutAmount * 2_000) / 10_000;
95121
uint256 remainingAmount;
@@ -103,7 +129,7 @@ contract TokenSale is Ownable {
103129
"TokenSale: tokenOut transfer failed"
104130
);
105131

106-
// if we use same tokenLock instance as airdrop, we make sure that
132+
// we use same tokenLock instance as airdrop, we make sure that
107133
// the claimers and buyers are distinct to not reinitialize vesting
108134
tokenLock.setupVesting(
109135
msg.sender,
@@ -131,18 +157,42 @@ contract TokenSale is Ownable {
131157
_buyers.length == _newTokenOutAmounts.length,
132158
"TokenSale: parameter length mismatch"
133159
);
134-
require(block.timestamp < saleStart, "TokenSale: sale already started");
160+
require(
161+
block.timestamp < saleStart || block.timestamp > saleStart + saleDuration,
162+
"TokenSale: ongoing sale"
163+
);
135164

136165
for (uint256 i = 0; i < _buyers.length; i++) {
166+
// Does not cover the case that the buyer has not claimed his airdrop
167+
// So it will have to be somewhat manually checked
168+
ITokenLockVestReader.VestingParams memory vestParams = tokenLock.vesting(_buyers[i]);
169+
require(vestParams.unlockBegin == 0, "TokenSale: buyer has existing vest schedule");
137170
whitelistedBuyersAmount[_buyers[i]] = _newTokenOutAmounts[i];
171+
emit BuyerWhitelisted(_buyers[i], _newTokenOutAmounts[i]);
138172
}
139173
}
140174

175+
/**
176+
* @dev Modifies the start time of the sale. Enables a new sale to be created assuming one is not ongoing
177+
* @dev A new list of buyers and tokenAmounts can be done by calling changeWhiteList()
178+
* @param _newSaleStart The new start time of the token sale
179+
*/
180+
function setNewSaleStart(uint64 _newSaleStart) external {
181+
require(msg.sender == owner() || msg.sender == saleRecipient, "TokenSale: not authorized");
182+
// can only change if there is no ongoing sale
183+
require(
184+
block.timestamp < saleStart || block.timestamp > saleStart + saleDuration,
185+
"TokenSale: ongoing sale"
186+
);
187+
require(block.timestamp < _newSaleStart, "TokenSale: new sale too early");
188+
saleStart = _newSaleStart;
189+
}
190+
141191
/**
142192
* @dev Transfers out any remaining `tokenOut` after the sale to owner
143193
*/
144194
function sweepTokenOut() external {
145-
require(saleStart + saleDuration < block.timestamp, "TokenSale: sale did not end yet");
195+
require(saleStart + saleDuration < block.timestamp, "TokenSale: ongoing sale");
146196

147197
uint256 tokenOutBalance = tokenOut.balanceOf(address(this));
148198
require(tokenOut.transfer(owner(), tokenOutBalance), "TokenSale: transfer failed");

deployments/polygonAddresses.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
"token": "0x6847D3A4c80a82e1fb26f1fC6F09F3Ad5BEB5222",
44
"tokenLock": "0xB17828789280C77C17B02fc8E6F20Ddc5721f2C2",
55
"timelock": "0xdFB26381aFBc37f0Fae4A77D385b91B90347aA12",
6-
"governor": "0xc6eaDcC36aFcf1C430962506ad79145aD5140E58"
6+
"governor": "0xc6eaDcC36aFcf1C430962506ad79145aD5140E58",
7+
"tokenSale": "0xD0e7d5a2220e32914540D97A6D0548658050180b"
78
}

hardhat.config.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ const config: HardhatUserConfig = {
4646
accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
4747
},
4848
},
49+
etherscan: {
50+
apiKey: {
51+
polygon: process.env.POLYGONSCAN_API_KEY == undefined ? '' : process.env.POLYGONSCAN_API_KEY,
52+
}
53+
},
4954
typechain: {
5055
outDir: 'typechain',
5156
target: 'ethers-v5',
@@ -54,9 +59,6 @@ const config: HardhatUserConfig = {
5459
enabled: process.env.REPORT_GAS !== undefined,
5560
currency: 'USD',
5661
},
57-
etherscan: {
58-
apiKey: process.env.ETHERSCAN_API_KEY,
59-
},
6062
mocha: {
6163
// 1 hour, essentially disabled auto timeout
6264
timeout: 60 * 60 * 1000,

interfaces/ITokenLockVestReader.sol

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.10;
3+
4+
import "./IRevokableTokenLock.sol";
5+
6+
interface ITokenLockVestReader is IRevokableTokenLock {
7+
struct VestingParams {
8+
uint256 unlockBegin;
9+
uint256 unlockCliff;
10+
uint256 unlockEnd;
11+
uint256 lockedAmounts;
12+
uint256 claimedAmounts;
13+
}
14+
15+
function vesting(address) external view returns (VestingParams memory);
16+
}

package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@
2424
},
2525
"homepage": "https://github.com/code-423n4/genesis#readme",
2626
"dependencies": {
27-
"hardhat": "2.7.0",
27+
"hardhat": "2.8.3",
2828
"lodash": "^4.17.21"
2929
},
3030
"devDependencies": {
31-
"@nomiclabs/hardhat-ethers": "^2.0.3",
32-
"@nomiclabs/hardhat-etherscan": "2.1.7",
31+
"@nomiclabs/hardhat-ethers": "^2.0.4",
32+
"@nomiclabs/hardhat-etherscan": "3.0.0",
3333
"@nomiclabs/hardhat-waffle": "^2.0.0",
3434
"@openzeppelin/contracts": "^4.4.0",
35-
"@typechain/ethers-v5": "^7.0.1",
36-
"@typechain/hardhat": "^2.3.0",
35+
"@typechain/ethers-v5": "^9.0.0",
36+
"@typechain/hardhat": "^4.0.0",
3737
"@types/chai": "^4.2.21",
3838
"@types/lodash": "^4.14.178",
3939
"@types/mocha": "^9.0.0",
@@ -60,7 +60,7 @@
6060
"solidity-coverage": "^0.7.16",
6161
"ts-generator": "^0.1.1",
6262
"ts-node": "^10.4.0",
63-
"typechain": "^5.1.2",
64-
"typescript": "^4.3.5"
63+
"typechain": "^7.0.0",
64+
"typescript": "^4.5.5"
6565
}
6666
}

scripts/deploy/config.ts

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,22 @@ type TokenSaleConfig = {
1919
TOKEN_SALE_ARENA_PRICE: BN;
2020
TOKEN_SALE_RECIPIENT: string;
2121
TOKEN_SALE_WHITELIST: typeof TOKEN_SALE_WHITELIST;
22+
RECIPIENT_AMOUNT: BN;
23+
TOKEN_SALE_SUPPLY: BN;
2224
};
2325

2426
const TOKEN_SALE_WHITELIST = [
25-
{buyer: '0x0f4Aeb1847B7F1a735f4a5Af7E8C299b793c1a9A', arenaAmount: BN.from(`10000`).mul(ONE_18)},
26-
{buyer: '0x3Ab0029e1C4515134464b267557cB80A39902699', arenaAmount: BN.from(`10001`).mul(ONE_18)},
27-
{buyer: '0x4F3F7ca7E91D869180EBbA55e4322845a8Dc6862', arenaAmount: BN.from(`10002`).mul(ONE_18)},
28-
{buyer: '0x5dcEb6f4dc5b64Af6271A5Ab3297DbE3C01dd57B', arenaAmount: BN.from(`10003`).mul(ONE_18)},
29-
{buyer: '0x62641eAE546835813B56EC7b544756A532275Dd3', arenaAmount: BN.from(`10004`).mul(ONE_18)},
30-
{buyer: '0x670f9e8B37d5816c2eB93A1D94841C66652a8E26', arenaAmount: BN.from(`10005`).mul(ONE_18)},
31-
{buyer: '0x691Cbab55CC1806d29994784Ba9d9e679c03f164', arenaAmount: BN.from(`10006`).mul(ONE_18)},
32-
{buyer: '0x697ccd97C8419EBba7347CEF03a0CD02804EbF54', arenaAmount: BN.from(`10007`).mul(ONE_18)},
33-
{buyer: '0x6c422839E7EceDb6d2A86F3F2bFd03aDd154Fc27', arenaAmount: BN.from(`10008`).mul(ONE_18)},
34-
{buyer: '0x7C0fb88c87c30eBF70340E25fe47763e53b907cF', arenaAmount: BN.from(`10009`).mul(ONE_18)},
35-
{buyer: '0x8498EAb53e03E3143d77B2303eDBdAC6C9041D33', arenaAmount: BN.from(`10010`).mul(ONE_18)},
36-
{buyer: '0x8D31BAC0870e323354eAF6F98277860772FFB2d4', arenaAmount: BN.from(`10011`).mul(ONE_18)},
37-
{buyer: '0xA432F83d8054F5F859cAcb86574baC5e07DD6529', arenaAmount: BN.from(`10012`).mul(ONE_18)},
38-
{buyer: '0xD3488b8C87416946D82CC957178B0863A1F089b2', arenaAmount: BN.from(`10013`).mul(ONE_18)},
39-
{buyer: '0xD5388291EAbe96b56069440C97046791E2F72573', arenaAmount: BN.from(`10014`).mul(ONE_18)},
40-
{buyer: '0xF20eb7eAf52712EA0Aa80467741f34E6b0dB18F8', arenaAmount: BN.from(`10015`).mul(ONE_18)},
41-
{buyer: '0xa1fA3C686C9c4E5e8407b32B67191B079a65ffD2', arenaAmount: BN.from(`10016`).mul(ONE_18)},
42-
{buyer: '0xbB79597641483Ed96BCE9fc24b4D63F720898b8A', arenaAmount: BN.from(`10017`).mul(ONE_18)},
43-
{buyer: '0xe552C6A88E71B2A5069Dec480507F54321Dc65F3', arenaAmount: BN.from(`10018`).mul(ONE_18)},
44-
{buyer: '0xf4290941dBc8b31c277E30deFF3fC59979FC6757', arenaAmount: BN.from(`10019`).mul(ONE_18)},
27+
{buyer: '0x1aa1F9f80f4c5dCe34d0f4faB4F66AAF562330bd', arenaAmount: BN.from(33_333_333).mul(ONE_18)},
28+
{buyer: '0x3a5c572aE7a806c661970058450dC90D9eF0f353', arenaAmount: BN.from(13_333_333).mul(ONE_18)},
29+
{buyer: '0xcfc50541c3dEaf725ce738EF87Ace2Ad778Ba0C5', arenaAmount: BN.from(10_166_666).mul(ONE_18)},
30+
{buyer: '0xC02ad7b9a9121fc849196E844DC869D2250DF3A6', arenaAmount: BN.from(8_333_333).mul(ONE_18)},
31+
{buyer: '0xCfCA53C4b6d3f763969c9A9C36DBCAd61F11F36D', arenaAmount: BN.from(6_666_666).mul(ONE_18)},
32+
{buyer: '0x636EDa86F6EC324347Bd560c1045192586b9DEE8', arenaAmount: BN.from(6_666_666).mul(ONE_18)},
33+
{buyer: '0xDbBB1bD4cbDA95dd2f1477be139C3D6cb9d2B349', arenaAmount: BN.from(3_333_333).mul(ONE_18)},
34+
{buyer: '0x4dA94e682326BD14997D1E1c62350654D8e44c5d', arenaAmount: BN.from(2_500_000).mul(ONE_18)},
35+
{buyer: '0x20392b9607dc8cC49BEa5B7B90E65d6251617538', arenaAmount: BN.from(1_166_666).mul(ONE_18)},
36+
{buyer: '0x83b23E8e5da74fD3f3E5471865FC778d9c843df0', arenaAmount: BN.from(833_333).mul(ONE_18)},
37+
{buyer: '0x7fCAf93cc92d51c490FFF701fb2C6197497a80db', arenaAmount: BN.from(833_333).mul(ONE_18)},
4538
];
4639

4740
export const allConfigs: {[key: number]: Config} = {
@@ -72,11 +65,13 @@ export const allConfigs: {[key: number]: Config} = {
7265
export const tokenSaleConfigs: {[key: number]: TokenSaleConfig} = {
7366
// polygon mainnet
7467
137: {
75-
TOKEN_SALE_START: Math.floor(new Date(`2022-01-12T00:00:00.000Z`).getTime() / 1000),
76-
TOKEN_SALE_DURATION: 14 * ONE_DAY,
68+
TOKEN_SALE_START: 1644451200, // Thursday, February 10, 2022 12:00:00 AM UTC
69+
TOKEN_SALE_DURATION: 10 * ONE_DAY,
7770
TOKEN_SALE_USDC: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174',
7871
TOKEN_SALE_ARENA_PRICE: BN.from(30_000).mul(ONE_18).div(ONE_18), // 0.03 USDC * 1e18 / 1.0 ARENA
79-
TOKEN_SALE_RECIPIENT: '0x670f9e8B37d5816c2eB93A1D94841C66652a8E26', // TODO: change to intended recipient
80-
TOKEN_SALE_WHITELIST, // TODO: update value
72+
TOKEN_SALE_RECIPIENT: '0x7f0049597056E37B4B1f887196E44CAc050D4863', // C4 Polygon multisig
73+
TOKEN_SALE_WHITELIST,
74+
RECIPIENT_AMOUNT: BN.from(1_750_000).mul(BN.from(10).pow(6)), // 1.75M USDC, rest to treasury
75+
TOKEN_SALE_SUPPLY: BN.from(100_000_000).mul(ONE_18), // 100M ARENA tokens
8176
},
8277
};

scripts/deploy/deployTokenSale.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414

1515
import {allConfigs, tokenSaleConfigs} from './config';
1616
import {HardhatRuntimeEnvironment} from 'hardhat/types';
17+
import {verifyContract} from './verify';
1718

1819
let proposerAddress: string;
1920
let tokenSale: TokenSale;
@@ -77,7 +78,8 @@ export async function deployTokenSale(hre: HardhatRuntimeEnvironment) {
7778
config.TOKEN_SALE_ARENA_PRICE,
7879
config.TOKEN_SALE_RECIPIENT,
7980
tokenLock.address,
80-
allConfigs[networkId].VEST_DURATION
81+
allConfigs[networkId].VEST_DURATION,
82+
config.RECIPIENT_AMOUNT
8183
);
8284
await tokenSale.deployed();
8385
console.log(`tokenSale address: ${tokenSale.address}`);
@@ -87,7 +89,6 @@ export async function deployTokenSale(hre: HardhatRuntimeEnvironment) {
8789
config.TOKEN_SALE_WHITELIST.map(({buyer}) => buyer),
8890
config.TOKEN_SALE_WHITELIST.map(({arenaAmount}) => arenaAmount)
8991
);
90-
const TOKEN_SALE_SUPPLY = config.TOKEN_SALE_WHITELIST.reduce((sum, el) => sum.add(el.arenaAmount), BN.from(`0`));
9192
// transfer token sale admin role to timelock
9293
await tokenSale.transferOwnership(timelock.address);
9394

@@ -97,14 +98,14 @@ export async function deployTokenSale(hre: HardhatRuntimeEnvironment) {
9798
let values: string[] = ['0', '0'];
9899
let calldatas: string[] = [
99100
tokenLock.interface.encodeFunctionData('setTokenSale', [tokenSale.address]),
100-
arenaToken.interface.encodeFunctionData('transfer', [tokenSale.address, TOKEN_SALE_SUPPLY]),
101+
arenaToken.interface.encodeFunctionData('transfer', [tokenSale.address, config.TOKEN_SALE_SUPPLY]),
101102
];
102103

103104
const tx = await governor['propose(address[],uint256[],bytes[],string)'](
104105
targets,
105106
values,
106107
calldatas,
107-
`Conduct Arena token sale!`
108+
`# C4IP-6: Transfer ARENA tokens for token sale\nThis proposal takes action on the token sale approved by [C4IP-1](<https://www.withtally.com/governance/eip155:137:0xc6eaDcC36aFcf1C430962506ad79145aD5140E58/proposal/61969381053746686972699442694032986733206504062025717191093241526145462208038>) and the hiring of Code4 Corporation approved by [C4IP-3](<https://www.withtally.com/governance/eip155:137:0xc6eaDcC36aFcf1C430962506ad79145aD5140E58/proposal/46190911081008287731655546929165163023822387405966829437304548060152876868278>) both of which are discussed in detail in [this forum post](<https://forum.code4rena.com/t/c4ip-1-constitution-dao-bootstrapping-reimbursements-token-sale/93>)<br>\n\n- 100,000,000 $ARENA tokens transferred to the [token sale contract](<https://polygonscan.com/address/0xD0e7d5a2220e32914540D97A6D0548658050180b>)\n\n- Tokens are sold at price of 1 ARENA = .03 USDC\n\n- Token sale details to be administered by Code4 Corporation\n\n- $1.75M of the initial sale will immediately be used to fund Code4 Corporation operations\n\n- Remaining $1.25M proceeds will be transferred to the Code4rena treasury\n\n\n<!-- -->\n\n`
108109
);
109110
console.log(`proposal submitted: ${tx.hash}`);
110111
console.log(`waiting for block inclusion ...`);
@@ -116,12 +117,23 @@ export async function deployTokenSale(hre: HardhatRuntimeEnvironment) {
116117
let exportJson = JSON.stringify(addressesToExport, null, 2);
117118
fs.writeFileSync(deploymentFilePath, exportJson);
118119

120+
console.log(`Verifying tokenSale contract...`);
121+
await verifyContract(hre, tokenSale.address, [
122+
config.TOKEN_SALE_USDC,
123+
arenaToken.address,
124+
config.TOKEN_SALE_START,
125+
config.TOKEN_SALE_DURATION,
126+
config.TOKEN_SALE_ARENA_PRICE,
127+
config.TOKEN_SALE_RECIPIENT,
128+
tokenLock.address,
129+
allConfigs[networkId].VEST_DURATION,
130+
config.RECIPIENT_AMOUNT,
131+
]);
132+
119133
/////////////////////////////////
120134
// ACCESS CONTROL VERIFICATION //
121135
/////////////////////////////////
122136
console.log('verifying access control settings...');
123-
// check tokenSale's tokenlock has been set
124-
expect(await tokenSale.tokenLock()).to.be.eq(tokenLock.address);
125137
// tokenSale's owner should be timelock
126138
expect(await tokenSale.owner()).to.be.eq(timelock.address);
127139

scripts/deploy/verify.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import {HardhatRuntimeEnvironment} from 'hardhat/types';
2+
3+
export async function verifyContract(hre: HardhatRuntimeEnvironment, contractAddress: string, ctorArgs: any[]) {
4+
await hre.run('verify:verify', {
5+
address: contractAddress,
6+
constructorArguments: ctorArgs,
7+
});
8+
}

0 commit comments

Comments
 (0)