From ebc3102e422d148c90cd2053fa62f25753395235 Mon Sep 17 00:00:00 2001 From: kw Date: Fri, 23 Feb 2024 17:44:05 +0800 Subject: [PATCH] added token contracts --- README.md | 2 + contracts/token/Airdrop.sol | 100 ++++++++++++++++++++++++++++++++++++ contracts/token/Virtual.sol | 17 ++++++ 3 files changed, 119 insertions(+) create mode 100644 contracts/token/Airdrop.sol create mode 100644 contracts/token/Virtual.sol diff --git a/README.md b/README.md index 62a7318..6eff2ef 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ | AgentDAO | This is implementation contract for VIRTUAL specific DAO. AgentFactory will clone this during VIRTUAL instantiation. It holds the maturity score for each core service. | - | N | | AgentReward | This is reward distribution center. | Roles: GOV_ROLE, TOKEN_SAVER_ROLE | Y | | TimeLockStaking | Allows user to stake their $VIRTUAL in exchange for $sVIRTUAL | Roles: GOV_ROLE, TOKEN_SAVER_ROLE | N | +| Virtual | $VIRTUAL token | Ownable | N | +| Airdrop | Airdrop token to holders | - | N | # Main Activities diff --git a/contracts/token/Airdrop.sol b/contracts/token/Airdrop.sol new file mode 100644 index 0000000..826d89d --- /dev/null +++ b/contracts/token/Airdrop.sol @@ -0,0 +1,100 @@ +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract Airdrop { + + /** + * + * @param _token ERC20 token to airdrop + * @param _recipients list of recipients + * @param _amounts list of amounts to send each recipient + * @param _total total amount to transfer from caller + */ + function airdrop( + IERC20 _token, + address[] calldata _recipients, + uint256[] calldata _amounts, + uint256 _total + ) external { + // bytes selector for transferFrom(address,address,uint256) + bytes4 transferFrom = 0x23b872dd; + // bytes selector for transfer(address,uint256) + bytes4 transfer = 0xa9059cbb; + + assembly { + // store transferFrom selector + let transferFromData := add(0x20, mload(0x40)) + mstore(transferFromData, transferFrom) + // store caller address + mstore(add(transferFromData, 0x04), caller()) + // store address + mstore(add(transferFromData, 0x24), address()) + // store _total + mstore(add(transferFromData, 0x44), _total) + // call transferFrom for _total + let successTransferFrom := call( + gas(), + _token, + 0, + transferFromData, + 0x64, + 0, + 0 + ) + // revert if call fails + if iszero(successTransferFrom) { + revert(0, 0) + } + + // store transfer selector + let transferData := add(0x20, mload(0x40)) + mstore(transferData, transfer) + + // store length of _recipients + let sz := _amounts.length + + // loop through _recipients + for { + let i := 0 + } lt(i, sz) { + // increment i + i := add(i, 1) + } { + // store offset for _amounts[i] + let offset := mul(i, 0x20) + // store _amounts[i] + let amt := calldataload(add(_amounts.offset, offset)) + // store _recipients[i] + let recp := calldataload(add(_recipients.offset, offset)) + // store _recipients[i] in transferData + mstore( + add(transferData, 0x04), + recp + ) + // store _amounts[i] in transferData + mstore( + add(transferData, 0x24), + amt + ) + // call transfer for _amounts[i] to _recipients[i] + let successTransfer := call( + gas(), + _token, + 0, + transferData, + 0x44, + 0, + 0 + ) + // revert if call fails + + + if iszero(successTransfer) { + revert(0, 0) + } + } + } + + } +} \ No newline at end of file diff --git a/contracts/token/Virtual.sol b/contracts/token/Virtual.sol new file mode 100644 index 0000000..8b5e2bc --- /dev/null +++ b/contracts/token/Virtual.sol @@ -0,0 +1,17 @@ +pragma solidity ^0.8.20; + +// SPDX-License-Identifier: MIT + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract VirtualToken is ERC20Capped, Ownable { + constructor(uint256 _initialSupply, address initialOwner) ERC20("Virtual Protocol", "VIRTUAL") ERC20Capped(1000000000*10**18) Ownable(initialOwner){ + ERC20._mint(msg.sender, _initialSupply); + } + + function mint(address _to, uint256 _amount) onlyOwner external { + _mint(_to, _amount); + } +} \ No newline at end of file