Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
100 changes: 100 additions & 0 deletions contracts/token/Airdrop.sol
Original file line number Diff line number Diff line change
@@ -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)
}
}
}

}
}
17 changes: 17 additions & 0 deletions contracts/token/Virtual.sol
Original file line number Diff line number Diff line change
@@ -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);
}
}