账户
0x9b...90e3
0x9b...90E3

0x9b...90E3

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.8.13+commit.abaa5c0e
语言
Solidity
合同源代码
文件 1 的 1:Destributor.sol
// File: undefined/test/MerkleProof.sol



pragma solidity 0.8.13;

/**
 * @dev These functions deal with verification of Merkle trees (hash trees),
 */
library MerkleProof {
  /// @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree defined by `root`.
  /// For this, a `proof` must be provided, containing sibling hashes on the branch from the leaf to the root of the 
  /// tree. Each pair of leaves and each pair of pre-images are assumed to be sorted.
  /// @param p Array of merkle proofs
  /// @param r Merkle root
  /// @param l Candidate 'leaf' of the merkle tree
  function verify(bytes32[] memory p, bytes32 r, bytes32 l) internal pure returns (bool) {
    uint256 len = p.length;
    bytes32 hash = l;

    for (uint256 i = 0; i < len; i++) {
      bytes32 element = p[i];

      if (hash <= element) {
        // Hash(current computed hash + current element of the proof)
        hash = keccak256(abi.encodePacked(hash, element));
      } else {
        // Hash(current element of the proof + current computed hash)
        hash = keccak256(abi.encodePacked(element, hash));
      }
    }

    // Check if the computed hash (root) is equal to the provided root
    return hash == r;
  }
}

// File: undefined/test/Interfaces.sol



pragma solidity 0.8.13;

interface Erc20 {
	function transfer(address, uint256) external returns (bool);
	function balanceOf(address) external returns (uint256);
	function transferFrom(address, address, uint256) external returns (bool);
}

// File: undefined/test/Destributor.sol



pragma solidity 0.8.13;



contract Destributor {
  mapping (uint256 => bytes32) public merkleRoot;
  mapping (uint256 => mapping (uint256 => uint256)) private claims;
  mapping (uint256 => bool) private cancelled;

  uint256 public distribution;

  address public immutable token;
  address public admin;
  bool public paused;

  event Distribute(bytes32 merkleRoot, uint256 distribution);
  event Claim(uint256 index, address owner, uint256 amount);

  /// @param t Address of an ERC20 token
  /// @param r Initial merkle root
  constructor(address t, bytes32 r) {
    admin = msg.sender;
    token = t;
    merkleRoot[0] = r;
  }

  /// @notice Generate a new distribution, cancelling the would be current one
  /// @param f The address of the wallet containing tokens to distribute
  /// @param t The address that will receive any currently remaining distributions (will normally be the same as from)
  /// @param a The amount of tokens in the new distribution
  /// @param r The merkle root associated with the new distribution
  function distribute(address f, address t, uint256 a, bytes32 r) external authorized(admin) returns (bool) {
    // remove curent token balance
    Erc20 erc = Erc20(token);
    uint256 balance = erc.balanceOf(address(this));
    erc.transfer(t, balance);
        
    // transfer enough tokens for new distribution
    erc.transferFrom(f, address(this), a);

    // we are working with the distribution, eventually bumping it...
    uint256 current = distribution;
        
    // cancel the (to-be) previous distribution
    cancelled[current] = true;

    current++;
    // add the new distribution's merkleRoot
    merkleRoot[current] = r;

    distribution = current;

    // unpause redemptions
    pause(false);

    emit Distribute(r, current);        

    return true;
  }

  /// @param i An index which to construct a possible claim from
  /// @param d The distribution to check for a claim
  function claimed(uint256 i, uint256 d) public view returns (bool) {
    uint256 wordIndex = i / 256;
    uint256 bitIndex = i % 256;
    uint256 word = claims[d][wordIndex];
    uint256 mask = (1 << bitIndex);

    return word & mask == mask;
  }

  /// @param i An index which to construct a claim from
  /// @param o Owner address of the token being transferred
  /// @param a Amount being transferred
  /// @param p array of merkle proofs
  function claim(uint256 i, address o, uint256 a, bytes32[] calldata p) external returns (bool) {
    require(!paused, 'claiming is paused');
    require(!claimed(i, distribution), 'distribution claimed');
    require(!cancelled[distribution], 'distribution cancelled');

    // Verify the merkle proof...
    bytes32 node = keccak256(abi.encodePacked(i, o, a));
    require(MerkleProof.verify(p, merkleRoot[distribution], node), 'invalid proof');

    // Mark it claimed...
    uint256 wordIndex = i / 256;
    uint256 bitIndex = i % 256;
    claims[distribution][wordIndex] = claims[distribution][wordIndex] | (1 << bitIndex);
    
    // send the token...
    require(Erc20(token).transfer(o, a), 'transfer failed.');

    emit Claim(i, o, a);

    return true;
  }

  /// @param a Address of a new admin
  function transferAdmin(address a) external authorized(admin) returns (bool) {
    admin = a;

    return true;
  }

  /// @notice Allows admin to pause or unpause claims
  /// @param b Boolean value to set paused to
  function pause(bool b) public authorized(admin) returns (bool) {
    paused = b;
    return true;
  }

  modifier authorized(address a) {
    require(msg.sender == a, 'sender must be authorized');
    _;
  }
}
设置
{
  "compilationTarget": {
    "Destributor.sol": "Destributor"
  },
  "evmVersion": "london",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 10000
  },
  "remappings": []
}
ABI
[{"inputs":[{"internalType":"address","name":"t","type":"address"},{"internalType":"bytes32","name":"r","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"distribution","type":"uint256"}],"name":"Distribute","type":"event"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"},{"internalType":"address","name":"o","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"bytes32[]","name":"p","type":"bytes32[]"}],"name":"claim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"},{"internalType":"uint256","name":"d","type":"uint256"}],"name":"claimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"}],"name":"distribute","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"distribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"pause","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"transferAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]