false
false
0

Contract Address Details

0x1000000000000000000000000000000000000001

Contract Name
StateConnector
Creator
Balance
0 FLR ( )
Tokens
Fetching tokens...
Transactions
401 Transactions
Transfers
0 Transfers
Gas Used
15,945,072
Last Balance Update
21659615
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
StateConnector




Optimization enabled
true
Compiler version
v0.7.6+commit.7338295f




Optimization runs
200
Verified at
2022-07-13T20:49:30.263090Z

./contracts/genesis/implementation/StateConnector.sol

// (c) 2021, Flare Networks Limited. All rights reserved.
// Please see the file LICENSE for licensing terms.

// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;

contract StateConnector {

//====================================================================
// Data Structures
//====================================================================

    // unused old storage slots (genesis contract upgrade)
    uint256[16] private gap;

    // Signalling block.coinbase value
    address public constant SIGNAL_COINBASE = address(0x00000000000000000000000000000000000DEaD1);
    // November 5th, 2021
    uint256 public constant BUFFER_TIMESTAMP_OFFSET = 1636070400 seconds;
    // Amount of time a buffer is active before cycling to the next one
    uint256 public constant BUFFER_WINDOW = 90 seconds;
    // {Requests, Votes, Reveals}
    uint256 public constant TOTAL_STORED_BUFFERS = 3;
    // Store a proof for one week
    uint256 public constant TOTAL_STORED_PROOFS = (1 weeks) / BUFFER_WINDOW;
    // Cold wallet address => Hot wallet address
    mapping(address => address) public attestorAddressMapping;

    //=======================
    // VOTING DATA STRUCTURES
    //=======================

    // Voting round consists of 4 sequential buffer windows: collect, commit, reveal, finalize
    // Round ID is the buffer number of the window of the collect phase
    struct Vote { // Struct for Vote in buffer number 'N'
        // Hash of the Merkle root (+ random number and msg.sender) that contains valid requests from 'Round ID = N-1' 
        bytes32 commitHash;
        // Merkle root for 'Round ID = N-2' used for commitHash in buffer number 'N-1'
        bytes32 merkleRoot;
        // Random number for 'Round ID = N-2' used for commitHash in buffer number 'N-1'
        bytes32 randomNumber;
    }
    struct Buffers {
        // {Requests, Votes, Reveals}
        Vote[TOTAL_STORED_BUFFERS] votes;
        // The latest buffer number that this account has voted on, used for determining relevant votes
        uint256 latestVote;
    }
    mapping(address => Buffers) public buffers;

    //=============================
    // MERKLE PROOF DATA STRUCTURES
    //=============================

    // The total number of buffers that have elapsed over time such that the latest buffer
    // has been proven using finaliseRound()
    uint256 public totalBuffers;
    // The proven merkle roots for each Round ID,
    // accessed using: Round ID % TOTAL_STORED_PROOFS
    // within one week of proving the merkle root.
    bytes32[TOTAL_STORED_PROOFS] public merkleRoots;

//====================================================================
// Events
//====================================================================

    event AttestationRequest(
        address sender,
        uint256 timestamp,
        bytes data
    );

    event RoundFinalised(
        uint256 indexed roundId,
        bytes32 merkleRoot
    );

//====================================================================
// Constructor
//====================================================================

    constructor() {
        /* empty block */
    }

//====================================================================
// Functions
//====================================================================  

    function updateAttestorAddressMapping(address _updatedAddress) external {
        attestorAddressMapping[msg.sender] = _updatedAddress;
    }

    function requestAttestations(bytes calldata _data) external {
        emit AttestationRequest(msg.sender, block.timestamp, _data); 
    }

    function submitAttestation(
        uint256 _bufferNumber,
        bytes32 _commitHash,
        bytes32 _merkleRoot,
        bytes32 _randomNumber
    ) 
        external returns (
            bool _isInitialBufferSlot
        )
    {
        require(_bufferNumber == (block.timestamp - BUFFER_TIMESTAMP_OFFSET) / BUFFER_WINDOW, "wrong bufferNumber");
        buffers[msg.sender].latestVote = _bufferNumber;
        buffers[msg.sender].votes[_bufferNumber % TOTAL_STORED_BUFFERS] = Vote(
            _commitHash,
            _merkleRoot,
            _randomNumber
        );
        // Determine if this is the first attestation submitted in a new buffer round.
        // If so, the golang code will automatically finalise the previous round using finaliseRound()
        if (_bufferNumber > totalBuffers) {
            return true;
        }
        return false;
    }

    function getAttestation(uint256 _bufferNumber) external view returns (bytes32 _merkleRoot) {
        address attestor = attestorAddressMapping[msg.sender];
        if (attestor == address(0)) {
            attestor = msg.sender;
        }
        require(_bufferNumber > 1);
        uint256 prevBufferNumber = _bufferNumber - 1;
        require(buffers[attestor].latestVote >= prevBufferNumber);
        bytes32 commitHash = buffers[attestor].votes[(prevBufferNumber - 1) % TOTAL_STORED_BUFFERS].commitHash;
        _merkleRoot = buffers[attestor].votes[prevBufferNumber % TOTAL_STORED_BUFFERS].merkleRoot;
        bytes32 randomNumber = buffers[attestor].votes[prevBufferNumber % TOTAL_STORED_BUFFERS].randomNumber;
        require(commitHash == keccak256(abi.encode(_merkleRoot, randomNumber, attestor)));
    }

    function finaliseRound(uint256 _bufferNumber, bytes32 _merkleRoot) external {
        require(_bufferNumber > 3);
        require(_bufferNumber == (block.timestamp - BUFFER_TIMESTAMP_OFFSET) / BUFFER_WINDOW);
        require(_bufferNumber > totalBuffers);
        // The following region can only be called from the golang code
        if (msg.sender == block.coinbase && block.coinbase == SIGNAL_COINBASE) {
            totalBuffers = _bufferNumber;
            merkleRoots[(_bufferNumber - 3) % TOTAL_STORED_PROOFS] = _merkleRoot;
            emit RoundFinalised(_bufferNumber - 3, _merkleRoot);
        }
    }

    function lastFinalizedRoundId() external view returns (uint256 _roundId) {
        require(totalBuffers >= 3, "totalBuffers < 3");
        return totalBuffers - 3;
    }

    function merkleRoot(uint256 _roundId) external view returns (bytes32) {
        require(totalBuffers >= 3, "totalBuffers < 3");
        require(_roundId <= totalBuffers - 3, "not finalized");
        require(_roundId < TOTAL_STORED_PROOFS || _roundId > totalBuffers - 3 - TOTAL_STORED_PROOFS, "expired");
        return merkleRoots[_roundId % TOTAL_STORED_PROOFS];
    }
}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"event","name":"AttestationRequest","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false},{"type":"bytes","name":"data","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"RoundFinalised","inputs":[{"type":"uint256","name":"roundId","internalType":"uint256","indexed":true},{"type":"bytes32","name":"merkleRoot","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BUFFER_TIMESTAMP_OFFSET","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BUFFER_WINDOW","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"SIGNAL_COINBASE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"TOTAL_STORED_BUFFERS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"TOTAL_STORED_PROOFS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"attestorAddressMapping","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"latestVote","internalType":"uint256"}],"name":"buffers","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"finaliseRound","inputs":[{"type":"uint256","name":"_bufferNumber","internalType":"uint256"},{"type":"bytes32","name":"_merkleRoot","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"_merkleRoot","internalType":"bytes32"}],"name":"getAttestation","inputs":[{"type":"uint256","name":"_bufferNumber","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_roundId","internalType":"uint256"}],"name":"lastFinalizedRoundId","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"merkleRoot","inputs":[{"type":"uint256","name":"_roundId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"merkleRoots","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"requestAttestations","inputs":[{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"_isInitialBufferSlot","internalType":"bool"}],"name":"submitAttestation","inputs":[{"type":"uint256","name":"_bufferNumber","internalType":"uint256"},{"type":"bytes32","name":"_commitHash","internalType":"bytes32"},{"type":"bytes32","name":"_merkleRoot","internalType":"bytes32"},{"type":"bytes32","name":"_randomNumber","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalBuffers","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateAttestorAddressMapping","inputs":[{"type":"address","name":"_updatedAddress","internalType":"address"}]}]
              

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101005760003560e01c8063c2f56d4c11610097578063ec7424a011610066578063ec7424a014610284578063f417c9d81461028c578063f5f59a4a14610294578063f64b6fda1461029c57610100565b8063c2f56d4c146101f0578063cfd1fdad14610216578063dd86215714610259578063eaebf6d31461026157610100565b80635f8c940d116100d35780635f8c940d1461018157806371c5ecb11461018957806371e24574146101a65780637ff6faa6146101cc57610100565b8063273c463b1461010557806329be4db21461012d5780633c70b3571461015c5780634b8a125f14610179575b600080fd5b61012b6004803603602081101561011b57600080fd5b50356001600160a01b031661030c565b005b61014a6004803603602081101561014357600080fd5b503561033b565b60408051918252519081900360200190f35b61014a6004803603602081101561017257600080fd5b503561049a565b61014a61059c565b61014a6105a4565b61014a6004803603602081101561019f57600080fd5b50356105a9565b61014a600480360360208110156101bc57600080fd5b50356001600160a01b03166105c1565b6101d46105d6565b604080516001600160a01b039092168252519081900360200190f35b6101d46004803603602081101561020657600080fd5b50356001600160a01b03166105dd565b6102456004803603608081101561022c57600080fd5b50803590602081013590604081013590606001356105f8565b604080519115158252519081900360200190f35b61014a6106d4565b61012b6004803603604081101561027757600080fd5b508035906020013561072c565b61014a6107d0565b61014a6107d6565b61014a6107dc565b61012b600480360360208110156102b257600080fd5b8101906020810181356401000000008111156102cd57600080fd5b8201836020820111156102df57600080fd5b8035906020019184600183028401116401000000008311171561030157600080fd5b5090925090506107e1565b33600090815260106020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b336000908152601060205260408120546001600160a01b03168061035c5750335b6001831161036957600080fd5b6001600160a01b03811660009081526011602052604090206009015460001984019081111561039757600080fd5b6001600160a01b03821660009081526011602052604081206003600019840106600381106103c157fe5b600390810291909101546001600160a01b0385166000908152601160205260409020909250908306600381106103f357fe5b60030201600101549350600060116000856001600160a01b03166001600160a01b031681526020019081526020016000206000016003848161043157fe5b066003811061043c57fe5b6003020160020154905084818560405160200180848152602001838152602001826001600160a01b03168152602001935050505060405160208183030381529060405280519060200120821461049157600080fd5b50505050919050565b6000600360125410156104e7576040805162461bcd60e51b815260206004820152601060248201526f746f74616c42756666657273203c203360801b604482015290519081900360640190fd5b600360125403821115610531576040805162461bcd60e51b815260206004820152600d60248201526c1b9bdd08199a5b985b1a5e9959609a1b604482015290519081900360640190fd5b611a408210806105475750601254611a42190182115b610582576040805162461bcd60e51b8152602060048201526007602482015266195e1c1a5c995960ca1b604482015290519081900360640190fd5b6013611a408306611a40811061059457fe5b015492915050565b636184740081565b600381565b601381611a4081106105ba57600080fd5b0154905081565b60116020526000908152604090206009015481565b620dead181565b6010602052600090815260409020546001600160a01b031681565b6000605a63618473ff19420104851461064d576040805162461bcd60e51b81526020600482015260126024820152713bb937b73390313ab33332b9273ab6b132b960711b604482015290519081900360640190fd5b336000818152601160208181526040808420600981018b905581516060810183528a81528084018a9052918201889052949093525290600387066003811061069157fe5b600302016000820151816000015560208201518160010155604082015181600201559050506012548511156106c8575060016106cc565b5060005b949350505050565b600060036012541015610721576040805162461bcd60e51b815260206004820152601060248201526f746f74616c42756666657273203c203360801b604482015290519081900360640190fd5b506012546002190190565b6003821161073957600080fd5b605a63618473ff19420104821461074f57600080fd5b601254821161075d57600080fd5b334114801561076e575041620dead1145b156107cc576012829055806013611a40600219850106611a40811061078f57fe5b01556040805182815290516002198401917f8ffd19aa79a62d0764e560d21b1245698310783be781d7d80b38233d4d7d288c919081900360200190a25b5050565b60125481565b611a4081565b605a81565b7f7cbc6812801238dea8eb58356bb62b95dbce8dc28498aa30e7d2c6873ed36cc73342848460405180856001600160a01b03168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a1505056fea26469706673582212201835668a4aedf7b8dd6cb953219e7b126f41acff165aaa41023acd8f3dd8edf064736f6c63430007060033