Transaction Hash:
Block:
18996763 at Jan-13-2024 08:25:11 AM +UTC
Transaction Fee:
0.00129470317474124 ETH
$4.92
Gas Used:
79,640 Gas / 16.256945941 Gwei
Emitted Events:
312 |
RING.Transfer( src=[Receiver] OwnedUpgradeabilityProxy, dst=[Sender] 0x122a1e9a4f2f6055f0f3fe60eb98ba438e560108, wad=25000000000000000000000 )
|
313 |
OwnedUpgradeabilityProxy.0x6fcd44939c95364863265e2908a0edea0cc534e2a03003586f8202855cc6b145( 0x6fcd44939c95364863265e2908a0edea0cc534e2a03003586f8202855cc6b145, 0x0000000000000000000000000000000000000000000000000000000000000307, 0x000000000000000000000000122a1e9a4f2f6055f0f3fe60eb98ba438e560108, 00000000000000000000000000000000000000000000054b40b1f852bda00000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x122A1E9a...38e560108 |
0.087256107224808642 Eth
Nonce: 595
|
0.085961404050067402 Eth
Nonce: 596
| 0.00129470317474124 | ||
0x4838B106...B0BAD5f97
Miner
| (Titan Builder) | 27.468361066045601575 Eth | 27.468429741566790575 Eth | 0.000068675521189 | |
0x649fDF6e...0fbD82D88 | |||||
0x9469D013...e535ec483 |
Execution Trace
OwnedUpgradeabilityProxy.5f8534ae( )
GringottsBank.claimDeposit( _depositID=775 )
claimDeposit[GringottsBank (ln:448)]
_claimDeposit[GringottsBank (ln:449)]
addressOf[GringottsBank (ln:488)]
transfer[GringottsBank (ln:503)]
ClaimedDeposit[GringottsBank (ln:506)]
File 1 of 4: OwnedUpgradeabilityProxy
File 2 of 4: RING
File 3 of 4: GringottsBank
File 4 of 4: SettingsRegistry
// Dependency file: contracts/Proxy.sol // pragma solidity ^0.4.21; /** * @title Proxy * @dev Gives the possibility to delegate any call to a foreign implementation. */ contract Proxy { /** * @dev Tells the address of the implementation where every call will be delegated. * @return address of the implementation to which it will be delegated */ function implementation() public view returns (address); /** * @dev Fallback function allowing to perform a delegatecall to the given implementation. * This function will return whatever the implementation call returns */ function () payable public { address _impl = implementation(); require(_impl != address(0)); assembly { let ptr := mload(0x40) calldatacopy(ptr, 0, calldatasize) let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0) let size := returndatasize returndatacopy(ptr, 0, size) switch result case 0 { revert(ptr, size) } default { return(ptr, size) } } } } // Dependency file: contracts/UpgradeabilityProxy.sol // pragma solidity ^0.4.21; // import 'contracts/Proxy.sol'; /** * @title UpgradeabilityProxy * @dev This contract represents a proxy where the implementation address to which it will delegate can be upgraded */ contract UpgradeabilityProxy is Proxy { /** * @dev This event will be emitted every time the implementation gets upgraded * @param implementation representing the address of the upgraded implementation */ event Upgraded(address indexed implementation); // Storage position of the address of the current implementation bytes32 private constant implementationPosition = keccak256("org.zeppelinos.proxy.implementation"); /** * @dev Constructor function */ function UpgradeabilityProxy() public {} /** * @dev Tells the address of the current implementation * @return address of the current implementation */ function implementation() public view returns (address impl) { bytes32 position = implementationPosition; assembly { impl := sload(position) } } /** * @dev Sets the address of the current implementation * @param newImplementation address representing the new implementation to be set */ function setImplementation(address newImplementation) internal { bytes32 position = implementationPosition; assembly { sstore(position, newImplementation) } } /** * @dev Upgrades the implementation address * @param newImplementation representing the address of the new implementation to be set */ function _upgradeTo(address newImplementation) internal { address currentImplementation = implementation(); require(currentImplementation != newImplementation); setImplementation(newImplementation); emit Upgraded(newImplementation); } } // Root file: contracts/OwnedUpgradeabilityProxy.sol pragma solidity ^0.4.21; // import 'contracts/UpgradeabilityProxy.sol'; /** * @title OwnedUpgradeabilityProxy * @dev This contract combines an upgradeability proxy with basic authorization control functionalities */ contract OwnedUpgradeabilityProxy is UpgradeabilityProxy { /** * @dev Event to show ownership has been transferred * @param previousOwner representing the address of the previous owner * @param newOwner representing the address of the new owner */ event ProxyOwnershipTransferred(address previousOwner, address newOwner); // Storage position of the owner of the contract bytes32 private constant proxyOwnerPosition = keccak256("org.zeppelinos.proxy.owner"); /** * @dev the constructor sets the original owner of the contract to the sender account. */ function OwnedUpgradeabilityProxy() public { setUpgradeabilityOwner(msg.sender); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyProxyOwner() { require(msg.sender == proxyOwner()); _; } /** * @dev Tells the address of the owner * @return the address of the owner */ function proxyOwner() public view returns (address owner) { bytes32 position = proxyOwnerPosition; assembly { owner := sload(position) } } /** * @dev Sets the address of the owner */ function setUpgradeabilityOwner(address newProxyOwner) internal { bytes32 position = proxyOwnerPosition; assembly { sstore(position, newProxyOwner) } } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferProxyOwnership(address newOwner) public onlyProxyOwner { require(newOwner != address(0)); emit ProxyOwnershipTransferred(proxyOwner(), newOwner); setUpgradeabilityOwner(newOwner); } /** * @dev Allows the proxy owner to upgrade the current version of the proxy. * @param implementation representing the address of the new implementation to be set. */ function upgradeTo(address implementation) public onlyProxyOwner { _upgradeTo(implementation); } /** * @dev Allows the proxy owner to upgrade the current version of the proxy and call the new implementation * to initialize whatever is needed through a low level call. * @param implementation representing the address of the new implementation to be set. * @param data represents the msg.data to bet sent in the low level call. This parameter may include the function * signature of the implementation to be called with the needed payload */ function upgradeToAndCall(address implementation, bytes data) payable public onlyProxyOwner { upgradeTo(implementation); require(this.call.value(msg.value)(data)); } }
File 2 of 4: RING
pragma solidity ^0.4.23; contract DSAuthority { function canCall( address src, address dst, bytes4 sig ) public view returns (bool); } contract DSAuthEvents { event LogSetAuthority (address indexed authority); event LogSetOwner (address indexed owner); } contract DSAuth is DSAuthEvents { DSAuthority public authority; address public owner; constructor() public { owner = msg.sender; emit LogSetOwner(msg.sender); } function setOwner(address owner_) public auth { owner = owner_; emit LogSetOwner(owner); } function setAuthority(DSAuthority authority_) public auth { authority = authority_; emit LogSetAuthority(authority); } modifier auth { require(isAuthorized(msg.sender, msg.sig)); _; } function isAuthorized(address src, bytes4 sig) internal view returns (bool) { if (src == address(this)) { return true; } else if (src == owner) { return true; } else if (authority == DSAuthority(0)) { return false; } else { return authority.canCall(src, this, sig); } } } contract DSNote { event LogNote( bytes4 indexed sig, address indexed guy, bytes32 indexed foo, bytes32 indexed bar, uint wad, bytes fax ) anonymous; modifier note { bytes32 foo; bytes32 bar; assembly { foo := calldataload(4) bar := calldataload(36) } emit LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data); _; } } contract DSStop is DSNote, DSAuth { bool public stopped; modifier stoppable { require(!stopped); _; } function stop() public auth note { stopped = true; } function start() public auth note { stopped = false; } } contract ERC20Events { event Approval(address indexed src, address indexed guy, uint wad); event Transfer(address indexed src, address indexed dst, uint wad); } contract ERC20 is ERC20Events { function totalSupply() public view returns (uint); function balanceOf(address guy) public view returns (uint); function allowance(address src, address guy) public view returns (uint); function approve(address guy, uint wad) public returns (bool); function transfer(address dst, uint wad) public returns (bool); function transferFrom( address src, address dst, uint wad ) public returns (bool); } contract DSMath { function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x); } function min(uint x, uint y) internal pure returns (uint z) { return x <= y ? x : y; } function max(uint x, uint y) internal pure returns (uint z) { return x >= y ? x : y; } function imin(int x, int y) internal pure returns (int z) { return x <= y ? x : y; } function imax(int x, int y) internal pure returns (int z) { return x >= y ? x : y; } uint constant WAD = 10 ** 18; uint constant RAY = 10 ** 27; function wmul(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, y), WAD / 2) / WAD; } function rmul(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, y), RAY / 2) / RAY; } function wdiv(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, WAD), y / 2) / y; } function rdiv(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, RAY), y / 2) / y; } // This famous algorithm is called "exponentiation by squaring" // and calculates x^n with x as fixed-point and n as regular unsigned. // // It's O(log n), instead of O(n) for naive repeated multiplication. // // These facts are why it works: // // If n is even, then x^n = (x^2)^(n/2). // If n is odd, then x^n = x * x^(n-1), // and applying the equation for even x gives // x^n = x * (x^2)^((n-1) / 2). // // Also, EVM division is flooring and // floor[(n-1) / 2] = floor[n / 2]. // function rpow(uint x, uint n) internal pure returns (uint z) { z = n % 2 != 0 ? x : RAY; for (n /= 2; n != 0; n /= 2) { x = rmul(x, x); if (n % 2 != 0) { z = rmul(z, x); } } } } contract DSTokenBase is ERC20, DSMath { uint256 _supply; mapping (address => uint256) _balances; mapping (address => mapping (address => uint256)) _approvals; constructor(uint supply) public { _balances[msg.sender] = supply; _supply = supply; } function totalSupply() public view returns (uint) { return _supply; } function balanceOf(address src) public view returns (uint) { return _balances[src]; } function allowance(address src, address guy) public view returns (uint) { return _approvals[src][guy]; } function transfer(address dst, uint wad) public returns (bool) { return transferFrom(msg.sender, dst, wad); } function transferFrom(address src, address dst, uint wad) public returns (bool) { if (src != msg.sender) { _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad); } _balances[src] = sub(_balances[src], wad); _balances[dst] = add(_balances[dst], wad); emit Transfer(src, dst, wad); return true; } function approve(address guy, uint wad) public returns (bool) { _approvals[msg.sender][guy] = wad; emit Approval(msg.sender, guy, wad); return true; } } contract DSToken is DSTokenBase(0), DSStop { bytes32 public symbol; uint256 public decimals = 18; // standard token precision. override to customize constructor(bytes32 symbol_) public { symbol = symbol_; } event Mint(address indexed guy, uint wad); event Burn(address indexed guy, uint wad); function approve(address guy) public stoppable returns (bool) { return super.approve(guy, uint(-1)); } function approve(address guy, uint wad) public stoppable returns (bool) { return super.approve(guy, wad); } function transferFrom(address src, address dst, uint wad) public stoppable returns (bool) { if (src != msg.sender && _approvals[src][msg.sender] != uint(-1)) { _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad); } _balances[src] = sub(_balances[src], wad); _balances[dst] = add(_balances[dst], wad); emit Transfer(src, dst, wad); return true; } function push(address dst, uint wad) public { transferFrom(msg.sender, dst, wad); } function pull(address src, uint wad) public { transferFrom(src, msg.sender, wad); } function move(address src, address dst, uint wad) public { transferFrom(src, dst, wad); } function mint(uint wad) public { mint(msg.sender, wad); } function burn(uint wad) public { burn(msg.sender, wad); } function mint(address guy, uint wad) public auth stoppable { _balances[guy] = add(_balances[guy], wad); _supply = add(_supply, wad); emit Mint(guy, wad); } function burn(address guy, uint wad) public auth stoppable { if (guy != msg.sender && _approvals[guy][msg.sender] != uint(-1)) { _approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad); } _balances[guy] = sub(_balances[guy], wad); _supply = sub(_supply, wad); emit Burn(guy, wad); } // Optional token name bytes32 public name = ""; function setName(bytes32 name_) public auth { name = name_; } } /// @title ERC223ReceivingContract - Standard contract implementation for compatibility with ERC223 tokens. interface ERC223ReceivingContract { /// @dev Function that is called when a user or another contract wants to transfer funds. /// @param _from Transaction initiator, analogue of msg.sender /// @param _value Number of tokens to transfer. /// @param _data Data containig a function signature and/or parameters function tokenFallback(address _from, uint256 _value, bytes _data) public; } /// @dev The token controller contract must implement these functions contract TokenController { /// @notice Called when `_owner` sends ether to the MiniMe Token contract /// @param _owner The address that sent the ether to create tokens /// @return True if the ether is accepted, false if it throws function proxyPayment(address _owner, bytes4 sig, bytes data) payable public returns (bool); /// @notice Notifies the controller about a token transfer allowing the /// controller to react if desired /// @param _from The origin of the transfer /// @param _to The destination of the transfer /// @param _amount The amount of the transfer /// @return False if the controller does not authorize the transfer function onTransfer(address _from, address _to, uint _amount) public returns (bool); /// @notice Notifies the controller about an approval allowing the /// controller to react if desired /// @param _owner The address that calls `approve()` /// @param _spender The spender in the `approve()` call /// @param _amount The amount in the `approve()` call /// @return False if the controller does not authorize the approval function onApprove(address _owner, address _spender, uint _amount) public returns (bool); } interface ApproveAndCallFallBack { function receiveApproval(address from, uint256 _amount, address _token, bytes _data) public; } interface ERC223 { function transfer(address to, uint amount, bytes data) public returns (bool ok); function transferFrom(address from, address to, uint256 amount, bytes data) public returns (bool ok); event ERC223Transfer(address indexed from, address indexed to, uint amount, bytes data); } contract ISmartToken { function transferOwnership(address _newOwner) public; function acceptOwnership() public; function disableTransfers(bool _disable) public; function issue(address _to, uint256 _amount) public; function destroy(address _from, uint256 _amount) public; } contract RING is DSToken("RING"), ERC223, ISmartToken { address public newOwner; bool public transfersEnabled = true; // true if transfer/transferFrom are enabled, false if not uint256 public cap; address public controller; // allows execution only when transfers aren't disabled modifier transfersAllowed { assert(transfersEnabled); _; } constructor() public { setName("Evolution Land Global Token"); controller = msg.sender; } ////////// // IOwned Methods ////////// /** @dev allows transferring the contract ownership the new owner still needs to accept the transfer can only be called by the contract owner @param _newOwner new contract owner */ function transferOwnership(address _newOwner) public auth { require(_newOwner != owner); newOwner = _newOwner; } /** @dev used by a new owner to accept an ownership transfer */ function acceptOwnership() public { require(msg.sender == newOwner); owner = newOwner; newOwner = address(0); } ////////// // SmartToken Methods ////////// /** @dev disables/enables transfers can only be called by the contract owner @param _disable true to disable transfers, false to enable them */ function disableTransfers(bool _disable) public auth { transfersEnabled = !_disable; } function issue(address _to, uint256 _amount) public auth stoppable { mint(_to, _amount); } function destroy(address _from, uint256 _amount) public auth stoppable { // do not require allowance _balances[_from] = sub(_balances[_from], _amount); _supply = sub(_supply, _amount); emit Burn(_from, _amount); emit Transfer(_from, 0, _amount); } ////////// // Cap Methods ////////// function changeCap(uint256 _newCap) public auth { require(_newCap >= _supply); cap = _newCap; } ////////// // Controller Methods ////////// /// @notice Changes the controller of the contract /// @param _newController The new controller of the contract function changeController(address _newController) auth { controller = _newController; } /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it /// is approved by `_from` /// @param _from The address holding the tokens being transferred /// @param _to The address of the recipient /// @param _amount The amount of tokens to be transferred /// @return True if the transfer was successful function transferFrom(address _from, address _to, uint256 _amount ) public transfersAllowed returns (bool success) { // Alerts the token controller of the transfer if (isContract(controller)) { if (!TokenController(controller).onTransfer(_from, _to, _amount)) revert(); } success = super.transferFrom(_from, _to, _amount); } /* * ERC 223 * Added support for the ERC 223 "tokenFallback" method in a "transfer" function with a payload. */ function transferFrom(address _from, address _to, uint256 _amount, bytes _data) public transfersAllowed returns (bool success) { // Alerts the token controller of the transfer if (isContract(controller)) { if (!TokenController(controller).onTransfer(_from, _to, _amount)) revert(); } require(super.transferFrom(_from, _to, _amount)); if (isContract(_to)) { ERC223ReceivingContract receiver = ERC223ReceivingContract(_to); receiver.tokenFallback(_from, _amount, _data); } emit ERC223Transfer(_from, _to, _amount, _data); return true; } /* * ERC 223 * Added support for the ERC 223 "tokenFallback" method in a "transfer" function with a payload. * https://github.com/ethereum/EIPs/issues/223 * function transfer(address _to, uint256 _value, bytes _data) public returns (bool success); */ /// @notice Send `_value` tokens to `_to` from `msg.sender` and trigger /// tokenFallback if sender is a contract. /// @dev Function that is called when a user or another contract wants to transfer funds. /// @param _to Address of token receiver. /// @param _amount Number of tokens to transfer. /// @param _data Data to be sent to tokenFallback /// @return Returns success of function call. function transfer( address _to, uint256 _amount, bytes _data) public returns (bool success) { return transferFrom(msg.sender, _to, _amount, _data); } /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on /// its behalf. This is a modified version of the ERC20 approve function /// to be a little bit safer /// @param _spender The address of the account able to transfer the tokens /// @param _amount The amount of tokens to be approved for transfer /// @return True if the approval was successful function approve(address _spender, uint256 _amount) returns (bool success) { // Alerts the token controller of the approve function call if (isContract(controller)) { if (!TokenController(controller).onApprove(msg.sender, _spender, _amount)) revert(); } return super.approve(_spender, _amount); } function mint(address _guy, uint _wad) auth stoppable { require(add(_supply, _wad) <= cap); super.mint(_guy, _wad); emit Transfer(0, _guy, _wad); } function burn(address _guy, uint _wad) auth stoppable { super.burn(_guy, _wad); emit Transfer(_guy, 0, _wad); } /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on /// its behalf, and then a function is triggered in the contract that is /// being approved, `_spender`. This allows users to use their tokens to /// interact with contracts in one function call instead of two /// @param _spender The address of the contract able to transfer the tokens /// @param _amount The amount of tokens to be approved for transfer /// @return True if the function call was successful function approveAndCall(address _spender, uint256 _amount, bytes _extraData ) returns (bool success) { if (!approve(_spender, _amount)) revert(); ApproveAndCallFallBack(_spender).receiveApproval( msg.sender, _amount, this, _extraData ); return true; } /// @dev Internal function to determine if an address is a contract /// @param _addr The address being queried /// @return True if `_addr` is a contract function isContract(address _addr) constant internal returns(bool) { uint size; if (_addr == 0) return false; assembly { size := extcodesize(_addr) } return size>0; } /// @notice The fallback function: If the contract's controller has not been /// set to 0, then the `proxyPayment` method is called which relays the /// ether and creates tokens as described in the token controller contract function () payable { if (isContract(controller)) { if (! TokenController(controller).proxyPayment.value(msg.value)(msg.sender, msg.sig, msg.data)) revert(); } else { revert(); } } ////////// // Safety Methods ////////// /// @notice This method can be used by the owner to extract mistakenly /// sent tokens to this contract. /// @param _token The address of the token contract that you want to recover /// set to 0 in case you want to extract ether. function claimTokens(address _token) public auth { if (_token == 0x0) { address(msg.sender).transfer(address(this).balance); return; } ERC20 token = ERC20(_token); uint balance = token.balanceOf(this); token.transfer(address(msg.sender), balance); emit ClaimedTokens(_token, address(msg.sender), balance); } function withdrawTokens(ERC20 _token, address _to, uint256 _amount) public auth { assert(_token.transfer(_to, _amount)); } //////////////// // Events //////////////// event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount); }
File 3 of 4: GringottsBank
// File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol pragma solidity ^0.4.24; /** * @title ERC20Basic * @dev Simpler version of ERC20 interface * See https://github.com/ethereum/EIPs/issues/179 */ contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address _who) public view returns (uint256); function transfer(address _to, uint256 _value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol pragma solidity ^0.4.24; /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 is ERC20Basic { function allowance(address _owner, address _spender) public view returns (uint256); function transferFrom(address _from, address _to, uint256 _value) public returns (bool); function approve(address _spender, uint256 _value) public returns (bool); event Approval( address indexed owner, address indexed spender, uint256 value ); } // File: @evolutionland/common/contracts/interfaces/ISettingsRegistry.sol pragma solidity ^0.4.24; contract ISettingsRegistry { enum SettingsValueTypes { NONE, UINT, STRING, ADDRESS, BYTES, BOOL, INT } function uintOf(bytes32 _propertyName) public view returns (uint256); function stringOf(bytes32 _propertyName) public view returns (string); function addressOf(bytes32 _propertyName) public view returns (address); function bytesOf(bytes32 _propertyName) public view returns (bytes); function boolOf(bytes32 _propertyName) public view returns (bool); function intOf(bytes32 _propertyName) public view returns (int); function setUintProperty(bytes32 _propertyName, uint _value) public; function setStringProperty(bytes32 _propertyName, string _value) public; function setAddressProperty(bytes32 _propertyName, address _value) public; function setBytesProperty(bytes32 _propertyName, bytes _value) public; function setBoolProperty(bytes32 _propertyName, bool _value) public; function setIntProperty(bytes32 _propertyName, int _value) public; function getValueTypeOf(bytes32 _propertyName) public view returns (uint /* SettingsValueTypes */ ); event ChangeProperty(bytes32 indexed _propertyName, uint256 _type); } // File: @evolutionland/common/contracts/interfaces/IBurnableERC20.sol pragma solidity ^0.4.23; contract IBurnableERC20 { function burn(address _from, uint _value) public; } // File: @evolutionland/common/contracts/interfaces/IMintableERC20.sol pragma solidity ^0.4.23; contract IMintableERC20 { function mint(address _to, uint256 _value) public; } // File: @evolutionland/common/contracts/interfaces/IAuthority.sol pragma solidity ^0.4.24; contract IAuthority { function canCall( address src, address dst, bytes4 sig ) public view returns (bool); } // File: @evolutionland/common/contracts/DSAuth.sol pragma solidity ^0.4.24; contract DSAuthEvents { event LogSetAuthority (address indexed authority); event LogSetOwner (address indexed owner); } /** * @title DSAuth * @dev The DSAuth contract is reference implement of https://github.com/dapphub/ds-auth * But in the isAuthorized method, the src from address(this) is remove for safty concern. */ contract DSAuth is DSAuthEvents { IAuthority public authority; address public owner; constructor() public { owner = msg.sender; emit LogSetOwner(msg.sender); } function setOwner(address owner_) public auth { owner = owner_; emit LogSetOwner(owner); } function setAuthority(IAuthority authority_) public auth { authority = authority_; emit LogSetAuthority(authority); } modifier auth { require(isAuthorized(msg.sender, msg.sig)); _; } modifier onlyOwner() { require(msg.sender == owner); _; } function isAuthorized(address src, bytes4 sig) internal view returns (bool) { if (src == owner) { return true; } else if (authority == IAuthority(0)) { return false; } else { return authority.canCall(src, this, sig); } } } // File: @evolutionland/common/contracts/SettingIds.sol pragma solidity ^0.4.24; /** Id definitions for SettingsRegistry.sol Can be used in conjunction with the settings registry to get properties */ contract SettingIds { bytes32 public constant CONTRACT_RING_ERC20_TOKEN = "CONTRACT_RING_ERC20_TOKEN"; bytes32 public constant CONTRACT_KTON_ERC20_TOKEN = "CONTRACT_KTON_ERC20_TOKEN"; bytes32 public constant CONTRACT_GOLD_ERC20_TOKEN = "CONTRACT_GOLD_ERC20_TOKEN"; bytes32 public constant CONTRACT_WOOD_ERC20_TOKEN = "CONTRACT_WOOD_ERC20_TOKEN"; bytes32 public constant CONTRACT_WATER_ERC20_TOKEN = "CONTRACT_WATER_ERC20_TOKEN"; bytes32 public constant CONTRACT_FIRE_ERC20_TOKEN = "CONTRACT_FIRE_ERC20_TOKEN"; bytes32 public constant CONTRACT_SOIL_ERC20_TOKEN = "CONTRACT_SOIL_ERC20_TOKEN"; bytes32 public constant CONTRACT_OBJECT_OWNERSHIP = "CONTRACT_OBJECT_OWNERSHIP"; bytes32 public constant CONTRACT_TOKEN_LOCATION = "CONTRACT_TOKEN_LOCATION"; bytes32 public constant CONTRACT_LAND_BASE = "CONTRACT_LAND_BASE"; bytes32 public constant CONTRACT_USER_POINTS = "CONTRACT_USER_POINTS"; bytes32 public constant CONTRACT_INTERSTELLAR_ENCODER = "CONTRACT_INTERSTELLAR_ENCODER"; bytes32 public constant CONTRACT_DIVIDENDS_POOL = "CONTRACT_DIVIDENDS_POOL"; bytes32 public constant CONTRACT_TOKEN_USE = "CONTRACT_TOKEN_USE"; bytes32 public constant CONTRACT_REVENUE_POOL = "CONTRACT_REVENUE_POOL"; bytes32 public constant CONTRACT_ERC721_BRIDGE = "CONTRACT_ERC721_BRIDGE"; bytes32 public constant CONTRACT_PET_BASE = "CONTRACT_PET_BASE"; // Cut owner takes on each auction, measured in basis points (1/100 of a percent). // this can be considered as transaction fee. // Values 0-10,000 map to 0%-100% // set ownerCut to 4% // ownerCut = 400; bytes32 public constant UINT_AUCTION_CUT = "UINT_AUCTION_CUT"; // Denominator is 10000 bytes32 public constant UINT_TOKEN_OFFER_CUT = "UINT_TOKEN_OFFER_CUT"; // Denominator is 10000 // Cut referer takes on each auction, measured in basis points (1/100 of a percent). // which cut from transaction fee. // Values 0-10,000 map to 0%-100% // set refererCut to 4% // refererCut = 400; bytes32 public constant UINT_REFERER_CUT = "UINT_REFERER_CUT"; bytes32 public constant CONTRACT_LAND_RESOURCE = "CONTRACT_LAND_RESOURCE"; } // File: contracts/BankSettingIds.sol pragma solidity ^0.4.24; contract BankSettingIds is SettingIds { // depositing X RING for 12 months, interest is about (1 * _unitInterest * X / 10**7) KTON // default: 1000 bytes32 public constant UINT_BANK_UNIT_INTEREST = "UINT_BANK_UNIT_INTEREST"; // penalty multiplier // default: 3 bytes32 public constant UINT_BANK_PENALTY_MULTIPLIER = "UINT_BANK_PENALTY_MULTIPLIER"; } // File: contracts/GringottsBankV2.sol pragma solidity ^0.4.24; contract GringottsBank is DSAuth, BankSettingIds { /* * Events */ event ClaimedTokens(address indexed _token, address indexed _owner, uint _amount); event NewDeposit(uint256 indexed _depositID, address indexed _depositor, uint _value, uint _month, uint _interest); event ClaimedDeposit(uint256 indexed _depositID, address indexed _depositor, uint _value, bool isPenalty, uint penaltyAmount); event TransferDeposit(uint256 indexed _depositID, address indexed _oldDepositor, address indexed _newDepositor); event BurnAndRedeem(uint256 indexed _depositID, address _depositor, uint48 _months, uint48 _startAt, uint64 _unitInterest, uint128 _value, bytes _data); /* * Constants */ uint public constant MONTH = 30 * 1 days; /* * Structs */ struct Deposit { address depositor; uint48 months; // Length of time from the deposit's beginning to end (in months), For now, months must >= 1 and <= 36 uint48 startAt; // when player deposit, timestamp in seconds uint128 value; // amount of ring uint64 unitInterest; bool claimed; } /* * Storages */ bool private singletonLock = false; ISettingsRegistry public registry; mapping (uint256 => Deposit) public deposits; uint public depositCount; mapping (address => uint[]) public userDeposits; // player => totalDepositRING, total number of ring that the player has deposited mapping (address => uint256) public userTotalDeposit; /* * Modifiers */ modifier singletonLockCall() { require(!singletonLock, "Only can call once"); _; singletonLock = true; } modifier canBeStoredWith128Bits(uint256 _value) { require(_value < 340282366920938463463374607431768211455); _; } modifier canBeStoredWith48Bits(uint256 _value) { require(_value < 281474976710656); _; } /** * @dev Bank's constructor which set the token address and unitInterest_ */ constructor () public { // initializeContract(_registry); } /** * @dev Same with constructor, but is used and called by storage proxy as logic contract. * @param _registry - address of SettingsRegistry */ function initializeContract(address _registry) public singletonLockCall { // call Ownable's constructor owner = msg.sender; emit LogSetOwner(msg.sender); registry = ISettingsRegistry(_registry); } function getDeposit(uint _id) public view returns (address, uint128, uint128, uint256, uint256, bool ) { return (deposits[_id].depositor, deposits[_id].value, deposits[_id].months, deposits[_id].startAt, deposits[_id].unitInterest, deposits[_id].claimed); } /** * @dev ERC223 fallback function, make sure to check the msg.sender is from target token contracts * @param _from - person who transfer token in for deposits or claim deposit with penalty KTON. * @param _amount - amount of token. * @param _data - data which indicate the operations. */ function tokenFallback(address _from, uint256 _amount, bytes _data) public { address ring = registry.addressOf(SettingIds.CONTRACT_RING_ERC20_TOKEN); address kryptonite = registry.addressOf(SettingIds.CONTRACT_KTON_ERC20_TOKEN); // deposit entrance if(ring == msg.sender) { uint months = bytesToUint256(_data); _deposit(_from, _amount, months); } // Early Redemption entrance if (kryptonite == msg.sender) { uint _depositID = bytesToUint256(_data); require(_amount >= computePenalty(_depositID), "No enough amount of KTON penalty."); _claimDeposit(_from, _depositID, true, _amount); // burn the KTON transferred in IBurnableERC20(kryptonite).burn(address(this), _amount); } } /** * @dev transfer of deposit from Ethereum network to Darwinia Network, params can be obtained by the function 'getDeposit' * @param _depositID - ID of deposit. * @param _data - receiving address of darwinia network. */ function burnAndRedeem(uint256 _depositID, bytes _data) public { bytes32 darwiniaAddress; assembly { let ptr := mload(0x40) calldatacopy(ptr, 0, calldatasize) darwiniaAddress := mload(add(ptr, 100)) } // Check the validity of the deposit require(deposits[_depositID].claimed == false, "Already claimed"); require(deposits[_depositID].startAt > 0, "Deposit not created."); require(deposits[_depositID].depositor == msg.sender, "Permission denied"); require(_data.length == 32, "The address (Darwinia Network) must be in a 32 bytes hexadecimal format"); require(darwiniaAddress != bytes32(0x0), "Darwinia Network Address can't be empty"); removeUserDepositsByID(_depositID, msg.sender); require(deposits[_depositID].value <= userTotalDeposit[msg.sender], "Subtraction overflow"); userTotalDeposit[msg.sender] -= deposits[_depositID].value; address ring = registry.addressOf(SettingIds.CONTRACT_RING_ERC20_TOKEN); IBurnableERC20(ring).burn(address(this), deposits[_depositID].value); emit BurnAndRedeem( _depositID, deposits[_depositID].depositor, deposits[_depositID].months, deposits[_depositID].startAt, deposits[_depositID].unitInterest, deposits[_depositID].value, _data ); delete deposits[_depositID]; } /** * @dev Deposit for msg sender, require the token approvement ahead. * @param _amount - amount of token. * @param _months - the amount of months that the token will be locked in the deposit. */ function deposit(uint256 _amount, uint256 _months) public { deposit(msg.sender, _amount, _months); } /** * @dev Deposit for benificiary, require the token approvement ahead. * @param _benificiary - benificiary of the deposit, which will get the KTON and RINGs after deposit being claimed. * @param _amount - amount of token. * @param _months - the amount of months that the token will be locked in the deposit. */ function deposit(address _benificiary, uint256 _amount, uint256 _months) public { address ring = registry.addressOf(SettingIds.CONTRACT_RING_ERC20_TOKEN); require(ERC20(ring).transferFrom(msg.sender, address(this), _amount), "RING token tranfer failed."); _deposit(_benificiary, _amount, _months); } function claimDeposit(uint _depositID) public { _claimDeposit(msg.sender, _depositID, false, 0); } function claimDepositWithPenalty(uint _depositID) public { address kryptonite = ERC20(registry.addressOf(SettingIds.CONTRACT_KTON_ERC20_TOKEN)); uint256 _penalty = computePenalty(_depositID); require(ERC20(kryptonite).transferFrom(msg.sender, address(this), _penalty)); _claimDeposit(msg.sender, _depositID, true, _penalty); IBurnableERC20(kryptonite).burn(address(this), _penalty); } function transferDeposit(address _benificiary, uint _depositID) public { require(deposits[_depositID].depositor == msg.sender, "Depositor must be the msg.sender"); require(_benificiary != 0x0, "Benificiary can not be zero"); require(deposits[_depositID].claimed == false, "Already claimed, can not transfer."); // update the depositor of the deposit. deposits[_depositID].depositor = _benificiary; // update the deposit ids of the original user and new user. removeUserDepositsByID(_depositID, msg.sender); userDeposits[_benificiary].push(_depositID); // update the balance of the original depositor and new depositor. require(deposits[_depositID].value <= userTotalDeposit[msg.sender], "Subtraction overflow"); userTotalDeposit[msg.sender] -= deposits[_depositID].value; userTotalDeposit[_benificiary] += deposits[_depositID].value; require(userTotalDeposit[_benificiary] >= deposits[_depositID].value, "Addition overflow"); emit TransferDeposit(_depositID, msg.sender, _benificiary); } // normal Redemption, withdraw at maturity function _claimDeposit(address _depositor, uint _depositID, bool isPenalty, uint _penaltyAmount) internal { address ring = registry.addressOf(SettingIds.CONTRACT_RING_ERC20_TOKEN); require(deposits[_depositID].startAt > 0, "Deposit not created."); require(deposits[_depositID].claimed == false, "Already claimed"); require(deposits[_depositID].depositor == _depositor, "Depositor must match."); if (isPenalty) { require(now - deposits[_depositID].startAt < deposits[_depositID].months * MONTH ); } else { require(now - deposits[_depositID].startAt >= deposits[_depositID].months * MONTH ); } deposits[_depositID].claimed = true; userTotalDeposit[_depositor] -= deposits[_depositID].value; require(ERC20(ring).transfer(_depositor, deposits[_depositID].value)); emit ClaimedDeposit(_depositID, _depositor, deposits[_depositID].value, isPenalty, _penaltyAmount); } /** * @dev deposit actions * @param _depositor - person who deposits * @param _value - depositor wants to deposit how many tokens * @param _month - Length of time from the deposit's beginning to end (in months). */ function _deposit(address _depositor, uint _value, uint _month) canBeStoredWith128Bits(_value) canBeStoredWith128Bits(_month) internal returns (uint _depositId) { address kryptonite = ERC20(registry.addressOf(SettingIds.CONTRACT_KTON_ERC20_TOKEN)); require( _value > 0 ); // because the _value is pass in from token transfer, token transfer will help check, so there should not be overflow issues. require( _month <= 36 && _month >= 1 ); _depositId = depositCount; uint64 _unitInterest = uint64(registry.uintOf(BankSettingIds.UINT_BANK_UNIT_INTEREST)); deposits[_depositId] = Deposit({ depositor: _depositor, value: uint128(_value), months: uint48(_month), startAt: uint48(now), unitInterest: uint48(_unitInterest), claimed: false }); depositCount += 1; userDeposits[_depositor].push(_depositId); userTotalDeposit[_depositor] += _value; require(userTotalDeposit[_depositor] >= _value, "Addition overflow"); // give the player interest immediately uint interest = computeInterest(_value, _month, _unitInterest); IMintableERC20(kryptonite).mint(_depositor, interest); emit NewDeposit(_depositId, _depositor, _value, _month, interest); } /** * @dev compute interst based on deposit amount and deposit time * @param _value - Amount of ring (in deceimal units) * @param _month - Length of time from the deposit's beginning to end (in months). * @param _unitInterest - Parameter of basic interest for deposited RING.(default value is 1000, returns _unitInterest/ 10**7 for one year) */ function computeInterest(uint _value, uint _month, uint _unitInterest) public canBeStoredWith128Bits(_value) canBeStoredWith48Bits(_month) pure returns (uint) { // these two actually mean the multiplier is 1.015 uint numerator = 67 ** _month; uint denominator = 66 ** _month; uint quotient; uint remainder; assembly { quotient := div(numerator, denominator) remainder := mod(numerator, denominator) } // depositing X RING for 12 months, interest is about (1 * _unitInterest * X / 10**7) KTON // and the multiplier is about 3 // ((quotient - 1) * 1000 + remainder * 1000 / denominator) is 197 when _month is 12. return (_unitInterest * uint128(_value)) * ((quotient - 1) * 1000 + remainder * 1000 / denominator) / (197 * 10**7); } function isClaimRequirePenalty(uint _depositID) public view returns (bool) { return (deposits[_depositID].startAt > 0 && !deposits[_depositID].claimed && (now - deposits[_depositID].startAt < deposits[_depositID].months * MONTH )); } function computePenalty(uint _depositID) public view returns (uint256) { require(isClaimRequirePenalty(_depositID), "Claim do not need Penalty."); uint256 monthsDuration = (now - deposits[_depositID].startAt) / MONTH; uint256 penalty = registry.uintOf(BankSettingIds.UINT_BANK_PENALTY_MULTIPLIER) * (computeInterest(deposits[_depositID].value, deposits[_depositID].months, deposits[_depositID].unitInterest) - computeInterest(deposits[_depositID].value, monthsDuration, deposits[_depositID].unitInterest)); return penalty; } function getDepositIds(address _user) public view returns(uint256[]) { return userDeposits[_user]; } function bytesToUint256(bytes _encodedParam) public pure returns (uint256 a) { /* solium-disable-next-line security/no-inline-assembly */ assembly { a := mload(add(_encodedParam, /*BYTES_HEADER_SIZE*/32)) } } /// @notice This method can be used by the owner to extract mistakenly /// sent tokens to this contract. /// @param _token The address of the token contract that you want to recover /// set to 0 in case you want to extract ether. function claimTokens(address _token) public onlyOwner { if (_token == 0x0) { owner.transfer(address(this).balance); return; } ERC20 token = ERC20(_token); uint balance = token.balanceOf(address(this)); token.transfer(owner, balance); emit ClaimedTokens(_token, owner, balance); } function setRegistry(address _registry) public onlyOwner { registry = ISettingsRegistry(_registry); } function removeUserDepositsByID(uint _depositID, address _depositor) private{ // update the deposit ids of the original user and new user. bool found = false; for(uint i = 0 ; i < userDeposits[_depositor].length; i++) { if (!found && userDeposits[_depositor][i] == _depositID){ found = true; delete userDeposits[_depositor][i]; } if (found && i < userDeposits[_depositor].length - 1) { // shifts value to left userDeposits[_depositor][i] = userDeposits[_depositor][i+1]; } } delete userDeposits[_depositor][userDeposits[_depositor].length-1]; //reducing the length userDeposits[_depositor].length--; } }
File 4 of 4: SettingsRegistry
// Dependency file: contracts/interfaces/ISettingsRegistry.sol // pragma solidity ^0.4.24; contract ISettingsRegistry { enum SettingsValueTypes { NONE, UINT, STRING, ADDRESS, BYTES, BOOL, INT } function uintOf(bytes32 _propertyName) public view returns (uint256); function stringOf(bytes32 _propertyName) public view returns (string); function addressOf(bytes32 _propertyName) public view returns (address); function bytesOf(bytes32 _propertyName) public view returns (bytes); function boolOf(bytes32 _propertyName) public view returns (bool); function intOf(bytes32 _propertyName) public view returns (int); function setUintProperty(bytes32 _propertyName, uint _value) public; function setStringProperty(bytes32 _propertyName, string _value) public; function setAddressProperty(bytes32 _propertyName, address _value) public; function setBytesProperty(bytes32 _propertyName, bytes _value) public; function setBoolProperty(bytes32 _propertyName, bool _value) public; function setIntProperty(bytes32 _propertyName, int _value) public; function getValueTypeOf(bytes32 _propertyName) public view returns (uint /* SettingsValueTypes */ ); event ChangeProperty(bytes32 indexed _propertyName, uint256 _type); } // Dependency file: contracts/interfaces/IAuthority.sol // pragma solidity ^0.4.24; contract IAuthority { function canCall( address src, address dst, bytes4 sig ) public view returns (bool); } // Dependency file: contracts/DSAuth.sol // pragma solidity ^0.4.24; // import 'contracts/interfaces/IAuthority.sol'; contract DSAuthEvents { event LogSetAuthority (address indexed authority); event LogSetOwner (address indexed owner); } /** * @title DSAuth * @dev The DSAuth contract is reference implement of https://github.com/dapphub/ds-auth * But in the isAuthorized method, the src from address(this) is remove for safty concern. */ contract DSAuth is DSAuthEvents { IAuthority public authority; address public owner; constructor() public { owner = msg.sender; emit LogSetOwner(msg.sender); } function setOwner(address owner_) public auth { owner = owner_; emit LogSetOwner(owner); } function setAuthority(IAuthority authority_) public auth { authority = authority_; emit LogSetAuthority(authority); } modifier auth { require(isAuthorized(msg.sender, msg.sig)); _; } modifier onlyOwner() { require(msg.sender == owner); _; } function isAuthorized(address src, bytes4 sig) internal view returns (bool) { if (src == owner) { return true; } else if (authority == IAuthority(0)) { return false; } else { return authority.canCall(src, this, sig); } } } // Root file: contracts/SettingsRegistry.sol pragma solidity ^0.4.24; // import "contracts/interfaces/ISettingsRegistry.sol"; // import "contracts/DSAuth.sol"; /** * @title SettingsRegistry * @dev This contract holds all the settings for updating and querying. */ contract SettingsRegistry is ISettingsRegistry, DSAuth { mapping(bytes32 => uint256) public uintProperties; mapping(bytes32 => string) public stringProperties; mapping(bytes32 => address) public addressProperties; mapping(bytes32 => bytes) public bytesProperties; mapping(bytes32 => bool) public boolProperties; mapping(bytes32 => int256) public intProperties; mapping(bytes32 => SettingsValueTypes) public valueTypes; function uintOf(bytes32 _propertyName) public view returns (uint256) { require(valueTypes[_propertyName] == SettingsValueTypes.UINT, "Property type does not match."); return uintProperties[_propertyName]; } function stringOf(bytes32 _propertyName) public view returns (string) { require(valueTypes[_propertyName] == SettingsValueTypes.STRING, "Property type does not match."); return stringProperties[_propertyName]; } function addressOf(bytes32 _propertyName) public view returns (address) { require(valueTypes[_propertyName] == SettingsValueTypes.ADDRESS, "Property type does not match."); return addressProperties[_propertyName]; } function bytesOf(bytes32 _propertyName) public view returns (bytes) { require(valueTypes[_propertyName] == SettingsValueTypes.BYTES, "Property type does not match."); return bytesProperties[_propertyName]; } function boolOf(bytes32 _propertyName) public view returns (bool) { require(valueTypes[_propertyName] == SettingsValueTypes.BOOL, "Property type does not match."); return boolProperties[_propertyName]; } function intOf(bytes32 _propertyName) public view returns (int) { require(valueTypes[_propertyName] == SettingsValueTypes.INT, "Property type does not match."); return intProperties[_propertyName]; } function setUintProperty(bytes32 _propertyName, uint _value) public auth { require( valueTypes[_propertyName] == SettingsValueTypes.NONE || valueTypes[_propertyName] == SettingsValueTypes.UINT, "Property type does not match."); uintProperties[_propertyName] = _value; valueTypes[_propertyName] = SettingsValueTypes.UINT; emit ChangeProperty(_propertyName, uint256(SettingsValueTypes.UINT)); } function setStringProperty(bytes32 _propertyName, string _value) public auth { require( valueTypes[_propertyName] == SettingsValueTypes.NONE || valueTypes[_propertyName] == SettingsValueTypes.STRING, "Property type does not match."); stringProperties[_propertyName] = _value; valueTypes[_propertyName] = SettingsValueTypes.STRING; emit ChangeProperty(_propertyName, uint256(SettingsValueTypes.STRING)); } function setAddressProperty(bytes32 _propertyName, address _value) public auth { require( valueTypes[_propertyName] == SettingsValueTypes.NONE || valueTypes[_propertyName] == SettingsValueTypes.ADDRESS, "Property type does not match."); addressProperties[_propertyName] = _value; valueTypes[_propertyName] = SettingsValueTypes.ADDRESS; emit ChangeProperty(_propertyName, uint256(SettingsValueTypes.ADDRESS)); } function setBytesProperty(bytes32 _propertyName, bytes _value) public auth { require( valueTypes[_propertyName] == SettingsValueTypes.NONE || valueTypes[_propertyName] == SettingsValueTypes.BYTES, "Property type does not match."); bytesProperties[_propertyName] = _value; valueTypes[_propertyName] = SettingsValueTypes.BYTES; emit ChangeProperty(_propertyName, uint256(SettingsValueTypes.BYTES)); } function setBoolProperty(bytes32 _propertyName, bool _value) public auth { require( valueTypes[_propertyName] == SettingsValueTypes.NONE || valueTypes[_propertyName] == SettingsValueTypes.BOOL, "Property type does not match."); boolProperties[_propertyName] = _value; valueTypes[_propertyName] = SettingsValueTypes.BOOL; emit ChangeProperty(_propertyName, uint256(SettingsValueTypes.BOOL)); } function setIntProperty(bytes32 _propertyName, int _value) public auth { require( valueTypes[_propertyName] == SettingsValueTypes.NONE || valueTypes[_propertyName] == SettingsValueTypes.INT, "Property type does not match."); intProperties[_propertyName] = _value; valueTypes[_propertyName] = SettingsValueTypes.INT; emit ChangeProperty(_propertyName, uint256(SettingsValueTypes.INT)); } function getValueTypeOf(bytes32 _propertyName) public view returns (uint256 /* SettingsValueTypes */ ) { return uint256(valueTypes[_propertyName]); } }