Skip to content

Instantly share code, notes, and snippets.

@CQBinh
Last active April 27, 2022 04:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CQBinh/591340fb410f66f7a14284b550d3e4b1 to your computer and use it in GitHub Desktop.
Save CQBinh/591340fb410f66f7a14284b550d3e4b1 to your computer and use it in GitHub Desktop.
Airdrop contract distributor using ECDSA signature
import signatureGenerator from './signatureGenerator'
import BN from 'bn.js'
const address = '0x0737BEf0f49abCf4A62d480A4fFcE1681f90daEE'
const { signature } = await signatureGenerator.getSignatureAirdrop(address, new BN('100'))
console.log('signature', signature)
import Web3 from 'web3'
import theAirdropABI from '../cross-env/abis/theAirdrop'
const web3Provider = new Web3.providers.HttpProvider('https://bsc-dataseed1.binance.org:443')
const web3 = new Web3(web3Provider)
const adminKey = 0x...
const airdropAddress = '0x...'
const airdropContract = new web3.eth.Contract(theAirdropABI, airdropAddress)
function signMessageAirdrop(message) {
const params = [
{ name: 'user', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'amount', type: 'uint256' }
]
const typedData = {
types: {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' }
],
Airdrop: params,
},
primaryType: 'Airdrop',
domain: {
name: 'Binh CAO',
version: '1',
chainId: '1',
verifyingContract: airdropAddress
},
message
}
const privateKey = Buffer.from(adminKey, 'hex')
const messageFromData = getMessage(typedData, true)
const { r, s, v } = ecsign(messageFromData, privateKey)
return `0x${r.toString('hex')}${s.toString('hex')}${v.toString(16)}`
}
async function getSignatureAirdrop(user, amount) {
const nonce = await getNonceOfAirdropContract(user)
const signature = signMessageAirdrop({
user,
nonce,
amount
})
return {
signature
}
}
async function getNonceOfAirdropContract(userAddress) {
return parseInt(await airdropContract.methods.nonces(userAddress).call())
}
export default {
getSignatureAirdrop
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
import "../libs/fota/MerkelProof.sol";
contract TheAirdropDistributor is EIP712 {
address public admin;
mapping (address => uint) public nonces;
mapping(address => bool) claimSignatureMarker;
event Claimed(address indexed user, uint amount);
constructor(
string memory _name,
string memory _version
) EIP712(_name, _version) {
admin = msg.sender;
rootHash = 0x4d690d7133a91f3a87725794a4532041be28f4eedb8e4305eafe73c6d732b390;
}
function updateRootHash(bytes32 _rootHash) external {
require(msg.sender == admin, "401");
rootHash = _rootHash;
}
function claim(bytes memory _signature, uint _amount) external {
require(!claimSignatureMarker[msg.sender], 'AirdropDistributor: Drop already claimed.');
bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
keccak256("Airdrop(address user,uint256 nonce,uint256 amount)"),
msg.sender,
nonces[msg.sender],
_amount
)));
nonces[msg.sender]++;
address signer = ECDSAUpgradeable.recover(digest, _signature);
require(signer == admin, "MessageVerifier: invalid signature");
require(signer != address(0), "ECDSAUpgradeable: invalid signature");
claimSignatureMarker[msg.sender] = true;
// TODO: distribute the airdrop to user
emit Claimed(msg.sender, _amount);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment