Last active
June 5, 2021 20:14
-
-
Save dbeal-eth/9d38a097c4c58f42409f3f9874f3a5fe to your computer and use it in GitHub Desktop.
Bonus Emission Escrow
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "./interfaces/IERC20.sol"; | |
import "./Owned.sol"; | |
/** | |
* @title BonusEmissionEscrow | |
* @dev Escrow that holds funds for a beneficiary, deposited from a single party | |
* @dev The owner account (that is, the address that instantiates this | |
* contract) deposits the principal into the contract after construction, and after | |
* `startTime` for `period` seconds following, deposited funds will be emitted | |
* linerly. Beneficiary can claim curerntly emitted, claimable funds by calling `claim`. | |
* Owner may terminate emission and collect unemitted funds by calling `terminate` | |
*/ | |
contract BonusEmissionEscrow is Owned { | |
event Claimed(address indexed beneficiary, uint claimed); | |
event Funded(address indexed beneficiary, uint funded); | |
address public immutable beneficiary; | |
address public immutable token; | |
uint public immutable principal; | |
uint public immutable startTime; | |
uint public immutable period; | |
uint public withdrawn; | |
/** | |
* @dev Constructor. | |
* @param beneficiary_ The beneficiary of the deposits. | |
* @param token_ The token supplied by the emitted bonus | |
* @param principal_ The amount of `token` supplied to the beneficiary by the end of `period_` | |
* @param startTime_ Unix time which beneficiary can start claiming funds | |
* @param period_ Unix time over which the funds will be emitted for claim | |
*/ | |
constructor (address payable beneficiary_, address token_, uint principal_, uint startTime_, uint period_) { | |
require(beneficiary_ != address(0), "RefundEscrow: beneficiary is the zero address"); | |
beneficiary = beneficiary_; | |
token = token_; | |
principal = principal_; | |
startTime = startTime_; | |
period = period_; | |
} | |
function tokenContract() internal view returns (IERC20) { | |
return IERC20(token); | |
} | |
/** | |
* @dev called after constructor to add funds to the contract | |
* will pull in needed ERC20 tokens in order to initialize the bonus emission | |
*/ | |
function fund() public onlyOwner virtual { | |
require(tokenContract().balanceOf(address(this)) == 0); | |
tokenContract().transferFrom(owner, address(this), principal); | |
emit Funded(beneficiary, principal); | |
} | |
/** | |
* @dev terminate the bonus, sends availableToWithdraw to beneficiary, and refunds remaining tokens to owner | |
*/ | |
function terminate() public onlyOwner virtual { | |
tokenContract().transfer(beneficiary, availableToClaim()); | |
tokenContract().transfer(owner, IERC20(token).balanceOf(address(this))); | |
selfdestruct(); | |
} | |
/** | |
* @dev reports number of tokens can be claimed if `claim` were called now. | |
*/ | |
function availableToClaim() public view returns (uint256) { | |
uint remaining = principal - withdrawn; | |
uint curtime = block.timestamp; | |
int reltime = curtime - startTime; | |
if(reltime < 0) { | |
return 0; | |
} | |
if(reltime > period) { | |
return remaining; | |
} | |
uint available = principal * reltime / period - withdrawn; | |
require(available < remaining); | |
return available; | |
} | |
/** | |
* @dev Claims the beneficiary's currently available funds. | |
*/ | |
function claim() public virtual { | |
uint claimable = availableToClaim(); | |
withdrawn += claimable; | |
tokenContract().transfer(owner, beneficiary, claimable); | |
emit Claimed(beneficiary, claimable); | |
if(principal - withdrawn == 0) { | |
selfdestruct(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment