增加一个用于claim usdt的合约
This commit is contained in:
parent
89efe5253f
commit
f8e7069439
@ -38317,7 +38317,7 @@
|
||||
}
|
||||
},
|
||||
"schemaVersion": "3.4.16",
|
||||
"updatedAt": "2024-01-10T06:03:43.853Z",
|
||||
"updatedAt": "2024-01-12T05:44:22.513Z",
|
||||
"networkType": "ethereum",
|
||||
"devdoc": {
|
||||
"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",
|
||||
"updatedAt": "2023-12-27T06:11:16.457Z",
|
||||
"updatedAt": "2024-01-12T05:44:22.582Z",
|
||||
"networkType": "ethereum",
|
||||
"devdoc": {
|
||||
"kind": "dev",
|
||||
|
@ -3259,7 +3259,7 @@
|
||||
}
|
||||
},
|
||||
"schemaVersion": "3.4.16",
|
||||
"updatedAt": "2024-01-10T06:03:43.872Z",
|
||||
"updatedAt": "2024-01-12T05:44:22.587Z",
|
||||
"networkType": "ethereum",
|
||||
"devdoc": {
|
||||
"kind": "dev",
|
||||
|
@ -33015,7 +33015,7 @@
|
||||
}
|
||||
},
|
||||
"schemaVersion": "3.4.16",
|
||||
"updatedAt": "2024-01-10T06:03:43.865Z",
|
||||
"updatedAt": "2024-01-12T05:44:22.527Z",
|
||||
"networkType": "ethereum",
|
||||
"devdoc": {
|
||||
"kind": "dev",
|
||||
|
@ -9715,7 +9715,7 @@
|
||||
}
|
||||
},
|
||||
"schemaVersion": "3.4.16",
|
||||
"updatedAt": "2024-01-10T06:03:43.845Z",
|
||||
"updatedAt": "2024-01-12T05:44:22.504Z",
|
||||
"networkType": "ethereum",
|
||||
"devdoc": {
|
||||
"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",
|
||||
"json": "assets/contracts/NftBuner.json",
|
||||
"address": "0xca5525178b0826A7C0835F0b7a383C802e10b6c7"
|
||||
},
|
||||
{
|
||||
"name": "ClaimToken",
|
||||
"type": "logic",
|
||||
"json": "assets/contracts/ClaimToken.json",
|
||||
"address": "0x2119A65A2cEE90B4E0184DBC4A7aDF7093730919"
|
||||
}
|
||||
]
|
@ -17,30 +17,6 @@
|
||||
"json": "assets/contracts/NftDistributor.json",
|
||||
"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",
|
||||
"type": "erc721",
|
||||
@ -136,5 +112,35 @@
|
||||
"type": "logic",
|
||||
"json": "assets/contracts/GoldBricksFactory.json",
|
||||
"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