Skip to content

Instantly share code, notes, and snippets.

@baryon
Created September 6, 2019 10:18
Show Gist options
  • Save baryon/a5d33506e9d56770103fd9703864416e to your computer and use it in GitHub Desktop.
Save baryon/a5d33506e9d56770103fd9703864416e to your computer and use it in GitHub Desktop.
CSS代币合约
/**
*Submitted for verification at Etherscan.io on 2019-09-06
*/
pragma solidity 0.5.4;
library SafeMath {
uint256 constant internal MAX_UINT = 2 ** 256 - 1; // max uint256
/**
* @dev Multiplies two numbers, reverts on overflow.
*/
function mul(uint256 _a, uint256 _b) internal pure returns(uint256) {
if (_a == 0) {
return 0;
}
require(MAX_UINT / _a >= _b);
return _a * _b;
}
/**
* @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
*/
function div(uint256 _a, uint256 _b) internal pure returns(uint256) {
require(_b != 0);
return _a / _b;
}
/**
* @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 _a, uint256 _b) internal pure returns(uint256) {
require(_b <= _a);
return _a - _b;
}
/**
* @dev Adds two numbers, reverts on overflow.
*/
function add(uint256 _a, uint256 _b) internal pure returns(uint256) {
require(MAX_UINT - _a >= _b);
return _a + _b;
}
}
interface AbcInterface {
function decimals() external view returns (uint8);
function tokenFallback(address _from, uint _value, bytes calldata _data) external;
function transfer(address _to, uint _value) external returns (bool);
}
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor () public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0));
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
contract Pausable is Ownable {
event Pause();
event Unpause();
bool public paused = false;
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*/
modifier whenNotPaused() {
require(!paused);
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*/
modifier whenPaused() {
require(paused);
_;
}
/**
* @dev called by the owner to pause, triggers stopped state
*/
function pause() public onlyOwner whenNotPaused {
paused = true;
emit Pause();
}
/**
* @dev called by the owner to unpause, returns to normal state
*/
function unpause() public onlyOwner whenPaused {
paused = false;
emit Unpause();
}
}
contract StandardToken {
using SafeMath for uint256;
mapping(address => uint256) internal balances;
mapping(address => mapping(address => uint256)) internal allowed;
uint256 public totalSupply;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the balance of.
* @return An uint256 representing the value owned by the passed address.
*/
function balanceOf(address _owner) public view returns(uint256) {
return balances[_owner];
}
/**
* @dev Function to check the value of tokens that an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint256 specifying the value of tokens still available for the spender.
*/
function allowance(address _owner, address _spender) public view returns(uint256) {
return allowed[_owner][_spender];
}
/**
* @dev Transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The value to be transferred.
*/
function transfer(address _to, uint256 _value) public returns(bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Approve the passed address to spend the specified value of tokens on behalf of msg.sender.
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param _spender The address which will spend the funds.
* @param _value The value of tokens to be spent.
*/
function approve(address _spender, uint256 _value) public returns(bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the value of tokens to be transferred
*/
function transferFrom(address _from, address _to, uint256 _value) public returns(bool) {
require(_to != address(0));
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
/**
* @dev Increase the value of tokens that an owner allowed to a spender.
* approve should be called when allowed[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _addedValue The value of tokens to increase the allowance by.
*/
function increaseApproval(address _spender, uint256 _addedValue) public returns(bool) {
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
/**
* @dev Decrease the value of tokens that an owner allowed to a spender.
* approve should be called when allowed[_spender] == 0. To decrement
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _subtractedValue The value of tokens to decrease the allowance by.
*/
function decreaseApproval(address _spender, uint256 _subtractedValue) public returns(bool) {
uint256 oldValue = allowed[msg.sender][_spender];
if (_subtractedValue >= oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
function _burn(address account, uint256 value) internal {
require(account != address(0));
totalSupply = totalSupply.sub(value);
balances[account] = balances[account].sub(value);
emit Transfer(account, address(0), value);
}
/**
* @dev Internal function that burns an value of the token of a given
* account, deducting from the sender's allowance for said account. Uses the
* internal burn function.
* @param account The account whose tokens will be burnt.
* @param value The value that will be burnt.
*/
function _burnFrom(address account, uint256 value) internal {
// Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted,
// this function needs to emit an event with the updated approval.
allowed[account][msg.sender] = allowed[account][msg.sender].sub(value);
_burn(account, value);
}
}
contract BurnableToken is StandardToken {
/**
* @dev Burns a specific value of tokens.
* @param value The value of token to be burned.
*/
function burn(uint256 value) public {
_burn(msg.sender, value);
}
/**
* @dev Burns a specific value of tokens from the target address and decrements allowance
* @param from address The address which you want to send tokens from
* @param value uint256 The value of token to be burned
*/
function burnFrom(address from, uint256 value) public {
_burnFrom(from, value);
}
}
/**
* @title Pausable token
* @dev ERC20 modified with pausable transfers.
*/
contract PausableToken is StandardToken, Pausable {
function transfer(address to, uint256 value) public whenNotPaused returns (bool) {
return super.transfer(to, value);
}
function transferFrom(address from, address to, uint256 value) public whenNotPaused returns (bool) {
return super.transferFrom(from, to, value);
}
function approve(address spender, uint256 value) public whenNotPaused returns (bool) {
return super.approve(spender, value);
}
function increaseApproval(address spender, uint256 addedValue) public whenNotPaused returns (bool success) {
return super.increaseApproval(spender, addedValue);
}
function decreaseApproval(address spender, uint256 subtractedValue) public whenNotPaused returns (bool success) {
return super.decreaseApproval(spender, subtractedValue);
}
}
contract LockableToken is PausableToken {
struct LockInfo {
uint256 amount;
uint256 releaseTime;
}
mapping(address => LockInfo[]) public lockDetail;
mapping(address => uint256) public transferLocked;
event LockToken(address indexed benefit, uint256 amount, uint256 releasetime);
event ReleaseToken(address indexed benefit, uint256 amount);
/**
* @dev Transfers and locks tokens.
* @param to The address to transfer to.
* @param value The value to be transferred.
* @param lockdays The days of locking tokens.
*/
function transferAndLock(address to, uint256 value, uint256 lockdays) public whenNotPaused returns (bool) {
release(msg.sender);
require(to != address(0) && value != 0 && lockdays != 0);
uint256 _releaseTime = now.add(lockdays.mul(1 days));
lockDetail[to].push(LockInfo({amount:value, releaseTime:_releaseTime}));
balances[msg.sender] = balances[msg.sender].sub(value);
transferLocked[to] = transferLocked[to].add(value);
emit Transfer(msg.sender, to, value);
emit LockToken(to, value, _releaseTime);
return true;
}
/**
* @dev Rewrites function transfer, release tokens before transferring.
*/
function transfer(address to, uint256 value) public returns (bool) {
release(msg.sender);
return super.transfer(to, value);
}
/**
* @dev Rewrites function transferFrom, release tokens before transferring.
*/
function transferFrom(address from, address to, uint256 value) public returns (bool) {
release(from);
return super.transferFrom(from, to, value);
}
/**
* @dev release tokens.
*/
function release(address benefit) public whenNotPaused {
uint256 len = lockDetail[benefit].length;
if( len == 0) return;
uint256 totalReleasable = 0;
for(uint256 i = 0; i < len; i = i.add(1)){
LockInfo memory tmp = lockDetail[benefit][i];
if(tmp.releaseTime != 0 && now >= tmp.releaseTime){
totalReleasable = totalReleasable.add(tmp.amount);
delete lockDetail[benefit][i];
}
}
if(totalReleasable == 0) return;
balances[benefit] = balances[benefit].add(totalReleasable);
transferLocked[benefit] = transferLocked[benefit].sub(totalReleasable);
if(transferLocked[benefit] == 0)
delete lockDetail[benefit];
emit ReleaseToken(benefit, totalReleasable);
}
/**
* @dev Calculates the amount of releasable tokens.
*/
function releasableTokens(address benefit) public view returns(uint256) {
uint256 len = lockDetail[benefit].length;
if( len == 0) return 0;
uint256 releasable = 0;
for(uint256 i = 0; i < len; i = i.add(1)){
LockInfo memory tmp = lockDetail[benefit][i];
if(tmp.releaseTime != 0 && now >= tmp.releaseTime){
releasable = releasable.add(tmp.amount);
}
}
return releasable;
}
}
contract Token is LockableToken, BurnableToken {
string public name; // name of Token
string public symbol; // symbol of Token
uint8 public decimals;
constructor(string memory _name, string memory _symbol, uint8 _decimals) public {
name = _name;
symbol = _symbol;
decimals = _decimals;
}
}
contract BDR is Token {
struct Trx {
bool executed;
address from;
uint256 value;
address[] signers;
}
mapping(address => bool) public isSigner;
mapping(uint256 => Trx) public exchangeTrx;
address public AbcInstance; // address of AbcToken
uint256 public requestSigners = 2; // BDR => Abc need signers number
uint256 public applyCounts = 0; // Sequence of exchange request
mapping(address => uint256) public exchangeLock;
event SetSigner(address indexed signer,bool isSigner); // emit when add/remove signer
event ApplyExchangeToken(address indexed from,uint256 value,uint256 trxSeq); // emit when exchange successful
event ConfirmTrx(address indexed signer,uint256 indexed trxSeq); // emit when signer confirmed exchange request
event CancleConfirmTrx(address indexed signer,uint256 indexed trxSeq); // emit when signer cancles confirmed exchange request
event CancleExchangeRequest(address indexed signer,uint256 indexed trxSeq); // emit when signer/requester cancles exchange request
event TokenExchange(address indexed from,uint256 value,bool AbcExchangeBDR); // emit when Abc <=> Bdr,true:Abc => BDR,false:BDR => abc
event Mint(address indexed target,uint256 value);
modifier onlySigner() {
require(isSigner[msg.sender]);
_;
}
/**
* @dev initialize token info
* @param _name string The name of token
* @param _symbol string The symbol of token
* @param _decimals uint8 The decimals of token
*/
constructor(string memory _name, string memory _symbol, uint8 _decimals) Token(_name,_symbol,_decimals) public {
}
/**
* @dev rewrite transfer function,user can't transfer token to AbcToken's address directly
*/
function transfer(address _to,uint256 _value) public returns (bool success) {
require(_to != AbcInstance,"can't transfer to AbcToken address directly");
return super.transfer(_to,_value);
}
/**
* @dev rewrite transferFrom function,user can't transfer token to AbcToken's address directly
*/
function transferFrom(address _from, address _to,uint256 _value) public returns (bool success) {
require(_to != AbcInstance,"can't transfer to AbcToken address directly");
return super.transferFrom(_from,_to,_value);
}
/**
* @dev rewrite transferAndLock function,user can't transfer token to AbcToken's address directly
*/
function transferAndLock(address _to, uint256 _value, uint256 _lockdays) public returns (bool success) {
require(_to != AbcInstance,"can't transfer to AbcToken address directly");
return super.transferAndLock(_to,_value,_lockdays);
}
/**
* @dev set AbcToken's address
*/
function setAbcInstance(address _abc) public onlyOwner {
require(_abc != address(0));
AbcInstance = _abc;
}
/**
* @dev add/remove signers
* @param _signers address[] The array of signers to add/remove
* @param _addSigner bool true:add signers,false:remove:signers
*/
function setSigners(address[] memory _signers,bool _addSigner) public onlyOwner {
for(uint256 i = 0;i< _signers.length;i++){
require(_signers[i] != address(0));
isSigner[_signers[i]] = _addSigner;
emit SetSigner(_signers[i],_addSigner);
}
}
/**
* @dev set the number of exchange request in order to execute
* @param _requestSigners uint256 The number of signers
*/
function setrequestSigners(uint256 _requestSigners) public onlyOwner {
require(_requestSigners != 0);
requestSigners = _requestSigners;
}
/**
* @dev check whether the signer confirmed this exchange request
*/
function isConfirmer(uint256 _trxSeq,address _signer) public view returns (bool) {
require(exchangeTrx[_trxSeq].from != address(0),"trxSeq not exist");
for(uint256 i = 0;i < exchangeTrx[_trxSeq].signers.length;i++){
if(exchangeTrx[_trxSeq].signers[i] == _signer){
return true;
}
}
return false;
}
/**
* @dev get how many signers that confirmed this exchange request
*/
function getConfirmersLengthOfTrx(uint256 _trxSeq) public view returns (uint256) {
return exchangeTrx[_trxSeq].signers.length;
}
/**
* @dev get signers's address that confirmed this exchange request
* @param _trxSeq uint256 the Sequence of exchange request
* @param _index uint256 the index of signers
*/
function getConfirmerOfTrx(uint256 _trxSeq,uint256 _index) public view returns (address) {
require(_index < getConfirmersLengthOfTrx(_trxSeq),"out of range");
return exchangeTrx[_trxSeq].signers[_index];
}
/**
* @dev apply BDR exchange Abc
* @param _value uint256 amount of BDR to exchange
* @return uint256 the sequence of exchange request
*/
function applyExchangeToken(uint256 _value) public whenNotPaused returns (uint256) {
uint256 trxSeq = applyCounts;
require(exchangeTrx[trxSeq].from == address(0),"trxSeq already exist");
require(balances[msg.sender] >= _value);
exchangeTrx[trxSeq].executed = false;
exchangeTrx[trxSeq].from = msg.sender;
exchangeTrx[trxSeq].value = _value;
applyCounts = applyCounts.add(1);
balances[address(this)] = balances[address(this)].add(_value);
balances[exchangeTrx[trxSeq].from] = balances[exchangeTrx[trxSeq].from].sub(_value);
exchangeLock[exchangeTrx[trxSeq].from] = exchangeLock[exchangeTrx[trxSeq].from].add(_value);
emit ApplyExchangeToken(exchangeTrx[trxSeq].from,exchangeTrx[trxSeq].value,trxSeq);
emit Transfer(msg.sender,address(this),_value);
return trxSeq;
}
/**
* @dev signer confirms one exchange request
* @param _trxSeq uint256 the Sequence of exchange request
*/
function confirmExchangeTrx(uint256 _trxSeq) public onlySigner {
require(exchangeTrx[_trxSeq].from != address(0),"_trxSeq not exist");
require(exchangeTrx[_trxSeq].signers.length < requestSigners,"trx already has enough signers");
require(exchangeTrx[_trxSeq].executed == false,"trx already executed");
require(isConfirmer(_trxSeq, msg.sender) == false,"signer already confirmed");
exchangeTrx[_trxSeq].signers.push(msg.sender);
emit ConfirmTrx(msg.sender, _trxSeq);
}
/**
* @dev signer cancel confirmed exchange request
* @param _trxSeq uint256 the Sequence of exchange request
*/
function cancelConfirm(uint256 _trxSeq) public onlySigner {
require(exchangeTrx[_trxSeq].from != address(0),"_trxSeq not exist");
require(isConfirmer(_trxSeq, msg.sender),"Signer didn't confirm");
require(exchangeTrx[_trxSeq].executed == false,"trx already executed");
uint256 len = exchangeTrx[_trxSeq].signers.length;
for(uint256 i = 0;i < len;i++){
if(exchangeTrx[_trxSeq].signers[i] == msg.sender){
exchangeTrx[_trxSeq].signers[i] = exchangeTrx[_trxSeq].signers[len.sub(1)] ;
exchangeTrx[_trxSeq].signers.length --;
break;
}
}
emit CancleConfirmTrx(msg.sender,_trxSeq);
}
/**
* @dev signer cancel exchange request
* @param _trxSeq uint256 the Sequence of exchange request
*/
function cancleExchangeRequest(uint256 _trxSeq) public {
require(exchangeTrx[_trxSeq].from != address(0),"_trxSeq not exist");
require(exchangeTrx[_trxSeq].executed == false,"trx already executed");
require(isSigner[msg.sender] || exchangeTrx[_trxSeq].from == msg.sender);
balances[address(this)] = balances[address(this)].sub(exchangeTrx[_trxSeq].value);
balances[exchangeTrx[_trxSeq].from] = balances[exchangeTrx[_trxSeq].from].add(exchangeTrx[_trxSeq].value);
exchangeLock[exchangeTrx[_trxSeq].from] = exchangeLock[exchangeTrx[_trxSeq].from].sub(exchangeTrx[_trxSeq].value);
delete exchangeTrx[_trxSeq];
emit CancleExchangeRequest(msg.sender,_trxSeq);
emit Transfer(address(this),exchangeTrx[_trxSeq].from,exchangeTrx[_trxSeq].value);
}
/**
* @dev execute exchange request which confirmed by enough signers
* @param _trxSeq uint256 the Sequence of exchange request
*/
function executeExchangeTrx(uint256 _trxSeq) public whenNotPaused{
address from = exchangeTrx[_trxSeq].from;
uint256 value = exchangeTrx[_trxSeq].value;
require(from != address(0),"trxSeq not exist");
require(exchangeTrx[_trxSeq].executed == false,"trxSeq has executed");
require(exchangeTrx[_trxSeq].signers.length >= requestSigners);
require(from == msg.sender|| isSigner[msg.sender]);
require(value <= balances[address(this)]);
_burn(address(this), value);
exchangeLock[from] = exchangeLock[from].sub(value);
exchangeTrx[_trxSeq].executed = true;
AbcInterface(AbcInstance).tokenFallback(from,value,bytes(""));
emit TokenExchange(exchangeTrx[_trxSeq].from,exchangeTrx[_trxSeq].value,false);
}
/**
* @dev exchange Abc token to BDR token,only AbcInstance can invoke this function
*/
function tokenFallback(address _from, uint _value, bytes memory) public {
require(msg.sender == AbcInstance);
require(_from != address(0));
require(_value > 0);
uint256 exchangeAmount = _value.mul(10**uint256(decimals)).div(10**uint256(AbcInterface(AbcInstance).decimals()));
_mint(_from, exchangeAmount);
emit Transfer(address(0x00),_from,exchangeAmount);
emit TokenExchange(_from,_value,true);
}
/**
* @dev mint BDR token
*/
function _mint(address target, uint256 value ) internal {
balances[target] = balances[target].add(value);
totalSupply = totalSupply.add(value);
emit Mint(target,value);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment