pragmasolidity ^0.5.2;contractAdmin{
addressinternal _admin;
eventAdminChanged(address oldAdmin, address newAdmin);
/// @notice gives the current administrator of this contract./// @return the current administrator of this contract.functiongetAdmin() externalviewreturns (address) {
return _admin;
}
/// @notice change the administrator to be `newAdmin`./// @param newAdmin address of the new administrator.functionchangeAdmin(address newAdmin) external{
require(msg.sender== _admin, "only admin can change admin");
emit AdminChanged(_admin, newAdmin);
_admin = newAdmin;
}
}
Contract Source Code
File 2 of 8: BytesUtil.sol
pragmasolidity ^0.5.2;libraryBytesUtil{
functionmemcpy(uint256 dest, uint256 src, uint256 len) internalpure{
// Copy word-length chunks while possiblefor (; len >=32; len -=32) {
assembly {
mstore(dest, mload(src))
}
dest +=32;
src +=32;
}
// Copy remaining bytesuint256 mask =256**(32- len) -1;
assembly {
let srcpart :=and(mload(src), not(mask))
let destpart :=and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
functionpointerToBytes(uint256 src, uint256 len)
internalpurereturns (bytesmemory)
{
bytesmemory ret =newbytes(len);
uint256 retptr;
assembly {
retptr :=add(ret, 32)
}
memcpy(retptr, src, len);
return ret;
}
functionaddressToBytes(address a) internalpurereturns (bytesmemory b) {
assembly {
let m :=mload(0x40)
mstore(
add(m, 20),
xor(0x140000000000000000000000000000000000000000, a)
)
mstore(0x40, add(m, 52))
b := m
}
}
functionuint256ToBytes(uint256 a) internalpurereturns (bytesmemory b) {
assembly {
let m :=mload(0x40)
mstore(add(m, 32), a)
mstore(0x40, add(m, 64))
b := m
}
}
functiondoFirstParamEqualsAddress(bytesmemory data, address _address)
internalpurereturns (bool)
{
if (data.length< (36+32)) {
returnfalse;
}
uint256 value;
assembly {
value :=mload(add(data, 36))
}
return value ==uint256(_address);
}
functiondoParamEqualsUInt256(bytesmemory data, uint256 i, uint256 value)
internalpurereturns (bool)
{
if (data.length< (36+ (i +1) *32)) {
returnfalse;
}
uint256 offset =36+ i *32;
uint256 valuePresent;
assembly {
valuePresent :=mload(add(data, offset))
}
return valuePresent == value;
}
functionoverrideFirst32BytesWithAddress(bytesmemory data,
address _address
) internalpurereturns (bytesmemory) {
uint256 dest;
assembly {
dest :=add(data, 48)
} // 48 = 32 (offset) + 4 (func sig) + 12 (address is only 20 bytes)bytesmemory addressBytes = addressToBytes(_address);
uint256 src;
assembly {
src :=add(addressBytes, 32)
}
memcpy(dest, src, 20);
return data;
}
functionoverrideFirstTwo32BytesWithAddressAndInt(bytesmemory data,
address _address,
uint256 _value
) internalpurereturns (bytesmemory) {
uint256 dest;
uint256 src;
assembly {
dest :=add(data, 48)
} // 48 = 32 (offset) + 4 (func sig) + 12 (address is only 20 bytes)bytesmemory bbytes = addressToBytes(_address);
assembly {
src :=add(bbytes, 32)
}
memcpy(dest, src, 20);
assembly {
dest :=add(data, 68)
} // 48 = 32 (offset) + 4 (func sig) + 32 (next slot)
bbytes = uint256ToBytes(_value);
assembly {
src :=add(bbytes, 32)
}
memcpy(dest, src, 32);
return data;
}
}
Contract Source Code
File 3 of 8: ERC20BaseToken.sol
pragmasolidity 0.5.9;import"../../../contracts_common/src/Interfaces/ERC20Events.sol";
import"../../../contracts_common/src/BaseWithStorage/SuperOperators.sol";
contractERC20BaseTokenisSuperOperators, ERC20Events{
uint256internal _totalSupply;
mapping(address=>uint256) internal _balances;
mapping(address=>mapping(address=>uint256)) internal _allowances;
/// @notice Gets the total number of tokens in existence./// @return the total number of tokens in existence.functiontotalSupply() publicviewreturns (uint256) {
return _totalSupply;
}
/// @notice Gets the balance of `owner`./// @param owner The address to query the balance of./// @return The amount owned by `owner`.functionbalanceOf(address owner) publicviewreturns (uint256) {
return _balances[owner];
}
/// @notice gets allowance of `spender` for `owner`'s tokens./// @param owner address whose token is allowed./// @param spender address allowed to transfer./// @return the amount of token `spender` is allowed to transfer on behalf of `owner`.functionallowance(address owner, address spender)
publicviewreturns (uint256 remaining)
{
return _allowances[owner][spender];
}
/// @notice returns the number of decimals for that token./// @return the number of decimals.functiondecimals() publicviewreturns (uint8) {
returnuint8(18);
}
/// @notice Transfer `amount` tokens to `to`./// @param to the recipient address of the tokens transfered./// @param amount the number of tokens transfered./// @return true if success.functiontransfer(address to, uint256 amount)
publicreturns (bool success)
{
_transfer(msg.sender, to, amount);
returntrue;
}
/// @notice Transfer `amount` tokens from `from` to `to`./// @param from whose token it is transferring from./// @param to the recipient address of the tokens transfered./// @param amount the number of tokens transfered./// @return true if success.functiontransferFrom(addressfrom, address to, uint256 amount)
publicreturns (bool success)
{
if (msg.sender!=from&&!_superOperators[msg.sender]) {
uint256 currentAllowance = _allowances[from][msg.sender];
if (currentAllowance != (2**256) -1) {
// save gas when allowance is maximal by not reducing it (see https://github.com/ethereum/EIPs/issues/717)require(currentAllowance >= amount, "Not enough funds allowed");
_allowances[from][msg.sender] = currentAllowance - amount;
}
}
_transfer(from, to, amount);
returntrue;
}
/// @notice burn `amount` tokens./// @param amount the number of tokens to burn./// @return true if success.functionburn(uint256 amount) externalreturns (bool) {
_burn(msg.sender, amount);
returntrue;
}
/// @notice burn `amount` tokens from `owner`./// @param owner address whose token is to burn./// @param amount the number of token to burn./// @return true if success.functionburnFor(address owner, uint256 amount) externalreturns (bool) {
_burn(owner, amount);
returntrue;
}
/// @notice approve `spender` to transfer `amount` tokens./// @param spender address to be given rights to transfer./// @param amount the number of tokens allowed./// @return true if success.functionapprove(address spender, uint256 amount)
publicreturns (bool success)
{
_approveFor(msg.sender, spender, amount);
returntrue;
}
/// @notice approve `spender` to transfer `amount` tokens from `owner`./// @param owner address whose token is allowed./// @param spender address to be given rights to transfer./// @param amount the number of tokens allowed./// @return true if success.functionapproveFor(address owner, address spender, uint256 amount)
publicreturns (bool success)
{
require(
msg.sender== owner || _superOperators[msg.sender],
"msg.sender != owner && !superOperator"
);
_approveFor(owner, spender, amount);
returntrue;
}
functionaddAllowanceIfNeeded(address owner, address spender, uint256 amountNeeded)
publicreturns (bool success)
{
require(
msg.sender== owner || _superOperators[msg.sender],
"msg.sender != owner && !superOperator"
);
_addAllowanceIfNeeded(owner, spender, amountNeeded);
returntrue;
}
function_addAllowanceIfNeeded(address owner, address spender, uint256 amountNeeded)
internal{
if(amountNeeded >0&&!isSuperOperator(spender)) {
uint256 currentAllowance = _allowances[owner][spender];
if(currentAllowance < amountNeeded) {
_approveFor(owner, spender, amountNeeded);
}
}
}
function_approveFor(address owner, address spender, uint256 amount)
internal{
require(
owner !=address(0) && spender !=address(0),
"Cannot approve with 0x0"
);
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function_transfer(addressfrom, address to, uint256 amount) internal{
require(to !=address(0), "Cannot send to 0x0");
uint256 currentBalance = _balances[from];
require(currentBalance >= amount, "not enough fund");
_balances[from] = currentBalance - amount;
_balances[to] += amount;
emit Transfer(from, to, amount);
}
function_mint(address to, uint256 amount) internal{
require(to !=address(0), "Cannot mint to 0x0");
require(amount >0, "cannot mint 0 tokens");
uint256 currentTotalSupply = _totalSupply;
uint256 newTotalSupply = currentTotalSupply + amount;
require(newTotalSupply > currentTotalSupply, "overflow");
_totalSupply = newTotalSupply;
_balances[to] += amount;
emit Transfer(address(0), to, amount);
}
function_burn(addressfrom, uint256 amount) internal{
require(amount >0, "cannot burn 0 tokens");
if (msg.sender!=from&&!_superOperators[msg.sender]) {
uint256 currentAllowance = _allowances[from][msg.sender];
require(
currentAllowance >= amount,
"Not enough funds allowed"
);
if (currentAllowance != (2**256) -1) {
// save gas when allowance is maximal by not reducing it (see https://github.com/ethereum/EIPs/issues/717)
_allowances[from][msg.sender] = currentAllowance - amount;
}
}
uint256 currentBalance = _balances[from];
require(currentBalance >= amount, "Not enough funds");
_balances[from] = currentBalance - amount;
_totalSupply -= amount;
emit Transfer(from, address(0), amount);
}
}
Contract Source Code
File 4 of 8: ERC20BasicApproveExtension.sol
pragmasolidity 0.5.9;import"../../../contracts_common/src/Libraries/BytesUtil.sol";
contractERC20BasicApproveExtension{
/// @notice approve `target` to spend `amount` and call it with data./// @param target address to be given rights to transfer and destination of the call./// @param amount the number of tokens allowed./// @param data bytes for the call./// @return data of the call.functionapproveAndCall(address target,
uint256 amount,
bytescalldata data
) externalpayablereturns (bytesmemory) {
require(
BytesUtil.doFirstParamEqualsAddress(data, msg.sender),
"first param != sender"
);
_approveFor(msg.sender, target, amount);
// solium-disable-next-line security/no-call-value
(bool success, bytesmemory returnData) = target.call.value(msg.value)(data);
require(success, string(returnData));
return returnData;
}
/// @notice temporarly approve `target` to spend `amount` and call it with data. Previous approvals remains unchanged./// @param target destination of the call, allowed to spend the amount specified/// @param amount the number of tokens allowed to spend./// @param data bytes for the call./// @return data of the call.functionpaidCall(address target,
uint256 amount,
bytescalldata data
) externalpayablereturns (bytesmemory) {
require(
BytesUtil.doFirstParamEqualsAddress(data, msg.sender),
"first param != sender"
);
if (amount >0) {
_addAllowanceIfNeeded(msg.sender, target, amount);
}
// solium-disable-next-line security/no-call-value
(bool success, bytesmemory returnData) = target.call.value(msg.value)(data);
require(success, string(returnData));
return returnData;
}
function_approveFor(address owner, address target, uint256 amount) internal;
function_addAllowanceIfNeeded(address owner, address spender, uint256 amountNeeded) internal;
}
Contract Source Code
File 5 of 8: ERC20Events.sol
pragmasolidity ^0.5.2;/* interface */contractERC20Events{
eventTransfer(addressindexedfrom, addressindexed to, uint256 value);
eventApproval(addressindexed owner,
addressindexed spender,
uint256 value
);
}
Contract Source Code
File 6 of 8: ERC20ExecuteExtension.sol
pragmasolidity 0.5.9;contractERC20ExecuteExtension{
/// @dev _executionAdmin != _admin so that this super power can be disabled independentlyaddressinternal _executionAdmin;
eventExecutionAdminAdminChanged(address oldAdmin, address newAdmin);
/// @notice give the address responsible for adding execution rights./// @return address of the execution administrator.functiongetExecutionAdmin() externalviewreturns (address) {
return _executionAdmin;
}
/// @notice change the execution adminstrator to be `newAdmin`./// @param newAdmin address of the new administrator.functionchangeExecutionAdmin(address newAdmin) external{
require(msg.sender== _executionAdmin, "only executionAdmin can change executionAdmin");
emit ExecutionAdminAdminChanged(_executionAdmin, newAdmin);
_executionAdmin = newAdmin;
}
mapping(address=>bool) internal _executionOperators;
eventExecutionOperator(address executionOperator, bool enabled);
/// @notice set `executionOperator` as executionOperator: `enabled`./// @param executionOperator address that will be given/removed executionOperator right./// @param enabled set whether the executionOperator is enabled or disabled.functionsetExecutionOperator(address executionOperator, bool enabled) external{
require(
msg.sender== _executionAdmin,
"only execution admin is allowed to add execution operators"
);
_executionOperators[executionOperator] = enabled;
emit ExecutionOperator(executionOperator, enabled);
}
/// @notice check whether address `who` is given executionOperator rights./// @param who The address to query./// @return whether the address has executionOperator rights.functionisExecutionOperator(address who) publicviewreturns (bool) {
return _executionOperators[who];
}
/// @notice execute on behalf of the contract./// @param to destination address fo the call./// @param gasLimit exact amount of gas to be passed to the call./// @param data the bytes sent to the destination address./// @return success whether the execution was successful./// @return returnData data resulting from the execution.functionexecuteWithSpecificGas(address to, uint256 gasLimit, bytescalldata data) externalreturns (bool success, bytesmemory returnData) {
require(_executionOperators[msg.sender], "only execution operators allowed to execute on SAND behalf");
(success, returnData) = to.call.gas(gasLimit)(data);
assert(gasleft() > gasLimit /63); // not enough gas provided, assert to throw all gas // TODO use EIP-1930
}
/// @notice approve a specific amount of token for `from` and execute on behalf of the contract./// @param from address of which token will be transfered./// @param to destination address fo the call./// @param amount number of tokens allowed that can be transfer by the code at `to`./// @param gasLimit exact amount of gas to be passed to the call./// @param data the bytes sent to the destination address./// @return success whether the execution was successful./// @return returnData data resulting from the execution.functionapproveAndExecuteWithSpecificGas(addressfrom,
address to,
uint256 amount,
uint256 gasLimit,
bytescalldata data
) externalreturns (bool success, bytesmemory returnData) {
require(_executionOperators[msg.sender], "only execution operators allowed to execute on SAND behalf");
return _approveAndExecuteWithSpecificGas(from, to, amount, gasLimit, data);
}
/// @dev the reason for this function is that charging for gas here is more gas-efficient than doing it in the caller./// @notice approve a specific amount of token for `from` and execute on behalf of the contract. Plus charge the gas required to perform it./// @param from address of which token will be transfered./// @param to destination address fo the call./// @param amount number of tokens allowed that can be transfer by the code at `to`./// @param gasLimit exact amount of gas to be passed to the call./// @param tokenGasPrice price in token for the gas to be charged./// @param baseGasCharge amount of gas charged on top of the gas used for the call./// @param tokenReceiver recipient address of the token charged for the gas used./// @param data the bytes sent to the destination address./// @return success whether the execution was successful./// @return returnData data resulting from the execution.functionapproveAndExecuteWithSpecificGasAndChargeForIt(addressfrom,
address to,
uint256 amount,
uint256 gasLimit,
uint256 tokenGasPrice,
uint256 baseGasCharge,
address tokenReceiver,
bytescalldata data
) externalreturns (bool success, bytesmemory returnData) {
uint256 initialGas =gasleft();
require(_executionOperators[msg.sender], "only execution operators allowed to execute on SAND behalf");
(success, returnData) = _approveAndExecuteWithSpecificGas(from, to, amount, gasLimit, data);
if (tokenGasPrice >0) {
_charge(from, gasLimit, tokenGasPrice, initialGas, baseGasCharge, tokenReceiver);
}
}
/// @notice transfer 1amount1 token from `from` to `to` and charge the gas required to perform that transfer./// @param from address of which token will be transfered./// @param to destination address fo the call./// @param amount number of tokens allowed that can be transfer by the code at `to`./// @param gasLimit exact amount of gas to be passed to the call./// @param tokenGasPrice price in token for the gas to be charged./// @param baseGasCharge amount of gas charged on top of the gas used for the call./// @param tokenReceiver recipient address of the token charged for the gas used./// @return whether the transfer was successful.functiontransferAndChargeForGas(addressfrom,
address to,
uint256 amount,
uint256 gasLimit,
uint256 tokenGasPrice,
uint256 baseGasCharge,
address tokenReceiver
) externalreturns (bool) {
uint256 initialGas =gasleft();
require(_executionOperators[msg.sender], "only execution operators allowed to perfrom transfer and charge");
_transfer(from, to, amount);
if (tokenGasPrice >0) {
_charge(from, gasLimit, tokenGasPrice, initialGas, baseGasCharge, tokenReceiver);
}
returntrue;
}
function_charge(addressfrom,
uint256 gasLimit,
uint256 tokenGasPrice,
uint256 initialGas,
uint256 baseGasCharge,
address tokenReceiver
) internal{
uint256 gasCharge = initialGas -gasleft();
if(gasCharge > gasLimit) {
gasCharge = gasLimit;
}
gasCharge += baseGasCharge;
uint256 tokensToCharge = gasCharge * tokenGasPrice;
require(tokensToCharge / gasCharge == tokenGasPrice, "overflow");
_transfer(from, tokenReceiver, tokensToCharge);
}
function_approveAndExecuteWithSpecificGas(addressfrom,
address to,
uint256 amount,
uint256 gasLimit,
bytesmemory data
) internalreturns (bool success, bytesmemory returnData) {
if (amount >0) {
_addAllowanceIfNeeded(from, to, amount);
}
(success, returnData) = to.call.gas(gasLimit)(data);
assert(gasleft() > gasLimit /63); // not enough gas provided, assert to throw all gas // TODO use EIP-1930
}
function_transfer(addressfrom, address to, uint256 amount) internal;
function_addAllowanceIfNeeded(address owner, address spender, uint256 amountNeeded) internal;
}
Contract Source Code
File 7 of 8: Sand.sol
pragmasolidity 0.5.9;import"./Sand/erc20/ERC20ExecuteExtension.sol";
import"./Sand/erc20/ERC20BaseToken.sol";
import"./Sand/erc20/ERC20BasicApproveExtension.sol";
contractSandisERC20ExecuteExtension, ERC20BasicApproveExtension, ERC20BaseToken{
constructor(address sandAdmin, address executionAdmin, address beneficiary) public{
_admin = sandAdmin;
_executionAdmin = executionAdmin;
_mint(beneficiary, 3000000000000000000000000000);
}
/// @notice A descriptive name for the tokens/// @return name of the tokensfunctionname() publicviewreturns (stringmemory) {
return"SAND";
}
/// @notice An abbreviated name for the tokens/// @return symbol of the tokensfunctionsymbol() publicviewreturns (stringmemory) {
return"SAND";
}
}
Contract Source Code
File 8 of 8: SuperOperators.sol
pragmasolidity ^0.5.2;import"./Admin.sol";
contractSuperOperatorsisAdmin{
mapping(address=>bool) internal _superOperators;
eventSuperOperator(address superOperator, bool enabled);
/// @notice Enable or disable the ability of `superOperator` to transfer tokens of all (superOperator rights)./// @param superOperator address that will be given/removed superOperator right./// @param enabled set whether the superOperator is enabled or disabled.functionsetSuperOperator(address superOperator, bool enabled) external{
require(
msg.sender== _admin,
"only admin is allowed to add super operators"
);
_superOperators[superOperator] = enabled;
emit SuperOperator(superOperator, enabled);
}
/// @notice check whether address `who` is given superOperator rights./// @param who The address to query./// @return whether the address has superOperator rights.functionisSuperOperator(address who) publicviewreturns (bool) {
return _superOperators[who];
}
}