增加一个用于claim usdt的合约
This commit is contained in:
parent
89efe5253f
commit
f8e7069439
@ -38317,7 +38317,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schemaVersion": "3.4.16",
|
"schemaVersion": "3.4.16",
|
||||||
"updatedAt": "2024-01-10T06:03:43.853Z",
|
"updatedAt": "2024-01-12T05:44:22.513Z",
|
||||||
"networkType": "ethereum",
|
"networkType": "ethereum",
|
||||||
"devdoc": {
|
"devdoc": {
|
||||||
"kind": "dev",
|
"kind": "dev",
|
||||||
|
19085
build/contracts/ClaimToken.json
Normal file
19085
build/contracts/ClaimToken.json
Normal file
File diff suppressed because one or more lines are too long
@ -17022,7 +17022,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schemaVersion": "3.4.16",
|
"schemaVersion": "3.4.16",
|
||||||
"updatedAt": "2023-12-27T06:11:16.457Z",
|
"updatedAt": "2024-01-12T05:44:22.582Z",
|
||||||
"networkType": "ethereum",
|
"networkType": "ethereum",
|
||||||
"devdoc": {
|
"devdoc": {
|
||||||
"kind": "dev",
|
"kind": "dev",
|
||||||
|
@ -3259,7 +3259,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schemaVersion": "3.4.16",
|
"schemaVersion": "3.4.16",
|
||||||
"updatedAt": "2024-01-10T06:03:43.872Z",
|
"updatedAt": "2024-01-12T05:44:22.587Z",
|
||||||
"networkType": "ethereum",
|
"networkType": "ethereum",
|
||||||
"devdoc": {
|
"devdoc": {
|
||||||
"kind": "dev",
|
"kind": "dev",
|
||||||
|
@ -33015,7 +33015,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schemaVersion": "3.4.16",
|
"schemaVersion": "3.4.16",
|
||||||
"updatedAt": "2024-01-10T06:03:43.865Z",
|
"updatedAt": "2024-01-12T05:44:22.527Z",
|
||||||
"networkType": "ethereum",
|
"networkType": "ethereum",
|
||||||
"devdoc": {
|
"devdoc": {
|
||||||
"kind": "dev",
|
"kind": "dev",
|
||||||
|
@ -9715,7 +9715,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schemaVersion": "3.4.16",
|
"schemaVersion": "3.4.16",
|
||||||
"updatedAt": "2024-01-10T06:03:43.845Z",
|
"updatedAt": "2024-01-12T05:44:22.504Z",
|
||||||
"networkType": "ethereum",
|
"networkType": "ethereum",
|
||||||
"devdoc": {
|
"devdoc": {
|
||||||
"kind": "dev",
|
"kind": "dev",
|
||||||
|
120
contracts/activity/ClaimToken.sol
Normal file
120
contracts/activity/ClaimToken.sol
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity 0.8.10;
|
||||||
|
|
||||||
|
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||||
|
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||||
|
import "../core/HasSignature.sol";
|
||||||
|
import "../utils/TimeChecker.sol";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title ClaimToken
|
||||||
|
* @dev for user to claim token
|
||||||
|
*/
|
||||||
|
contract ClaimToken is HasSignature, TimeChecker {
|
||||||
|
using SafeERC20 for IERC20;
|
||||||
|
uint256 private immutable _CACHED_CHAIN_ID;
|
||||||
|
address private immutable _CACHED_THIS;
|
||||||
|
address private verifier;
|
||||||
|
address private paymentAddress;
|
||||||
|
mapping(address => bool) public tokenSupported;
|
||||||
|
mapping(address => uint256) public claimHistory;
|
||||||
|
struct TestStuct {
|
||||||
|
address user;
|
||||||
|
address nft;
|
||||||
|
uint256 tokenId;
|
||||||
|
uint64 start;
|
||||||
|
uint64 stakeTime;
|
||||||
|
}
|
||||||
|
event TestEvent (
|
||||||
|
address indexed user,
|
||||||
|
TestStuct info
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
event TokenClaimed(
|
||||||
|
address indexed tokenAddress,
|
||||||
|
address indexed to,
|
||||||
|
uint256 indexed nonce,
|
||||||
|
uint256 amount
|
||||||
|
);
|
||||||
|
event TokenSupportUpdated(address indexed tokenAddress, bool support);
|
||||||
|
event VerifierUpdated(address indexed verifier);
|
||||||
|
event PaymentAddressUpdated(address indexed paymentAddress);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
_CACHED_CHAIN_ID = block.chainid;
|
||||||
|
_CACHED_THIS = address(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTokenSupport(address _token, bool _support) external onlyOwner {
|
||||||
|
tokenSupported[_token] = _support;
|
||||||
|
emit TokenSupportUpdated(_token, _support);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev update verifier address
|
||||||
|
*/
|
||||||
|
function updateVerifier(address _verifier) external onlyOwner {
|
||||||
|
require(_verifier != address(0), "ClaimToken: address can not be zero");
|
||||||
|
verifier = _verifier;
|
||||||
|
emit VerifierUpdated(_verifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev update payment address
|
||||||
|
*/
|
||||||
|
function updatePaymentAddress(address _paymentAddress) external onlyOwner {
|
||||||
|
require(
|
||||||
|
_paymentAddress != address(0),
|
||||||
|
"ClaimToken: payment address can not be zero"
|
||||||
|
);
|
||||||
|
paymentAddress = _paymentAddress;
|
||||||
|
emit PaymentAddressUpdated(_paymentAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
function claim(
|
||||||
|
address _token,
|
||||||
|
uint256 _amount,
|
||||||
|
uint256 _startTime,
|
||||||
|
uint256 _saltNonce,
|
||||||
|
bytes calldata _signature
|
||||||
|
) external signatureValid(_signature) timeValid(_startTime) {
|
||||||
|
require(tokenSupported[_token], "ClaimToken: unsupported token");
|
||||||
|
address to = _msgSender();
|
||||||
|
bytes32 criteriaMessageHash = getMessageHash(
|
||||||
|
to,
|
||||||
|
_token,
|
||||||
|
_CACHED_THIS,
|
||||||
|
_CACHED_CHAIN_ID,
|
||||||
|
_amount,
|
||||||
|
_startTime,
|
||||||
|
_saltNonce
|
||||||
|
);
|
||||||
|
checkSigner(verifier, criteriaMessageHash, _signature);
|
||||||
|
IERC20(_token).safeTransferFrom(paymentAddress, to, _amount);
|
||||||
|
claimHistory[to] = _amount;
|
||||||
|
_useSignature(_signature);
|
||||||
|
emit TokenClaimed(_token, to, _saltNonce, _amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMessageHash(
|
||||||
|
address _to,
|
||||||
|
address _address,
|
||||||
|
address _contract,
|
||||||
|
uint256 _chainId,
|
||||||
|
uint256 _amount,
|
||||||
|
uint256 _startTime,
|
||||||
|
uint256 _saltNonce
|
||||||
|
) public pure returns (bytes32) {
|
||||||
|
bytes memory encoded = abi.encodePacked(
|
||||||
|
_to,
|
||||||
|
_address,
|
||||||
|
_contract,
|
||||||
|
_chainId,
|
||||||
|
_amount,
|
||||||
|
_startTime,
|
||||||
|
_saltNonce
|
||||||
|
);
|
||||||
|
return keccak256(encoded);
|
||||||
|
}
|
||||||
|
}
|
61
migrations/14_deploy_activity_202401.js
Normal file
61
migrations/14_deploy_activity_202401.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
const base = require("../scripts/base");
|
||||||
|
const NftBuner = artifacts.require("logic/NftBuner");
|
||||||
|
const Badge = artifacts.require("tokens/erc721/BEBadge");
|
||||||
|
const NFTSbt = artifacts.require("tokens/erc721/NFTSbt");
|
||||||
|
const ClaimToken = artifacts.require("activity/ClaimToken");
|
||||||
|
const FT = artifacts.require("tokens/erc20/FT");
|
||||||
|
|
||||||
|
module.exports = async function (deployer, network, accounts) {
|
||||||
|
const config = require(`../config/config_${network}`);
|
||||||
|
let cfgs = base.loadData({ network });
|
||||||
|
// await deployer.deploy(NftBuner);
|
||||||
|
// const bunerInstance = await NftBuner.deployed();
|
||||||
|
// if (bunerInstance) {
|
||||||
|
// console.log("NftBuner successfully deployed.");
|
||||||
|
// console.log("address: " + bunerInstance.address);
|
||||||
|
// }
|
||||||
|
// base.updateArray({
|
||||||
|
// name: "NftBuner",
|
||||||
|
// type: "logic",
|
||||||
|
// json: "assets/contracts/NftBuner.json",
|
||||||
|
// address: bunerInstance.address,
|
||||||
|
// network,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const gacha = cfgs.find((c) => c.name === "Gacha").address
|
||||||
|
// const gachaInstance = await Badge.at(gacha);
|
||||||
|
// await gachaInstance.setBurnRole(bunerInstance.address);
|
||||||
|
// console.log("gacha setBurnRole successfully deployed.");
|
||||||
|
|
||||||
|
// const candy = cfgs.find((c) => c.name === "Candy").address
|
||||||
|
// const candyInstance = await Badge.at(candy);
|
||||||
|
// await candyInstance.setBurnRole(bunerInstance.address);
|
||||||
|
// console.log("candy setBurnRole successfully deployed.");
|
||||||
|
// const explorer = cfgs.find((c) => c.name === "Explorer").address
|
||||||
|
// const explorerInstance = await NFTSbt.at(explorer);
|
||||||
|
// await explorerInstance.setBurnRole(bunerInstance.address);
|
||||||
|
// console.log("explorer setBurnRole successfully deployed.");
|
||||||
|
|
||||||
|
await deployer.deploy(ClaimToken);
|
||||||
|
const claimInstance = await ClaimToken.deployed();
|
||||||
|
if (claimInstance) {
|
||||||
|
console.log("ClaimToken successfully deployed.");
|
||||||
|
console.log("address: " + claimInstance.address);
|
||||||
|
}
|
||||||
|
base.updateArray({
|
||||||
|
name: "ClaimToken",
|
||||||
|
type: "logic",
|
||||||
|
json: "assets/contracts/ClaimToken.json",
|
||||||
|
address: claimInstance.address,
|
||||||
|
network,
|
||||||
|
});
|
||||||
|
|
||||||
|
const usdt = cfgs.find((c) => c.name === "BEUSDT").address
|
||||||
|
const usdtInstance = await FT.at(usdt);
|
||||||
|
await claimInstance.updateTokenSupport(usdtInstance.address, true);
|
||||||
|
console.log("updateTokenSupport successfully deployed.");
|
||||||
|
await claimInstance.updateVerifier(config.admins.admin);
|
||||||
|
console.log("updateVerifier successfully deployed.");
|
||||||
|
await claimInstance.updatePaymentAddress(config.admins.admin);
|
||||||
|
console.log("updatePaymentAddress successfully deployed.");
|
||||||
|
};
|
@ -1,34 +0,0 @@
|
|||||||
const base = require("../scripts/base");
|
|
||||||
const NftBuner = artifacts.require("logic/NftBuner");
|
|
||||||
const Badge = artifacts.require("tokens/erc721/BEBadge");
|
|
||||||
const NFTSbt = artifacts.require("tokens/erc721/NFTSbt");
|
|
||||||
|
|
||||||
module.exports = async function (deployer, network, accounts) {
|
|
||||||
await deployer.deploy(NftBuner);
|
|
||||||
const bunerInstance = await NftBuner.deployed();
|
|
||||||
if (bunerInstance) {
|
|
||||||
console.log("NftBuner successfully deployed.");
|
|
||||||
console.log("address: " + bunerInstance.address);
|
|
||||||
}
|
|
||||||
base.updateArray({
|
|
||||||
name: "NftBuner",
|
|
||||||
type: "logic",
|
|
||||||
json: "assets/contracts/NftBuner.json",
|
|
||||||
address: bunerInstance.address,
|
|
||||||
network,
|
|
||||||
});
|
|
||||||
let cfgs = base.loadData({ network });
|
|
||||||
const gacha = cfgs.find((c) => c.name === "Gacha").address
|
|
||||||
const gachaInstance = await Badge.at(gacha);
|
|
||||||
await gachaInstance.setBurnRole(bunerInstance.address);
|
|
||||||
console.log("gacha setBurnRole successfully deployed.");
|
|
||||||
|
|
||||||
const candy = cfgs.find((c) => c.name === "Candy").address
|
|
||||||
const candyInstance = await Badge.at(candy);
|
|
||||||
await candyInstance.setBurnRole(bunerInstance.address);
|
|
||||||
console.log("candy setBurnRole successfully deployed.");
|
|
||||||
const explorer = cfgs.find((c) => c.name === "Explorer").address
|
|
||||||
const explorerInstance = await NFTSbt.at(explorer);
|
|
||||||
await explorerInstance.setBurnRole(bunerInstance.address);
|
|
||||||
console.log("explorer setBurnRole successfully deployed.");
|
|
||||||
};
|
|
@ -154,5 +154,11 @@
|
|||||||
"type": "logic",
|
"type": "logic",
|
||||||
"json": "assets/contracts/NftBuner.json",
|
"json": "assets/contracts/NftBuner.json",
|
||||||
"address": "0xca5525178b0826A7C0835F0b7a383C802e10b6c7"
|
"address": "0xca5525178b0826A7C0835F0b7a383C802e10b6c7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ClaimToken",
|
||||||
|
"type": "logic",
|
||||||
|
"json": "assets/contracts/ClaimToken.json",
|
||||||
|
"address": "0x2119A65A2cEE90B4E0184DBC4A7aDF7093730919"
|
||||||
}
|
}
|
||||||
]
|
]
|
@ -17,30 +17,6 @@
|
|||||||
"json": "assets/contracts/NftDistributor.json",
|
"json": "assets/contracts/NftDistributor.json",
|
||||||
"address": "0xf520767FDBE4443F89F37714EE1BeEC0BDF05B79"
|
"address": "0xf520767FDBE4443F89F37714EE1BeEC0BDF05B79"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "CEC",
|
|
||||||
"type": "erc20",
|
|
||||||
"json": "assets/contracts/FT.json",
|
|
||||||
"address": "0x012A2C3C6f7F198A52E2820aEB48208d453EEa17"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "CEG",
|
|
||||||
"type": "erc20",
|
|
||||||
"json": "assets/contracts/FT.json",
|
|
||||||
"address": "0x931985167bD678bA850156fc717443c34C856424"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "BEUSDC",
|
|
||||||
"type": "erc20",
|
|
||||||
"json": "assets/contracts/FT.json",
|
|
||||||
"address": "0x4a931bfa7331009b0973c615b6D0B4FCCd5A89bb"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "BEUSDT",
|
|
||||||
"type": "erc20",
|
|
||||||
"json": "assets/contracts/FT.json",
|
|
||||||
"address": "0xb48c8Fa8Bc892f2F48A5Ea3C5dD3335aFECB9b0c"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "HERO",
|
"name": "HERO",
|
||||||
"type": "erc721",
|
"type": "erc721",
|
||||||
@ -136,5 +112,35 @@
|
|||||||
"type": "logic",
|
"type": "logic",
|
||||||
"json": "assets/contracts/GoldBricksFactory.json",
|
"json": "assets/contracts/GoldBricksFactory.json",
|
||||||
"address": "0x6F6BfF298e182882091B8D0FF40208d09aE96B62"
|
"address": "0x6F6BfF298e182882091B8D0FF40208d09aE96B62"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Explorer",
|
||||||
|
"type": "erc721",
|
||||||
|
"json": "assets/contracts/NFTSbt.json",
|
||||||
|
"address": "0x2D8BE6BF0baA74e0A907016679CaE9190e80dD0A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CEC",
|
||||||
|
"type": "erc20",
|
||||||
|
"json": "assets/contracts/FT.json",
|
||||||
|
"address": "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CEG",
|
||||||
|
"type": "erc20",
|
||||||
|
"json": "assets/contracts/FT.json",
|
||||||
|
"address": "0xD833215cBcc3f914bD1C9ece3EE7BF8B14f841bb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "BEUSDC",
|
||||||
|
"type": "erc20",
|
||||||
|
"json": "assets/contracts/FT.json",
|
||||||
|
"address": "0x9561C133DD8580860B6b7E504bC5Aa500f0f06a7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "BEUSDT",
|
||||||
|
"type": "erc20",
|
||||||
|
"json": "assets/contracts/FT.json",
|
||||||
|
"address": "0xe982E462b094850F12AF94d21D470e21bE9D0E9C"
|
||||||
}
|
}
|
||||||
]
|
]
|
59
test/claimtoken.test.js
Normal file
59
test/claimtoken.test.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
const ClaimToken = artifacts.require("ClaimToken");
|
||||||
|
const FT = artifacts.require("FT");
|
||||||
|
const {
|
||||||
|
BN,
|
||||||
|
constants,
|
||||||
|
expectEvent,
|
||||||
|
expectRevert,
|
||||||
|
} = require("@openzeppelin/test-helpers");
|
||||||
|
|
||||||
|
|
||||||
|
contract("ClaimToken", (accounts) => {
|
||||||
|
let tokenClaimer;
|
||||||
|
let usdt;
|
||||||
|
const owner = accounts[0];
|
||||||
|
const user = accounts[1];
|
||||||
|
const executor = accounts[2];
|
||||||
|
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
usdt = await FT.new("USDT", "USDT", 0);
|
||||||
|
tokenClaimer = await ClaimToken.new();
|
||||||
|
await tokenClaimer.updateTokenSupport(usdt.address, true);
|
||||||
|
await tokenClaimer.updateVerifier(executor);
|
||||||
|
await tokenClaimer.updatePaymentAddress(owner);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should cliam token", async () => {
|
||||||
|
await usdt.mint(owner, web3.utils.toWei("1000"));
|
||||||
|
await usdt.approve(tokenClaimer.address, web3.utils.toWei("1000"), { from: owner });
|
||||||
|
const balanceOfOwner = await usdt.balanceOf(owner);
|
||||||
|
console.log('balanceOfOwner: ', balanceOfOwner.toString())
|
||||||
|
const allowance = await usdt.allowance(owner, tokenClaimer.address);
|
||||||
|
console.log('allowance: ', allowance.toString())
|
||||||
|
const token = usdt.address;
|
||||||
|
const amount = web3.utils.toWei("100");
|
||||||
|
console.log(amount)
|
||||||
|
const chainId = await web3.eth.getChainId();
|
||||||
|
console.log(chainId)
|
||||||
|
const address = tokenClaimer.address;
|
||||||
|
const startTime = Date.now() / 1000 | 0;
|
||||||
|
const saltNonce = (Math.random() * 1000) | 0;
|
||||||
|
let signStr = web3.utils.soliditySha3.apply(this,
|
||||||
|
[user, token, address, chainId, amount, startTime, saltNonce]);
|
||||||
|
let signature = await web3.eth.sign(signStr, executor);
|
||||||
|
signature = signature.replace(/00$/, "1b").replace(/01$/, "1c");
|
||||||
|
|
||||||
|
const receipt = await tokenClaimer.claim(
|
||||||
|
token,
|
||||||
|
amount,
|
||||||
|
startTime,
|
||||||
|
saltNonce,
|
||||||
|
signature,
|
||||||
|
{ from: user }
|
||||||
|
);
|
||||||
|
|
||||||
|
const balanceOfUser = await usdt.balanceOf(user);
|
||||||
|
assert.equal(balanceOfUser, amount, "Incorrect user balance");
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user