commit
9e41dba391
@ -0,0 +1,11 @@ |
||||
node_modules |
||||
.env |
||||
coverage |
||||
coverage.json |
||||
typechain |
||||
typechain-types |
||||
|
||||
# Hardhat files |
||||
cache |
||||
artifacts |
||||
|
@ -0,0 +1,99 @@ |
||||
# Kaly Chain wKLC Token & Vesting Contract Deploy and Verify |
||||
|
||||
## How to configue `harhat.config.js` |
||||
|
||||
```bash |
||||
module.exports = { |
||||
solidity: { |
||||
compilers: [ |
||||
{ |
||||
version: "0.8.11", |
||||
settings: { |
||||
optimizer: { |
||||
enabled: true, |
||||
runs: 200, |
||||
}, |
||||
}, |
||||
} |
||||
], |
||||
}, |
||||
networks: { |
||||
kaly: { |
||||
url: "https://testnetrpc.kalychain.io/rpc", |
||||
accounts: ['put your private key here dont forget to remove before uploading to github'], |
||||
gas: 3000000, |
||||
gasPrice: 8000000000, |
||||
|
||||
} |
||||
}, |
||||
etherscan: { |
||||
apiKey: { |
||||
kaly: "abc" |
||||
}, |
||||
customChains: [ |
||||
{ |
||||
network: "kaly", |
||||
chainId: 3889, |
||||
allowUnlimitedContractSize: true, |
||||
gas: 3000000, |
||||
gasPrice: 8000000000, |
||||
urls: { |
||||
apiURL: "https://testnet.kalyscan.io/api", |
||||
browserURL: "https://testnet.kalyscan.io" |
||||
} |
||||
} |
||||
] |
||||
} |
||||
}; |
||||
``` |
||||
|
||||
## How to deploy wKLC token and Vesting contract |
||||
|
||||
### Deploy token contract |
||||
|
||||
```bash |
||||
npx hardhat run scripts/deploy_token.js --network kaly |
||||
``` |
||||
|
||||
### Deploy token vesting contract |
||||
|
||||
Before deploy, you have to update `scripts/deploy_vesting.js` as you can see below with the wKLC address. |
||||
|
||||
```bash |
||||
const TokenVesting = await ethers.getContractFactory("TokenVesting"); |
||||
const tokenVesting = await TokenVesting.deploy( |
||||
Token = "0x069255299Bb729399f3CECaBdc73d15d3D10a2A3" |
||||
); |
||||
console.log("TokenVesting address:", tokenVesting.address); |
||||
} |
||||
``` |
||||
|
||||
```bash |
||||
npx hardhat run scripts/deploy_vesting.js --network kaly |
||||
``` |
||||
|
||||
|
||||
Update `scripts/verify_vesting.js` with the Token Vesting address and wKLC address |
||||
|
||||
`verify_vesting.js` |
||||
```bash |
||||
await hre.run("verify:verify", { |
||||
address: Deployed Token Vesting contract address, |
||||
constructorArguments: [ |
||||
0x069255299Bb729399f3CECaBdc73d15d3D10a2A3 |
||||
] |
||||
}) |
||||
``` |
||||
|
||||
The final step is run below commands. |
||||
|
||||
```bash |
||||
npx hardhat run scripts/verify_token.js --network kaly |
||||
``` |
||||
|
||||
```bash |
||||
npx hardhat run scripts/verify_vesting.js --network kaly |
||||
``` |
||||
|
||||
|
||||
Finally, you will get fully verified wKLC Token and Vesting contracts. |
@ -0,0 +1,351 @@ |
||||
// contracts/TokenVesting.sol |
||||
// SPDX-License-Identifier: Apache-2.0 |
||||
pragma solidity 0.8.11; |
||||
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; |
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; |
||||
import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; |
||||
import "@openzeppelin/contracts/access/Ownable.sol"; |
||||
import "@openzeppelin/contracts/utils/math/Math.sol"; |
||||
import "@openzeppelin/contracts/utils/math/SafeMath.sol"; |
||||
|
||||
/** |
||||
* @title TokenVesting |
||||
*/ |
||||
contract TokenVesting is Ownable, ReentrancyGuard{ |
||||
using SafeMath for uint256; |
||||
using SafeERC20 for IERC20; |
||||
struct VestingSchedule{ |
||||
bool initialized; |
||||
// beneficiary of tokens after they are released |
||||
address beneficiary; |
||||
// cliff period in seconds |
||||
uint256 cliff; |
||||
// start time of the vesting period |
||||
uint256 start; |
||||
// duration of the vesting period in seconds |
||||
uint256 duration; |
||||
// duration of a slice period for the vesting in seconds |
||||
uint256 slicePeriodSeconds; |
||||
// whether or not the vesting is revocable |
||||
bool revocable; |
||||
// total amount of tokens to be released at the end of the vesting |
||||
uint256 amountTotal; |
||||
// amount of tokens released |
||||
uint256 released; |
||||
// whether or not the vesting has been revoked |
||||
bool revoked; |
||||
} |
||||
|
||||
// address of the ERC20 token |
||||
IERC20 immutable private _token; |
||||
|
||||
bytes32[] private vestingSchedulesIds; |
||||
mapping(bytes32 => VestingSchedule) private vestingSchedules; |
||||
uint256 private vestingSchedulesTotalAmount; |
||||
mapping(address => uint256) private holdersVestingCount; |
||||
|
||||
event Released(uint256 amount); |
||||
event Revoked(); |
||||
|
||||
/** |
||||
* @dev Reverts if no vesting schedule matches the passed identifier. |
||||
*/ |
||||
modifier onlyIfVestingScheduleExists(bytes32 vestingScheduleId) { |
||||
require(vestingSchedules[vestingScheduleId].initialized == true); |
||||
_; |
||||
} |
||||
|
||||
/** |
||||
* @dev Reverts if the vesting schedule does not exist or has been revoked. |
||||
*/ |
||||
modifier onlyIfVestingScheduleNotRevoked(bytes32 vestingScheduleId) { |
||||
require(vestingSchedules[vestingScheduleId].initialized == true); |
||||
require(vestingSchedules[vestingScheduleId].revoked == false); |
||||
_; |
||||
} |
||||
|
||||
/** |
||||
* @dev Creates a vesting contract. |
||||
* @param token_ address of the ERC20 token contract |
||||
*/ |
||||
constructor(address token_) { |
||||
require(token_ != address(0x0)); |
||||
_token = IERC20(token_); |
||||
} |
||||
|
||||
receive() external payable {} |
||||
|
||||
fallback() external payable {} |
||||
|
||||
/** |
||||
* @dev Returns the number of vesting schedules associated to a beneficiary. |
||||
* @return the number of vesting schedules |
||||
*/ |
||||
function getVestingSchedulesCountByBeneficiary(address _beneficiary) |
||||
external |
||||
view |
||||
returns(uint256){ |
||||
return holdersVestingCount[_beneficiary]; |
||||
} |
||||
|
||||
/** |
||||
* @dev Returns the vesting schedule id at the given index. |
||||
* @return the vesting id |
||||
*/ |
||||
function getVestingIdAtIndex(uint256 index) |
||||
external |
||||
view |
||||
returns(bytes32){ |
||||
require(index < getVestingSchedulesCount(), "TokenVesting: index out of bounds"); |
||||
return vestingSchedulesIds[index]; |
||||
} |
||||
|
||||
/** |
||||
* @notice Returns the vesting schedule information for a given holder and index. |
||||
* @return the vesting schedule structure information |
||||
*/ |
||||
function getVestingScheduleByAddressAndIndex(address holder, uint256 index) |
||||
external |
||||
view |
||||
returns(VestingSchedule memory){ |
||||
return getVestingSchedule(computeVestingScheduleIdForAddressAndIndex(holder, index)); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* @notice Returns the total amount of vesting schedules. |
||||
* @return the total amount of vesting schedules |
||||
*/ |
||||
function getVestingSchedulesTotalAmount() |
||||
external |
||||
view |
||||
returns(uint256){ |
||||
return vestingSchedulesTotalAmount; |
||||
} |
||||
|
||||
/** |
||||
* @dev Returns the address of the ERC20 token managed by the vesting contract. |
||||
*/ |
||||
function getToken() |
||||
external |
||||
view |
||||
returns(address){ |
||||
return address(_token); |
||||
} |
||||
|
||||
/** |
||||
* @notice Creates a new vesting schedule for a beneficiary. |
||||
* @param _beneficiary address of the beneficiary to whom vested tokens are transferred |
||||
* @param _start start time of the vesting period |
||||
* @param _cliff duration in seconds of the cliff in which tokens will begin to vest |
||||
* @param _duration duration in seconds of the period in which the tokens will vest |
||||
* @param _slicePeriodSeconds duration of a slice period for the vesting in seconds |
||||
* @param _revocable whether the vesting is revocable or not |
||||
* @param _amount total amount of tokens to be released at the end of the vesting |
||||
*/ |
||||
function createVestingSchedule( |
||||
address _beneficiary, |
||||
uint256 _start, |
||||
uint256 _cliff, |
||||
uint256 _duration, |
||||
uint256 _slicePeriodSeconds, |
||||
bool _revocable, |
||||
uint256 _amount |
||||
) |
||||
public |
||||
onlyOwner{ |
||||
require( |
||||
this.getWithdrawableAmount() >= _amount, |
||||
"TokenVesting: cannot create vesting schedule because not sufficient tokens" |
||||
); |
||||
require(_duration > 0, "TokenVesting: duration must be > 0"); |
||||
require(_amount > 0, "TokenVesting: amount must be > 0"); |
||||
require(_slicePeriodSeconds >= 1, "TokenVesting: slicePeriodSeconds must be >= 1"); |
||||
bytes32 vestingScheduleId = this.computeNextVestingScheduleIdForHolder(_beneficiary); |
||||
uint256 cliff = _start.add(_cliff); |
||||
vestingSchedules[vestingScheduleId] = VestingSchedule( |
||||
true, |
||||
_beneficiary, |
||||
cliff, |
||||
_start, |
||||
_duration, |
||||
_slicePeriodSeconds, |
||||
_revocable, |
||||
_amount, |
||||
0, |
||||
false |
||||
); |
||||
vestingSchedulesTotalAmount = vestingSchedulesTotalAmount.add(_amount); |
||||
vestingSchedulesIds.push(vestingScheduleId); |
||||
uint256 currentVestingCount = holdersVestingCount[_beneficiary]; |
||||
holdersVestingCount[_beneficiary] = currentVestingCount.add(1); |
||||
} |
||||
|
||||
/** |
||||
* @notice Revokes the vesting schedule for given identifier. |
||||
* @param vestingScheduleId the vesting schedule identifier |
||||
*/ |
||||
function revoke(bytes32 vestingScheduleId) |
||||
public |
||||
onlyOwner |
||||
onlyIfVestingScheduleNotRevoked(vestingScheduleId){ |
||||
VestingSchedule storage vestingSchedule = vestingSchedules[vestingScheduleId]; |
||||
require(vestingSchedule.revocable == true, "TokenVesting: vesting is not revocable"); |
||||
uint256 vestedAmount = _computeReleasableAmount(vestingSchedule); |
||||
if(vestedAmount > 0){ |
||||
release(vestingScheduleId, vestedAmount); |
||||
} |
||||
uint256 unreleased = vestingSchedule.amountTotal.sub(vestingSchedule.released); |
||||
vestingSchedulesTotalAmount = vestingSchedulesTotalAmount.sub(unreleased); |
||||
vestingSchedule.revoked = true; |
||||
} |
||||
|
||||
/** |
||||
* @notice Withdraw the specified amount if possible. |
||||
* @param amount the amount to withdraw |
||||
*/ |
||||
function withdraw(uint256 amount) |
||||
public |
||||
nonReentrant |
||||
onlyOwner{ |
||||
require(this.getWithdrawableAmount() >= amount, "TokenVesting: not enough withdrawable funds"); |
||||
_token.safeTransfer(owner(), amount); |
||||
} |
||||
|
||||
/** |
||||
* @notice Release vested amount of tokens. |
||||
* @param vestingScheduleId the vesting schedule identifier |
||||
* @param amount the amount to release |
||||
*/ |
||||
function release( |
||||
bytes32 vestingScheduleId, |
||||
uint256 amount |
||||
) |
||||
public |
||||
nonReentrant |
||||
onlyIfVestingScheduleNotRevoked(vestingScheduleId){ |
||||
VestingSchedule storage vestingSchedule = vestingSchedules[vestingScheduleId]; |
||||
bool isBeneficiary = msg.sender == vestingSchedule.beneficiary; |
||||
bool isOwner = msg.sender == owner(); |
||||
require( |
||||
isBeneficiary || isOwner, |
||||
"TokenVesting: only beneficiary and owner can release vested tokens" |
||||
); |
||||
uint256 vestedAmount = _computeReleasableAmount(vestingSchedule); |
||||
require(vestedAmount >= amount, "TokenVesting: cannot release tokens, not enough vested tokens"); |
||||
vestingSchedule.released = vestingSchedule.released.add(amount); |
||||
address payable beneficiaryPayable = payable(vestingSchedule.beneficiary); |
||||
vestingSchedulesTotalAmount = vestingSchedulesTotalAmount.sub(amount); |
||||
_token.safeTransfer(beneficiaryPayable, amount); |
||||
} |
||||
|
||||
/** |
||||
* @dev Returns the number of vesting schedules managed by this contract. |
||||
* @return the number of vesting schedules |
||||
*/ |
||||
function getVestingSchedulesCount() |
||||
public |
||||
view |
||||
returns(uint256){ |
||||
return vestingSchedulesIds.length; |
||||
} |
||||
|
||||
/** |
||||
* @notice Computes the vested amount of tokens for the given vesting schedule identifier. |
||||
* @return the vested amount |
||||
*/ |
||||
function computeReleasableAmount(bytes32 vestingScheduleId) |
||||
public |
||||
onlyIfVestingScheduleNotRevoked(vestingScheduleId) |
||||
view |
||||
returns(uint256){ |
||||
VestingSchedule storage vestingSchedule = vestingSchedules[vestingScheduleId]; |
||||
return _computeReleasableAmount(vestingSchedule); |
||||
} |
||||
|
||||
/** |
||||
* @notice Returns the vesting schedule information for a given identifier. |
||||
* @return the vesting schedule structure information |
||||
*/ |
||||
function getVestingSchedule(bytes32 vestingScheduleId) |
||||
public |
||||
view |
||||
returns(VestingSchedule memory){ |
||||
return vestingSchedules[vestingScheduleId]; |
||||
} |
||||
|
||||
/** |
||||
* @dev Returns the amount of tokens that can be withdrawn by the owner. |
||||
* @return the amount of tokens |
||||
*/ |
||||
function getWithdrawableAmount() |
||||
public |
||||
view |
||||
returns(uint256){ |
||||
return _token.balanceOf(address(this)).sub(vestingSchedulesTotalAmount); |
||||
} |
||||
|
||||
/** |
||||
* @dev Computes the next vesting schedule identifier for a given holder address. |
||||
*/ |
||||
function computeNextVestingScheduleIdForHolder(address holder) |
||||
public |
||||
view |
||||
returns(bytes32){ |
||||
return computeVestingScheduleIdForAddressAndIndex(holder, holdersVestingCount[holder]); |
||||
} |
||||
|
||||
/** |
||||
* @dev Returns the last vesting schedule for a given holder address. |
||||
*/ |
||||
function getLastVestingScheduleForHolder(address holder) |
||||
public |
||||
view |
||||
returns(VestingSchedule memory){ |
||||
return vestingSchedules[computeVestingScheduleIdForAddressAndIndex(holder, holdersVestingCount[holder] - 1)]; |
||||
} |
||||
|
||||
/** |
||||
* @dev Computes the vesting schedule identifier for an address and an index. |
||||
*/ |
||||
function computeVestingScheduleIdForAddressAndIndex(address holder, uint256 index) |
||||
public |
||||
pure |
||||
returns(bytes32){ |
||||
return keccak256(abi.encodePacked(holder, index)); |
||||
} |
||||
|
||||
/** |
||||
* @dev Computes the releasable amount of tokens for a vesting schedule. |
||||
* @return the amount of releasable tokens |
||||
*/ |
||||
function _computeReleasableAmount(VestingSchedule memory vestingSchedule) |
||||
internal |
||||
view |
||||
returns(uint256){ |
||||
uint256 currentTime = getCurrentTime(); |
||||
if ((currentTime < vestingSchedule.cliff) || vestingSchedule.revoked == true) { |
||||
return 0; |
||||
} else if (currentTime >= vestingSchedule.start.add(vestingSchedule.duration)) { |
||||
return vestingSchedule.amountTotal.sub(vestingSchedule.released); |
||||
} else { |
||||
uint256 timeFromStart = currentTime.sub(vestingSchedule.start); |
||||
uint secondsPerSlice = vestingSchedule.slicePeriodSeconds; |
||||
uint256 vestedSlicePeriods = timeFromStart.div(secondsPerSlice); |
||||
uint256 vestedSeconds = vestedSlicePeriods.mul(secondsPerSlice); |
||||
uint256 vestedAmount = vestingSchedule.amountTotal.mul(vestedSeconds).div(vestingSchedule.duration); |
||||
vestedAmount = vestedAmount.sub(vestingSchedule.released); |
||||
return vestedAmount; |
||||
} |
||||
} |
||||
|
||||
function getCurrentTime() |
||||
internal |
||||
virtual |
||||
view |
||||
returns(uint256){ |
||||
return block.timestamp; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,61 @@ |
||||
// SPDX-License-Identifier: MIT |
||||
pragma solidity ^0.8.0; |
||||
|
||||
contract WKLC { |
||||
string public name = "Wrapped Kaly Coin"; |
||||
string public symbol = "WKLC"; |
||||
uint8 public decimals = 18; |
||||
mapping (address => uint256) public balanceOf; |
||||
mapping (address => mapping (address => uint256)) public allowance; |
||||
|
||||
event Approval(address indexed src, address indexed guy, uint256 wad); |
||||
event Transfer(address indexed src, address indexed dst, uint256 wad); |
||||
event Deposit(address indexed dst, uint256 wad); |
||||
event Withdrawal(address indexed src, uint256 wad); |
||||
|
||||
receive() external payable { |
||||
deposit(); |
||||
} |
||||
|
||||
function deposit() public payable { |
||||
balanceOf[msg.sender] += msg.value; |
||||
emit Deposit(msg.sender, msg.value); |
||||
} |
||||
|
||||
function withdraw(uint256 wad) public { |
||||
require(balanceOf[msg.sender] >= wad); |
||||
balanceOf[msg.sender] -= wad; |
||||
payable(msg.sender).transfer(wad); |
||||
emit Withdrawal(msg.sender, wad); |
||||
} |
||||
|
||||
function totalSupply() public view returns (uint256) { |
||||
return address(this).balance; |
||||
} |
||||
|
||||
function approve(address guy, uint256 wad) public returns (bool) { |
||||
allowance[msg.sender][guy] = wad; |
||||
emit Approval(msg.sender, guy, wad); |
||||
return true; |
||||
} |
||||
|
||||
function transfer(address dst, uint256 wad) public returns (bool) { |
||||
return transferFrom(msg.sender, dst, wad); |
||||
} |
||||
|
||||
function transferFrom(address src, address dst, uint256 wad) public returns (bool) { |
||||
require(balanceOf[src] >= wad); |
||||
|
||||
if (src != msg.sender && allowance[src][msg.sender] != type(uint256).max) { |
||||
require(allowance[src][msg.sender] >= wad); |
||||
allowance[src][msg.sender] -= wad; |
||||
} |
||||
|
||||
balanceOf[src] -= wad; |
||||
balanceOf[dst] += wad; |
||||
|
||||
emit Transfer(src, dst, wad); |
||||
|
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,61 @@ |
||||
require("@nomicfoundation/hardhat-toolbox"); |
||||
require("dotenv").config(); |
||||
|
||||
// This is a sample Hardhat task. To learn how to create your own go to
|
||||
// https://hardhat.org/guides/create-task.html
|
||||
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => { |
||||
const accounts = await hre.ethers.getSigners(); |
||||
|
||||
for (const account of accounts) { |
||||
console.log(account.address); |
||||
} |
||||
}); |
||||
|
||||
// You need to export an object to set up your config
|
||||
// Go to https://hardhat.org/config/ to learn more
|
||||
|
||||
/** |
||||
* @type import('hardhat/config').HardhatUserConfig |
||||
*/ |
||||
module.exports = { |
||||
solidity: { |
||||
compilers: [ |
||||
{ |
||||
version: "0.8.11", |
||||
settings: { |
||||
optimizer: { |
||||
enabled: true, |
||||
runs: 200, |
||||
}, |
||||
}, |
||||
} |
||||
], |
||||
}, |
||||
networks: { |
||||
kaly: { |
||||
url: "https://testnetrpc.kalychain.io/rpc", |
||||
accounts: [''], |
||||
gas: 3000000, |
||||
gasPrice: 8000000000, |
||||
|
||||
} |
||||
}, |
||||
etherscan: { |
||||
apiKey: { |
||||
kaly: "abc" |
||||
}, |
||||
customChains: [ |
||||
{ |
||||
network: "kaly", |
||||
chainId: 3889, |
||||
allowUnlimitedContractSize: true, |
||||
gas: 3000000, |
||||
gasPrice: 8000000000, |
||||
urls: { |
||||
apiURL: "https://testnet.kalyscan.io/api", |
||||
browserURL: "https://testnet.kalyscan.io" |
||||
} |
||||
} |
||||
] |
||||
} |
||||
}; |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,25 @@ |
||||
{ |
||||
"name": "vesting", |
||||
"version": "1.0.0", |
||||
"description": "", |
||||
"main": "index.js", |
||||
"scripts": { |
||||
"test": "echo \"Error: no test specified\" && exit 1" |
||||
}, |
||||
"keywords": [], |
||||
"author": "", |
||||
"license": "ISC", |
||||
"devDependencies": { |
||||
"@nomicfoundation/hardhat-chai-matchers": "^1.0.5", |
||||
"@nomicfoundation/hardhat-toolbox": "^2.0.0", |
||||
"@nomiclabs/hardhat-ethers": "^2.2.1", |
||||
"chai": "^4.3.7", |
||||
"ethers": "^5.7.2", |
||||
"hardhat": "^2.12.3" |
||||
}, |
||||
"dependencies": { |
||||
"@openzeppelin/contracts": "^4.8.0", |
||||
"@unirep/contracts": "^1.0.1", |
||||
"dotenv": "^16.0.3" |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
const main = async () => { |
||||
const [deployer] = await hre.ethers.getSigners(); |
||||
const accountBalance = await deployer.getBalance(); |
||||
|
||||
console.log("Deploying contracts with account: ", deployer.address); |
||||
console.log("Account balance: ", accountBalance.toString()); |
||||
|
||||
const contractFactory = await hre.ethers.getContractFactory("WKLC"); |
||||
const contract = await contractFactory.deploy(); |
||||
await contract.deployed(); |
||||
|
||||
console.log("WKLC address: ", contract.address); |
||||
}; |
||||
|
||||
const runMain = async () => { |
||||
try { |
||||
await main(); |
||||
process.exit(0); |
||||
} catch (error) { |
||||
console.log(error); |
||||
process.exit(1); |
||||
} |
||||
}; |
||||
|
||||
runMain(); |
@ -0,0 +1,20 @@ |
||||
async function main() { |
||||
const [deployer] = await ethers.getSigners(); |
||||
|
||||
console.log("Deploying contracts with the account:", deployer.address); |
||||
|
||||
console.log("Account balance:", (await deployer.getBalance()).toString()); |
||||
|
||||
const TokenVesting = await ethers.getContractFactory("TokenVesting"); |
||||
const tokenVesting = await TokenVesting.deploy( |
||||
Token = "0x069255299Bb729399f3CECaBdc73d15d3D10a2A3" |
||||
); |
||||
console.log("TokenVesting address:", tokenVesting.address); |
||||
} |
||||
|
||||
main() |
||||
.then(() => process.exit(0)) |
||||
.catch((error) => { |
||||
console.error(error); |
||||
process.exit(1); |
||||
}); |
@ -0,0 +1,17 @@ |
||||
const main = async () => { |
||||
await hre.run("verify:verify", { |
||||
address: "0xdaDbc4d96E5b418562d85DdAccBE970d0aca4803" |
||||
}) |
||||
}; |
||||
|
||||
const runMain = async () => { |
||||
try { |
||||
await main(); |
||||
process.exit(0); |
||||
} catch (error) { |
||||
console.log(error); |
||||
process.exit(1); |
||||
} |
||||
}; |
||||
|
||||
runMain(); |
@ -0,0 +1,20 @@ |
||||
const main = async () => { |
||||
await hre.run("verify:verify", { |
||||
address: "0x43D5576CF364eAc467Da4644C123C81A34DA1034", |
||||
constructorArguments: [ |
||||
"0x069255299Bb729399f3CECaBdc73d15d3D10a2A3" |
||||
] |
||||
}) |
||||
}; |
||||
|
||||
const runMain = async () => { |
||||
try { |
||||
await main(); |
||||
process.exit(0); |
||||
} catch (error) { |
||||
console.log(error); |
||||
process.exit(1); |
||||
} |
||||
}; |
||||
|
||||
runMain(); |
Loading…
Reference in new issue