Address Contract Verified
Address
0x7a6d98a6CC5c0f0029D6a26E987aA7e04FA5da03
Balance
0 ETH
Nonce
1
Code Size
3112 bytes
Creator
0x19092089...F509 at tx 0xc291bb90...c07b16
Indexed Transactions
0
Contract Bytecode
3112 bytes
0x608060405234801561000f575f5ffd5b5060043610610090575f3560e01c80638da5cb5b116100635780638da5cb5b14610117578063c18402fa14610129578063edca76bc14610164578063f2fde38b14610177578063fc0c546a1461018a575f5ffd5b80632eb4a7ab146100945780632f48ab7d146100b05780636fe3bc08146100ef5780637cb6475914610104575b5f5ffd5b61009d60015481565b6040519081526020015b60405180910390f35b6100d77f0000000000000000000000003bef807ac66522d7759caf07b668a7eb00e1d00e81565b6040516001600160a01b0390911681526020016100a7565b6101026100fd366004610a72565b6101b1565b005b610102610112366004610a9a565b610291565b5f546100d7906001600160a01b031681565b61014f610137366004610ab1565b60026020525f90815260409020805460019091015482565b604080519283526020830191909152016100a7565b610102610172366004610ad1565b6102f5565b610102610185366004610ab1565b6106be565b6100d77f000000000000000000000000044ca854fa227e27e07652b7f6a6b578703f394581565b5f546001600160a01b031633146101e35760405162461bcd60e51b81526004016101da90610b50565b60405180910390fd5b6001600160a01b0382166102255760405162461bcd60e51b81526020600482015260096024820152683d32b9379030b2323960b91b60448201526064016101da565b5f81116102625760405162461bcd60e51b815260206004820152600b60248201526a616d6f756e74207a65726f60a81b60448201526064016101da565b61028d7f0000000000000000000000003bef807ac66522d7759caf07b668a7eb00e1d00e8383610782565b5050565b5f546001600160a01b031633146102ba5760405162461bcd60e51b81526004016101da90610b50565b60018190556040518181527f42cbc405e4dbf1b691e85b9a34b08ecfcf7a9ad9078bf4d645ccfa1fac11c10b9060200160405180910390a150565b6001546103335760405162461bcd60e51b815260206004820152600c60248201526b1c9bdbdd081b9bdd081cd95d60a21b60448201526064016101da565b6040516bffffffffffffffffffffffff193360601b16602082015260348101859052605481018490525f906074016040516020818303038152906040528051906020012090506103b98383808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050600154915084905061088a565b6103f55760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b210383937b7b360991b60448201526064016101da565b335f9081526002602090815260409182902082518084019093528054808452600190910154918301919091528610156104645760405162461bcd60e51b81526020600482015260116024820152701d1bdad95b951bdd185b080f081d5cd959607a1b60448201526064016101da565b80602001518510156104ab5760405162461bcd60e51b815260206004820152601060248201526f1d5cd91d151bdd185b080f081d5cd95960821b60448201526064016101da565b80515f906104b99088610b73565b90505f8260200151876104cc9190610b73565b90505f8211806104db57505f81115b61051a5760405162461bcd60e51b815260206004820152601060248201526f4e6f7468696e6720746f20636c61696d60801b60448201526064016101da565b335f9081526002602052604090208881556001018790558115610563576105637f000000000000000000000000044ca854fa227e27e07652b7f6a6b578703f394533308561089f565b801561066a576040516370a0823160e01b815230600482015281907f0000000000000000000000003bef807ac66522d7759caf07b668a7eb00e1d00e6001600160a01b0316906370a0823190602401602060405180830381865afa1580156105cd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105f19190610b92565b101561063f5760405162461bcd60e51b815260206004820152601d60248201527f696e73756666696369656e74205553445420696e20636f6e747261637400000060448201526064016101da565b61066a7f0000000000000000000000003bef807ac66522d7759caf07b668a7eb00e1d00e3383610782565b60408051838152602081018390529081018990526060810188905233907f40afc61aabce83a502901d9dc66b15d1ee92bfcc1f4f56923b8434dcd041e19f9060800160405180910390a25050505050505050565b5f546001600160a01b031633146106e75760405162461bcd60e51b81526004016101da90610b50565b6001600160a01b0381166107295760405162461bcd60e51b81526020600482015260096024820152683d32b9379030b2323960b91b60448201526064016101da565b5f80546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35f80546001600160a01b0319166001600160a01b0392909216919091179055565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291515f928392908716916107dd9190610ba9565b5f604051808303815f865af19150503d805f8114610816576040519150601f19603f3d011682016040523d82523d5f602084013e61081b565b606091505b50915091508180156108455750805115806108455750808060200190518101906108459190610bbf565b6108835760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064016101da565b5050505050565b5f8261089685846109b5565b14949350505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291515f928392908816916109029190610ba9565b5f604051808303815f865af19150503d805f811461093b576040519150601f19603f3d011682016040523d82523d5f602084013e610940565b606091505b509150915081801561096a57508051158061096a57508080602001905181019061096a9190610bbf565b6109ad5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064016101da565b505050505050565b5f81815b8451811015610a4d575f8582815181106109d5576109d5610bde565b60200260200101519050808311610a17576040805160208101859052908101829052606001604051602081830303815290604052805190602001209250610a44565b60408051602081018390529081018490526060016040516020818303038152906040528051906020012092505b506001016109b9565b5090505b92915050565b80356001600160a01b0381168114610a6d575f5ffd5b919050565b5f5f60408385031215610a83575f5ffd5b610a8c83610a57565b946020939093013593505050565b5f60208284031215610aaa575f5ffd5b5035919050565b5f60208284031215610ac1575f5ffd5b610aca82610a57565b9392505050565b5f5f5f5f60608587031215610ae4575f5ffd5b8435935060208501359250604085013567ffffffffffffffff811115610b08575f5ffd5b8501601f81018713610b18575f5ffd5b803567ffffffffffffffff811115610b2e575f5ffd5b8760208260051b8401011115610b42575f5ffd5b949793965060200194505050565b6020808252600990820152682737ba1037bbb732b960b91b604082015260600190565b81810381811115610a5157634e487b7160e01b5f52601160045260245ffd5b5f60208284031215610ba2575f5ffd5b5051919050565b5f82518060208501845e5f920191825250919050565b5f60208284031215610bcf575f5ffd5b81518015158114610aca575f5ffd5b634e487b7160e01b5f52603260045260245ffdfea264697066735822122030e65dec40803e020df1973698b8db104cd7a52b8c9193edfda979b39548c98464736f6c634300081f0033
Verified Source Code Full Match
Compiler: v0.8.31+commit.fd3a2265
EVM: prague
Optimization: Yes (200 runs)
MerkleRefund.sol 188 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @notice 简单的 ERC20 接口(保留返回值定义,但不会直接用它)
interface IERC20 {
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}
/// @notice MerkleProof 库(简化版)
library MerkleProof {
function verify(
bytes32[] memory proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
function processProof(
bytes32[] memory proof,
bytes32 leaf
) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
bytes32 proofElement = proof[i];
if (computedHash <= proofElement) {
computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
} else {
computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
}
}
return computedHash;
}
}
/// @notice Ownable
contract Ownable {
address public owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
owner = msg.sender;
emit OwnershipTransferred(address(0), msg.sender);
}
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), "zero addr");
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
contract MerkleRefund is Ownable {
IERC20 public immutable token = IERC20(0x044Ca854fA227E27E07652B7F6A6b578703F3945); // 用户要扣的代币
IERC20 public immutable usdt = IERC20(0x3bEF807ac66522d7759cAf07b668a7eb00e1D00E); // 合约退给用户的 USDT(以太坊 CUSDT)
bytes32 public merkleRoot;
struct UserUsage {
uint256 tokenUsed;
uint256 usdtUsed;
}
mapping(address => UserUsage) public userUsage;
event MerkleRootSet(bytes32 root);
event Refunded(
address indexed user,
uint256 tokenIn,
uint256 usdtOut,
uint256 tokenTotalAllocated,
uint256 usdtTotalAllocated
);
constructor(bytes32 _root) {
merkleRoot = _root;
emit MerkleRootSet(_root);
}
/// @notice 设置 Merkle Root(如需多次更新可以去掉 require 限制)
function setMerkleRoot(bytes32 _root) external onlyOwner {
merkleRoot = _root;
emit MerkleRootSet(_root);
}
/**
* @notice 用户退款
* @param tokenTotal 用户在 Merkle 中的 token 总额度
* @param usdtTotal 用户在 Merkle 中的 usdt 总额度
* @param merkleProof Merkle 证明
*
* 叶子: keccak256(abi.encodePacked(user, tokenTotal, usdtTotal))
*/
function refund(
uint256 tokenTotal,
uint256 usdtTotal,
bytes32[] calldata merkleProof
) external {
require(merkleRoot != bytes32(0), "root not set");
bytes32 leaf = keccak256(
abi.encodePacked(msg.sender, tokenTotal, usdtTotal)
);
require(MerkleProof.verify(merkleProof, merkleRoot, leaf), "Invalid proof");
UserUsage memory usage = userUsage[msg.sender];
require(tokenTotal >= usage.tokenUsed, "tokenTotal < used");
require(usdtTotal >= usage.usdtUsed, "usdtTotal < used");
uint256 tokenToUse = tokenTotal - usage.tokenUsed;
uint256 usdtToUse = usdtTotal - usage.usdtUsed;
require(tokenToUse > 0 || usdtToUse > 0, "Nothing to claim");
// 先更新状态,防止重入
userUsage[msg.sender].tokenUsed = tokenTotal;
userUsage[msg.sender].usdtUsed = usdtTotal;
// 从用户扣 token
if (tokenToUse > 0) {
_safeTransferFrom(token, msg.sender, address(this), tokenToUse);
}
// 合约给用户转 USDT
if (usdtToUse > 0) {
require(
usdt.balanceOf(address(this)) >= usdtToUse,
"insufficient USDT in contract"
);
_safeTransfer(usdt, msg.sender, usdtToUse);
}
emit Refunded(
msg.sender,
tokenToUse,
usdtToUse,
tokenTotal,
usdtTotal
);
}
// ================= SafeERC20 风格函数 =================
function _safeTransfer(
IERC20 _token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = address(_token).call(
abi.encodeWithSelector(_token.transfer.selector, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TRANSFER_FAILED"
);
}
function _safeTransferFrom(
IERC20 _token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = address(_token).call(
abi.encodeWithSelector(_token.transferFrom.selector, from, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TRANSFER_FROM_FAILED"
);
}
/// @notice 管理员提取合约内的 USDT(紧急或清算使用)
function adminWithdrawUSDT(address to, uint256 amount) external onlyOwner {
require(to != address(0), "zero addr");
require(amount > 0, "amount zero");
_safeTransfer(usdt, to, amount);
}
}
Read Contract
merkleRoot 0x2eb4a7ab → bytes32
owner 0x8da5cb5b → address
token 0xfc0c546a → address
usdt 0x2f48ab7d → address
userUsage 0xc18402fa → uint256, uint256
Write Contract 4 functions
These functions modify contract state and require a wallet transaction to execute.
adminWithdrawUSDT 0x6fe3bc08
address to
uint256 amount
refund 0xedca76bc
uint256 tokenTotal
uint256 usdtTotal
bytes32[] merkleProof
setMerkleRoot 0x7cb64759
bytes32 _root
transferOwnership 0xf2fde38b
address newOwner
Token Balances (1)
View Transfers →Recent Transactions
No transactions found for this address