Transaction Hash:
Block:
11158104 at Oct-30-2020 12:23:25 PM +UTC
Transaction Fee:
0.00165150004819077 ETH
$3.10
Gas Used:
33,030 Gas / 50.000001459 Gwei
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0xB3b7874F...A3505D8d4
Miner
| (Babel Pool) | 15,817.380541980438766055 Eth | 15,817.382193480486956825 Eth | 0.00165150004819077 | |
0xBac5ACE9...c97b9eCAF |
2.773216620868211027 Eth
Nonce: 7090
|
2.771565120820020257 Eth
Nonce: 7091
| 0.00165150004819077 |
Execution Trace
0x7ee8ab2a8d890c000acc87bf6e22e2ad383e23ce.865a6b4f( )
0x63faee0a2cbcedc0102575c6ff17da38b1565c22.7ecc6397( )
-
RocketPoolToken.balanceOf( _owner=0x70EA56e46266f0137BAc6B75710e3546f47C855D ) => ( balance=259191114488087569480588 )
-
pragma solidity ^0.4.11; contract Owned { address public owner; address public newOwner; event OwnershipTransferred(address indexed _from, address indexed _to); function Owned() { owner = msg.sender; } modifier onlyOwner { require(msg.sender == owner); _; } function transferOwnership(address _newOwner) onlyOwner { newOwner = _newOwner; } function acceptOwnership() { require(msg.sender == newOwner); OwnershipTransferred(owner, newOwner); owner = newOwner; } } contract Token { uint256 public totalSupply; function balanceOf(address _owner) constant returns (uint256 balance); function transfer(address _to, uint256 _value) returns (bool success); function transferFrom(address _from, address _to, uint256 _value) returns (bool success); function approve(address _spender, uint256 _value) returns (bool success); function allowance(address _owner, address _spender) constant returns (uint256 remaining); event Transfer(address indexed _from, address indexed _to, uint256 _value); event Approval(address indexed _owner, address indexed _spender, uint256 _value); } library SafeMath { function mul(uint256 a, uint256 b) internal returns (uint256) { uint256 c = a * b; assert(a == 0 || c / a == b); return c; } function div(uint256 a, uint256 b) internal returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function sub(uint256 a, uint256 b) internal returns (uint256) { assert(b <= a); return a - b; } function add(uint256 a, uint256 b) internal returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } function max64(uint64 a, uint64 b) internal constant returns (uint64) { return a >= b ? a : b; } function min64(uint64 a, uint64 b) internal constant returns (uint64) { return a < b ? a : b; } function max256(uint256 a, uint256 b) internal constant returns (uint256) { return a >= b ? a : b; } function min256(uint256 a, uint256 b) internal constant returns (uint256) { return a < b ? a : b; } } contract SalesAgentInterface { /**** Properties ***********/ // Main contract token address address tokenContractAddress; // Contributions per address mapping (address => uint256) public contributions; // Total ETH contributed uint256 public contributedTotal; /// @dev Only allow access from the main token contract modifier onlyTokenContract() {_;} /*** Events ****************/ event Contribute(address _agent, address _sender, uint256 _value); event FinaliseSale(address _agent, address _sender, uint256 _value); event Refund(address _agent, address _sender, uint256 _value); event ClaimTokens(address _agent, address _sender, uint256 _value); /*** Methods ****************/ /// @dev The address used for the depositAddress must checkin with the contract to verify it can interact with this contract, must happen or it won't accept funds function getDepositAddressVerify() public; /// @dev Get the contribution total of ETH from a contributor /// @param _owner The owners address function getContributionOf(address _owner) constant returns (uint256 balance); } /* ERC 20 token */ contract StandardToken is Token { function transfer(address _to, uint256 _value) returns (bool success) { if (balances[msg.sender] >= _value && _value > 0) { balances[msg.sender] -= _value; balances[_to] += _value; Transfer(msg.sender, _to, _value); return true; } else { return false; } } function transferFrom(address _from, address _to, uint256 _value) returns (bool success) { if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) { balances[_to] += _value; balances[_from] -= _value; allowed[_from][msg.sender] -= _value; Transfer(_from, _to, _value); return true; } else { return false; } } function balanceOf(address _owner) constant returns (uint256 balance) { return balances[_owner]; } function approve(address _spender, uint256 _value) returns (bool success) { allowed[msg.sender][_spender] = _value; Approval(msg.sender, _spender, _value); return true; } function allowance(address _owner, address _spender) constant returns (uint256 remaining) { return allowed[_owner][_spender]; } mapping (address => uint256) balances; mapping (address => mapping (address => uint256)) allowed; } /// @title The main Rocket Pool Token (RPL) contract /// @author David Rugendyke - http://www.rocketpool.net /***************************************************************** * This is the main Rocket Pool Token (RPL) contract. It features * Smart Agent compatibility. The Sale Agent is a new type of * contract that can authorise the minting of tokens on behalf of * the traditional ERC20 token contract. This allows you to * distribute your ICO tokens through multiple Sale Agents, * at various times, of various token quantities and of varying * fund targets. Once you’ve written a new Sale Agent contract, * you can register him with the main ERC20 token contract, * he’s then permitted to sell it’s tokens on your behalf using * guidelines such as the amount of tokens he’s allowed to sell, * the maximum ether he’s allowed to raise, the start block and * end blocks he’s allowed to sell between and more. /****************************************************************/ contract RocketPoolToken is StandardToken, Owned { /**** Properties ***********/ string public name = "Rocket Pool"; string public symbol = "RPL"; string public version = "1.0"; // Set our token units uint8 public constant decimals = 18; uint256 public exponent = 10**uint256(decimals); uint256 public totalSupply = 0; // The total of tokens currently minted by sales agent contracts uint256 public totalSupplyCap = 18 * (10**6) * exponent; // 18 Million tokens /**** Libs *****************/ using SafeMath for uint; /*** Sale Addresses *********/ mapping (address => SalesAgent) private salesAgents; // Our contract addresses of our sales contracts address[] private salesAgentsAddresses; // Keep an array of all our sales agent addresses for iteration /*** Structs ***************/ struct SalesAgent { // These are contract addresses that are authorised to mint tokens address saleContractAddress; // Address of the contract bytes32 saleContractType; // Type of the contract ie. presale, crowdsale uint256 targetEthMax; // The max amount of ether the agent is allowed raise uint256 targetEthMin; // The min amount of ether to raise to consider this contracts sales a success uint256 tokensLimit; // The maximum amount of tokens this sale contract is allowed to distribute uint256 tokensMinted; // The current amount of tokens minted by this agent uint256 minDeposit; // The minimum deposit amount allowed uint256 maxDeposit; // The maximum deposit amount allowed uint256 startBlock; // The start block when allowed to mint tokens uint256 endBlock; // The end block when to finish minting tokens address depositAddress; // The address that receives the ether for that sale contract bool depositAddressCheckedIn; // The address that receives the ether for that sale contract must check in with its sale contract to verify its a valid address that can interact bool finalised; // Has this sales contract been completed and the ether sent to the deposit address? bool exists; // Check to see if the mapping exists } /*** Events ****************/ event MintToken(address _agent, address _address, uint256 _value); event SaleFinalised(address _agent, address _address, uint256 _value); /*** Tests *****************/ event FlagUint(uint256 flag); event FlagAddress(address flag); /*** Modifiers *************/ /// @dev Only allow access from the latest version of a sales contract modifier isSalesContract(address _sender) { // Is this an authorised sale contract? assert(salesAgents[_sender].exists == true); _; } /**** Methods ***********/ /// @dev RPL Token Init function RocketPoolToken() {} // @dev General validation for a sales agent contract receiving a contribution, additional validation can be done in the sale contract if required // @param _value The value of the contribution in wei // @return A boolean that indicates if the operation was successful. function validateContribution(uint256 _value) isSalesContract(msg.sender) returns (bool) { // Get an instance of the sale agent contract SalesAgentInterface saleAgent = SalesAgentInterface(msg.sender); // Did they send anything from a proper address? assert(_value > 0); // Check the depositAddress has been verified by the account holder assert(salesAgents[msg.sender].depositAddressCheckedIn == true); // Check if we're ok to receive contributions, have we started? assert(block.number > salesAgents[msg.sender].startBlock); // Already ended? Or if the end block is 0, it's an open ended sale until finalised by the depositAddress assert(block.number < salesAgents[msg.sender].endBlock || salesAgents[msg.sender].endBlock == 0); // Is it above the min deposit amount? assert(_value >= salesAgents[msg.sender].minDeposit); // Is it below the max deposit allowed? assert(_value <= salesAgents[msg.sender].maxDeposit); // No contributions if the sale contract has finalised assert(salesAgents[msg.sender].finalised == false); // Does this deposit put it over the max target ether for the sale contract? assert(saleAgent.contributedTotal().add(_value) <= salesAgents[msg.sender].targetEthMax); // All good return true; } // @dev General validation for a sales agent contract that requires the user claim the tokens after the sale has finished // @param _sender The address sent the request // @return A boolean that indicates if the operation was successful. function validateClaimTokens(address _sender) isSalesContract(msg.sender) returns (bool) { // Get an instance of the sale agent contract SalesAgentInterface saleAgent = SalesAgentInterface(msg.sender); // Must have previously contributed assert(saleAgent.getContributionOf(_sender) > 0); // Sale contract completed assert(block.number > salesAgents[msg.sender].endBlock); // All good return true; } // @dev Mint the Rocket Pool Tokens (RPL) // @param _to The address that will receive the minted tokens. // @param _amount The amount of tokens to mint. // @return A boolean that indicates if the operation was successful. function mint(address _to, uint _amount) isSalesContract(msg.sender) returns (bool) { // Check if we're ok to mint new tokens, have we started? // We dont check for the end block as some sale agents mint tokens during the sale, and some after its finished (proportional sales) assert(block.number > salesAgents[msg.sender].startBlock); // Check the depositAddress has been verified by the designated account holder that will receive the funds from that agent assert(salesAgents[msg.sender].depositAddressCheckedIn == true); // No minting if the sale contract has finalised assert(salesAgents[msg.sender].finalised == false); // Check we don't exceed the assigned tokens of the sale agent assert(salesAgents[msg.sender].tokensLimit >= salesAgents[msg.sender].tokensMinted.add(_amount)); // Verify ok balances and values assert(_amount > 0); // Check we don't exceed the supply limit assert(totalSupply.add(_amount) <= totalSupplyCap); // Ok all good, automatically checks for overflow with safeMath balances[_to] = balances[_to].add(_amount); // Add to the total minted for that agent, automatically checks for overflow with safeMath salesAgents[msg.sender].tokensMinted = salesAgents[msg.sender].tokensMinted.add(_amount); // Add to the overall total minted, automatically checks for overflow with safeMath totalSupply = totalSupply.add(_amount); // Fire the event MintToken(msg.sender, _to, _amount); // Fire the transfer event Transfer(0x0, _to, _amount); // Completed return true; } /// @dev Returns the amount of tokens that can still be minted function getRemainingTokens() public constant returns(uint256) { return totalSupplyCap.sub(totalSupply); } /// @dev Set the address of a new crowdsale/presale contract agent if needed, usefull for upgrading /// @param _saleAddress The address of the new token sale contract /// @param _saleContractType Type of the contract ie. presale, crowdsale, quarterly /// @param _targetEthMin The min amount of ether to raise to consider this contracts sales a success /// @param _targetEthMax The max amount of ether the agent is allowed raise /// @param _tokensLimit The maximum amount of tokens this sale contract is allowed to distribute /// @param _minDeposit The minimum deposit amount allowed /// @param _maxDeposit The maximum deposit amount allowed /// @param _startBlock The start block when allowed to mint tokens /// @param _endBlock The end block when to finish minting tokens /// @param _depositAddress The address that receives the ether for that sale contract function setSaleAgentContract( address _saleAddress, string _saleContractType, uint256 _targetEthMin, uint256 _targetEthMax, uint256 _tokensLimit, uint256 _minDeposit, uint256 _maxDeposit, uint256 _startBlock, uint256 _endBlock, address _depositAddress ) // Only the owner can register a new sale agent public onlyOwner { // Valid addresses? assert(_saleAddress != 0x0 && _depositAddress != 0x0); // Must have some available tokens assert(_tokensLimit > 0 && _tokensLimit <= totalSupplyCap); // Make sure the min deposit is less than or equal to the max assert(_minDeposit <= _maxDeposit); // Add the new sales contract salesAgents[_saleAddress] = SalesAgent({ saleContractAddress: _saleAddress, saleContractType: sha3(_saleContractType), targetEthMin: _targetEthMin, targetEthMax: _targetEthMax, tokensLimit: _tokensLimit, tokensMinted: 0, minDeposit: _minDeposit, maxDeposit: _maxDeposit, startBlock: _startBlock, endBlock: _endBlock, depositAddress: _depositAddress, depositAddressCheckedIn: false, finalised: false, exists: true }); // Store our agent address so we can iterate over it if needed salesAgentsAddresses.push(_saleAddress); } /// @dev Sets the contract sale agent process as completed, that sales agent is now retired function setSaleContractFinalised(address _sender) isSalesContract(msg.sender) public returns(bool) { // Get an instance of the sale agent contract SalesAgentInterface saleAgent = SalesAgentInterface(msg.sender); // Finalise the crowdsale funds assert(!salesAgents[msg.sender].finalised); // The address that will receive this contracts deposit, should match the original senders assert(salesAgents[msg.sender].depositAddress == _sender); // If the end block is 0, it means an open ended crowdsale, once it's finalised, the end block is set to the current one if (salesAgents[msg.sender].endBlock == 0) { salesAgents[msg.sender].endBlock = block.number; } // Not yet finished? assert(block.number >= salesAgents[msg.sender].endBlock); // Not enough raised? assert(saleAgent.contributedTotal() >= salesAgents[msg.sender].targetEthMin); // We're done now salesAgents[msg.sender].finalised = true; // Fire the event SaleFinalised(msg.sender, _sender, salesAgents[msg.sender].tokensMinted); // All good return true; } /// @dev Verifies if the current address matches the depositAddress /// @param _verifyAddress The address to verify it matches the depositAddress given for the sales agent function setSaleContractDepositAddressVerified(address _verifyAddress) isSalesContract(msg.sender) public { // Check its verified assert(salesAgents[msg.sender].depositAddress == _verifyAddress && _verifyAddress != 0x0); // Ok set it now salesAgents[msg.sender].depositAddressCheckedIn = true; } /// @dev Returns true if this sales contract has finalised /// @param _salesAgentAddress The address of the token sale agent contract function getSaleContractIsFinalised(address _salesAgentAddress) constant isSalesContract(_salesAgentAddress) public returns(bool) { return salesAgents[_salesAgentAddress].finalised; } /// @dev Returns the min target amount of ether the contract wants to raise /// @param _salesAgentAddress The address of the token sale agent contract function getSaleContractTargetEtherMin(address _salesAgentAddress) constant isSalesContract(_salesAgentAddress) public returns(uint256) { return salesAgents[_salesAgentAddress].targetEthMin; } /// @dev Returns the max target amount of ether the contract can raise /// @param _salesAgentAddress The address of the token sale agent contract function getSaleContractTargetEtherMax(address _salesAgentAddress) constant isSalesContract(_salesAgentAddress) public returns(uint256) { return salesAgents[_salesAgentAddress].targetEthMax; } /// @dev Returns the min deposit amount of ether /// @param _salesAgentAddress The address of the token sale agent contract function getSaleContractDepositEtherMin(address _salesAgentAddress) constant isSalesContract(_salesAgentAddress) public returns(uint256) { return salesAgents[_salesAgentAddress].minDeposit; } /// @dev Returns the max deposit amount of ether /// @param _salesAgentAddress The address of the token sale agent contract function getSaleContractDepositEtherMax(address _salesAgentAddress) constant isSalesContract(_salesAgentAddress) public returns(uint256) { return salesAgents[_salesAgentAddress].maxDeposit; } /// @dev Returns the address where the sale contracts ether will be deposited /// @param _salesAgentAddress The address of the token sale agent contract function getSaleContractDepositAddress(address _salesAgentAddress) constant isSalesContract(_salesAgentAddress) public returns(address) { return salesAgents[_salesAgentAddress].depositAddress; } /// @dev Returns the true if the sale agents deposit address has been verified /// @param _salesAgentAddress The address of the token sale agent contract function getSaleContractDepositAddressVerified(address _salesAgentAddress) constant isSalesContract(_salesAgentAddress) public returns(bool) { return salesAgents[_salesAgentAddress].depositAddressCheckedIn; } /// @dev Returns the start block for the sale agent /// @param _salesAgentAddress The address of the token sale agent contract function getSaleContractStartBlock(address _salesAgentAddress) constant isSalesContract(_salesAgentAddress) public returns(uint256) { return salesAgents[_salesAgentAddress].startBlock; } /// @dev Returns the start block for the sale agent /// @param _salesAgentAddress The address of the token sale agent contract function getSaleContractEndBlock(address _salesAgentAddress) constant isSalesContract(_salesAgentAddress) public returns(uint256) { return salesAgents[_salesAgentAddress].endBlock; } /// @dev Returns the max tokens for the sale agent /// @param _salesAgentAddress The address of the token sale agent contract function getSaleContractTokensLimit(address _salesAgentAddress) constant isSalesContract(_salesAgentAddress) public returns(uint256) { return salesAgents[_salesAgentAddress].tokensLimit; } /// @dev Returns the token total currently minted by the sale agent /// @param _salesAgentAddress The address of the token sale agent contract function getSaleContractTokensMinted(address _salesAgentAddress) constant isSalesContract(_salesAgentAddress) public returns(uint256) { return salesAgents[_salesAgentAddress].tokensMinted; } }