Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Add Signer | 18830208 | 324 days ago | IN | 0 ETH | 0.00247304 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
18826941 | 324 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Minimal Proxy Contract for 0x8890451c3f26507d1309822a0c15c02df2a03a30
Contract Name:
LinkdropMastercopy
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2023-08-11 */ // SPDX-License-Identifier: GPL-3.0 // pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // Dependency file: contracts/interfaces/ILinkdropERC20.sol // pragma solidity >=0.6.0 <0.8.0; interface ILinkdropERC20 { function verifyLinkdropSignerSignature ( uint _weiAmount, address _tokenAddress, uint _tokenAmount, uint _expiration, address _linkId, bytes calldata _signature ) external view returns (bool); function checkClaimParams ( uint _weiAmount, address _tokenAddress, uint _tokenAmount, uint _expiration, address _linkId, bytes calldata _linkdropSignerSignature, address _receiver, bytes calldata _receiverSignature ) external view returns (bool); function claim ( uint _weiAmount, address _tokenAddress, uint _tokenAmount, uint _expiration, address _linkId, bytes calldata _linkdropSignerSignature, address payable _receiver, bytes calldata _receiverSignature ) external payable returns (bool); } // Dependency file: contracts/interfaces/IERC20Mintable.sol // pragma solidity >=0.6.0 <0.8.0; interface IERC20Mintable { function mint(address to, uint256 amount) external; } // Dependency file: contracts/interfaces/IFeeManager.sol // pragma solidity >=0.6.0 <0.8.0; interface IFeeManager { function isWhitelisted(address _addr) external view returns (bool); function whitelist(address _addr) external returns (bool); function cancelWhitelist(address _addr) external returns (bool); function changeFeeReceiver(address payable _addr) external returns (bool); function updateFee(uint _fee) external returns (bool); function updateClaimerFee(uint _claimerFee) external returns (bool); function withdraw() external returns (bool); function calculateFee( address _linkdropMaster, address _tokenAddress, address _receiver) external view returns (uint); function feeReceiver() external view returns (address payable); } // Dependency file: contracts/interfaces/ILinkdropCommon.sol // pragma solidity >=0.6.0 <0.8.0; interface ILinkdropCommon { function initialize ( address _owner, address payable _linkdropMaster, uint _version, uint _chainId, uint _claimPattern ) external returns (bool); function isClaimedLink(address _linkId) external view returns (bool); function isCanceledLink(address _linkId) external view returns (bool); function paused() external view returns (bool); function cancel(address _linkId) external returns (bool); function withdraw() external returns (bool); function pause() external returns (bool); function unpause() external returns (bool); function addSigner(address _linkdropSigner) external payable returns (bool); function removeSigner(address _linkdropSigner) external returns (bool); function destroy() external; function getLinkdropMaster() external view returns (address); function getMasterCopyVersion() external view returns (uint); function verifyReceiverSignature( address _linkId, address _receiver, bytes calldata _signature ) external view returns (bool); receive() external payable; } // Dependency file: contracts/interfaces/ILinkdropFactory.sol // pragma solidity >=0.6.0 <0.8.0; interface ILinkdropFactory { function feeManager() external view returns (address); } // Dependency file: contracts/storage/LinkdropStorage.sol // pragma solidity >=0.6.0 <0.8.0; // import "contracts/interfaces/ILinkdropFactory.sol"; contract LinkdropStorage { // Address of contract deploying proxies ILinkdropFactory public factory; // Address corresponding to linkdrop master key address payable public linkdropMaster; // Version of mastercopy contract uint public version; // Network id uint public chainId; // Indicates whether an address corresponds to linkdrop signing key mapping (address => bool) public isLinkdropSigner; // Indicates who the link is claimed to mapping (address => address) public claimedTo; // Indicates whether the link is canceled or not mapping (address => bool) internal _canceled; // Indicates whether the initializer function has been called or not bool public initialized; // Indicates whether the contract is paused or not bool internal _paused; // Indicates which pattern the campaign will use (mint on claim, transfer pre-minted tokens, etc) uint public claimPattern; // Events event Canceled(address linkId); event Claimed(address indexed linkId, uint ethAmount, address indexed token, uint tokenAmount, address receiver); event ClaimedERC721(address indexed linkId, uint ethAmount, address indexed nft, uint tokenId, address receiver); event ClaimedERC1155(address indexed linkId, uint ethAmount, address indexed nft, uint tokenId, uint tokenAmount, address receiver); event Paused(); event Unpaused(); event AddedSigningKey(address linkdropSigner); event RemovedSigningKey(address linkdropSigner); } // Dependency file: openzeppelin-solidity/contracts/cryptography/ECDSA.sol // pragma solidity >=0.6.0 <0.8.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { revert("ECDSA: invalid signature length"); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return recover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover-bytes32-bytes-} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value"); require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value"); // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); require(signer != address(0), "ECDSA: invalid signature"); return signer; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`] * JSON-RPC method. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } } // Dependency file: openzeppelin-solidity/contracts/math/SafeMath.sol // pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } } // Dependency file: contracts/linkdrop/LinkdropCommon.sol // pragma solidity >=0.6.0 <0.8.0; // import "contracts/interfaces/ILinkdropCommon.sol"; // import "contracts/storage/LinkdropStorage.sol"; // import "openzeppelin-solidity/contracts/cryptography/ECDSA.sol"; // import "openzeppelin-solidity/contracts/math/SafeMath.sol"; // import "contracts/interfaces/ILinkdropFactory.sol"; // import "contracts/interfaces/IFeeManager.sol"; contract LinkdropCommon is ILinkdropCommon, LinkdropStorage { /** * @dev Function called only once to set factory, linkdrop master, contract version and chain id * @param _factory Factory address * @param _linkdropMaster Address corresponding to master key * @param _version Contract version * @param _chainId Network id * @param _claimPattern which pattern the campaign will use (mint on claim, transfer pre-minted tokens, etc) */ function initialize ( address _factory, address payable _linkdropMaster, uint _version, uint _chainId, uint _claimPattern ) public override returns (bool) { require(!initialized, "LINKDROP_PROXY_CONTRACT_ALREADY_INITIALIZED"); require(_claimPattern == 0 || _claimPattern == 1, "UNKNOWN_TRANSFER_PATTERN"); factory = ILinkdropFactory(_factory); linkdropMaster = _linkdropMaster; isLinkdropSigner[linkdropMaster] = true; version = _version; chainId = _chainId; claimPattern = _claimPattern; initialized = true; return true; } modifier onlyLinkdropMaster() { require(msg.sender == linkdropMaster, "ONLY_LINKDROP_MASTER"); _; } modifier onlyLinkdropMasterOrFactory() { require (msg.sender == linkdropMaster || msg.sender == address(factory), "ONLY_LINKDROP_MASTER_OR_FACTORY"); _; } modifier onlyFactory() { require(msg.sender == address(factory), "ONLY_FACTORY"); _; } modifier whenNotPaused() { require(!paused(), "LINKDROP_PROXY_CONTRACT_PAUSED"); _; } /** * @dev Get linkdrop master for this contract * @return linkdrop master address */ function getLinkdropMaster() public override view returns (address) { return linkdropMaster; } /** * @dev Indicates whether a link is claimed or not * @param _linkId Address corresponding to link key * @return True if claimed */ function isClaimedLink(address _linkId) public override view returns (bool) { return claimedTo[_linkId] != address(0); } /** * @dev Indicates whether a link is canceled or not * @param _linkId Address corresponding to link key * @return True if canceled */ function isCanceledLink(address _linkId) public override view returns (bool) { return _canceled[_linkId]; } /** * @dev Indicates whether a contract is paused or not * @return True if paused */ function paused() public override view returns (bool) { return _paused; } /** * @dev Function to cancel a link, can only be called by linkdrop master * @param _linkId Address corresponding to link key * @return True if success */ function cancel(address _linkId) external override onlyLinkdropMaster returns (bool) { require(!isClaimedLink(_linkId), "LINK_CLAIMED"); _canceled[_linkId] = true; emit Canceled(_linkId); return true; } /** * @dev Function to withdraw eth to linkdrop master, can only be called by linkdrop master * @return True if success */ function withdraw() external override onlyLinkdropMaster returns (bool) { linkdropMaster.transfer(address(this).balance); return true; } /** * @dev Function to pause contract, can only be called by linkdrop master * @return True if success */ function pause() external override onlyLinkdropMaster whenNotPaused returns (bool) { _paused = true; emit Paused(); return true; } /** * @dev Function to unpause contract, can only be called by linkdrop master * @return True if success */ function unpause() external override onlyLinkdropMaster returns (bool) { require(paused(), "LINKDROP_CONTRACT_ALREADY_UNPAUSED"); _paused = false; emit Unpaused(); return true; } /** * @dev Function to add new signing key, can only be called by linkdrop master or factory * @param _linkdropSigner Address corresponding to signing key * @return True if success */ function addSigner(address _linkdropSigner) external override payable onlyLinkdropMasterOrFactory returns (bool) { require(_linkdropSigner != address(0), "INVALID_LINKDROP_SIGNER_ADDRESS"); isLinkdropSigner[_linkdropSigner] = true; return true; } /** * @dev Function to remove signing key, can only be called by linkdrop master * @param _linkdropSigner Address corresponding to signing key * @return True if success */ function removeSigner(address _linkdropSigner) external override onlyLinkdropMaster returns (bool) { require(_linkdropSigner != address(0), "INVALID_LINKDROP_SIGNER_ADDRESS"); isLinkdropSigner[_linkdropSigner] = false; return true; } /** * @dev Function to destroy this contract, can only be called by factory or linkdrop master * Withdraws all the remaining ETH to linkdrop master */ function destroy() external override onlyLinkdropMasterOrFactory { selfdestruct(linkdropMaster); } /** * @dev Function for other contracts to be able to fetch the mastercopy version * @return Master copy version */ function getMasterCopyVersion() external override view returns (uint) { return version; } /** * @dev Function to verify linkdrop receiver's signature * @param _linkId Address corresponding to link key * @param _receiver Address of linkdrop receiver * @param _signature ECDSA signature of linkdrop receiver * @return True if signed with link key */ function verifyReceiverSignature ( address _linkId, address _receiver, bytes memory _signature ) public view override returns (bool) { bytes32 prefixedHash = ECDSA.toEthSignedMessageHash(keccak256(abi.encodePacked(_receiver))); address signer = ECDSA.recover(prefixedHash, _signature); return signer == _linkId; } function _payFee( address _tokenAddress, address payable _receiver ) internal { // should send fees to fee receiver IFeeManager feeManager = IFeeManager(factory.feeManager()); uint fee = feeManager.calculateFee(linkdropMaster, _tokenAddress, address(_receiver)); // if claim is not sponsored // verify that exactly the amount of ETH was provided to pay the fees if (_receiver == address(tx.origin)) { require(msg.value == fee, "TX_VALUE_FEE_MISMATCH"); } if (fee > 0) { address payable feeReceiver = feeManager.feeReceiver(); feeReceiver.transfer(fee); } } /** * @dev Fallback function to accept ETH */ receive() external override payable {} } // Dependency file: contracts/linkdrop/LinkdropERC20.sol // pragma solidity >=0.6.0 <0.8.0; // import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; // import "contracts/interfaces/ILinkdropERC20.sol"; // import "contracts/interfaces/IERC20Mintable.sol"; // import "contracts/interfaces/IFeeManager.sol"; // import "contracts/linkdrop/LinkdropCommon.sol"; contract LinkdropERC20 is ILinkdropERC20, LinkdropCommon { using SafeMath for uint; /** * @dev Function to verify linkdrop signer's signature * @param _weiAmount Amount of wei to be claimed * @param _tokenAddress Token address * @param _tokenAmount Amount of tokens to be claimed (in atomic value) * @param _expiration Unix timestamp of link expiration time * @param _linkId Address corresponding to link key * @param _signature ECDSA signature of linkdrop signer * @return True if signed with linkdrop signer's private key */ function verifyLinkdropSignerSignature ( uint _weiAmount, address _tokenAddress, uint _tokenAmount, uint _expiration, address _linkId, bytes memory _signature ) public view override returns (bool) { bytes32 prefixedHash = ECDSA.toEthSignedMessageHash ( keccak256 ( abi.encodePacked ( _weiAmount, _tokenAddress, _tokenAmount, _expiration, version, chainId, _linkId, address(this) ) ) ); address signer = ECDSA.recover(prefixedHash, _signature); return isLinkdropSigner[signer]; } /** * @dev Function to verify claim params and make sure the link is not claimed or canceled * @param _weiAmount Amount of wei to be claimed * @param _tokenAddress Token address * @param _tokenAmount Amount of tokens to be claimed (in atomic value) * @param _expiration Unix timestamp of link expiration time * @param _linkId Address corresponding to link key * @param _linkdropSignerSignature ECDSA signature of linkdrop signer * @param _receiver Address of linkdrop receiver * @param _receiverSignature ECDSA signature of linkdrop receiver, * @return True if success */ function checkClaimParams ( uint _weiAmount, address _tokenAddress, uint _tokenAmount, uint _expiration, address _linkId, bytes memory _linkdropSignerSignature, address _receiver, bytes memory _receiverSignature ) public view override whenNotPaused returns (bool) { // If tokens are being claimed if (_tokenAmount > 0) { require(_tokenAddress != address(0), "INVALID_TOKEN_ADDRESS"); } // Make sure link is not claimed require(isClaimedLink(_linkId) == false, "LINK_CLAIMED"); // Make sure link is not canceled require(isCanceledLink(_linkId) == false, "LINK_CANCELED"); // Make sure link is not expired require(_expiration >= now, "LINK_EXPIRED"); // Make sure eth amount is available for this contract require(address(this).balance >= _weiAmount, "INSUFFICIENT_ETHERS"); // Make sure tokens are available for this contract if (_tokenAddress != address(0) && claimPattern != 1) { require ( IERC20(_tokenAddress).balanceOf(linkdropMaster) >= _tokenAmount, "INSUFFICIENT_TOKENS" ); require ( IERC20(_tokenAddress).allowance(linkdropMaster, address(this)) >= _tokenAmount, "INSUFFICIENT_ALLOWANCE" ); } // Verify that link key is legit and signed by linkdrop signer require ( verifyLinkdropSignerSignature ( _weiAmount, _tokenAddress, _tokenAmount, _expiration, _linkId, _linkdropSignerSignature ), "INVALID_LINKDROP_SIGNER_SIGNATURE" ); // Verify that receiver address is signed by ephemeral key assigned to claim link (link key) require ( verifyReceiverSignature(_linkId, _receiver, _receiverSignature), "INVALID_RECEIVER_SIGNATURE" ); return true; } /** * @dev Function to claim ETH and/or ERC20 tokens. Can only be called when contract is not paused * @param _weiAmount Amount of wei to be claimed * @param _tokenAddress Token address * @param _tokenAmount Amount of tokens to be claimed (in atomic value) * @param _expiration Unix timestamp of link expiration time * @param _linkId Address corresponding to link key * @param _linkdropSignerSignature ECDSA signature of linkdrop signer * @param _receiver Address of linkdrop receiver * @param _receiverSignature ECDSA signature of linkdrop receiver * @return True if success */ function claim ( uint _weiAmount, address _tokenAddress, uint _tokenAmount, uint _expiration, address _linkId, bytes calldata _linkdropSignerSignature, address payable _receiver, bytes calldata _receiverSignature ) external override payable whenNotPaused returns (bool) { // Make sure params are valid require ( checkClaimParams ( _weiAmount, _tokenAddress, _tokenAmount, _expiration, _linkId, _linkdropSignerSignature, _receiver, _receiverSignature ), "INVALID_CLAIM_PARAMS" ); // Mark link as claimed claimedTo[_linkId] = _receiver; // Make sure transfer succeeds require(_transferFunds(_weiAmount, _tokenAddress, _tokenAmount, _receiver), "TRANSFER_FAILED"); // Emit claim event emit Claimed(_linkId, _weiAmount, _tokenAddress, _tokenAmount, _receiver); return true; } /** * @dev Internal function to mint or transfer ERC20 tokens depending on the transfer pattern chosen for the contract. * @param _tokenAddress Token address * @param _tokenAmount Amount of tokens to be claimed (in atomic value) * @param _receiver Address to transfer funds to */ function _mintOrTransferTokens( address _tokenAddress, uint _tokenAmount, address payable _receiver ) internal { if (claimPattern == 0) { // transfer` IERC20(_tokenAddress).transferFrom(linkdropMaster, _receiver, _tokenAmount); return; } else if (claimPattern == 1) { IERC20Mintable(_tokenAddress).mint(_receiver, _tokenAmount); return; } revert("UNKNOWN_TRANSFER_PATTERN"); } /** * @dev Internal function to transfer ethers and/or ERC20 tokens * @param _weiAmount Amount of wei to be claimed * @param _tokenAddress Token address * @param _tokenAmount Amount of tokens to be claimed (in atomic value) * @param _receiver Address to transfer funds to * @return True if success */ function _transferFunds ( uint _weiAmount, address _tokenAddress, uint _tokenAmount, address payable _receiver ) internal returns (bool) { // pay Linkdrop fee if needed _payFee(_tokenAddress, _receiver); // Transfer ether if (_weiAmount > 0) { _receiver.transfer(_weiAmount); } // mint or transfer tokens if (_tokenAmount > 0) { _mintOrTransferTokens( _tokenAddress, _tokenAmount, _receiver); } return true; } } // Dependency file: /Users/mikhail/Documents/soft/linkdrop/linkdrop-contracts/contracts/interfaces/ILinkdropERC721.sol // pragma solidity >=0.6.0 <0.8.0; interface ILinkdropERC721 { function verifyLinkdropSignerSignatureERC721 ( uint _weiAmount, address _nftAddress, uint _tokenId, uint _expiration, address _linkId, bytes calldata _signature ) external view returns (bool); function verifyReceiverSignatureERC721 ( address _linkId, address _receiver, bytes calldata _signature ) external view returns (bool); function checkClaimParamsERC721 ( uint _weiAmount, address _nftAddress, uint _tokenId, uint _expiration, address _linkId, bytes calldata _linkdropSignerSignature, address _receiver, bytes calldata _receiverSignature ) external view returns (bool); function claimERC721 ( uint _weiAmount, address _nftAddress, uint _tokenId, uint _expiration, address _linkId, bytes calldata _linkdropSignerSignature, address payable _receiver, bytes calldata _receiverSignature ) external payable returns (bool); } // Dependency file: contracts/interfaces/IERC721Mintable.sol // pragma solidity >=0.6.0 <0.8.0; interface IERC721Mintable { function safeMint(address to) external; } // Dependency file: openzeppelin-solidity/contracts/introspection/IERC165.sol // pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // Dependency file: openzeppelin-solidity/contracts/token/ERC721/IERC721.sol // pragma solidity >=0.6.2 <0.8.0; // import "openzeppelin-solidity/contracts/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; } // Dependency file: contracts/linkdrop/LinkdropERC721.sol // pragma solidity >=0.6.0 <0.8.0; // import "contracts/linkdrop/LinkdropCommon.sol"; // import "/Users/mikhail/Documents/soft/linkdrop/linkdrop-contracts/contracts/interfaces/ILinkdropERC721.sol"; // import "contracts/interfaces/IERC721Mintable.sol"; // import "contracts/interfaces/IFeeManager.sol"; // import "openzeppelin-solidity/contracts/token/ERC721/IERC721.sol"; contract LinkdropERC721 is ILinkdropERC721, LinkdropCommon { using SafeMath for uint; /** * @dev Function to verify linkdrop signer's signature * @param _weiAmount Amount of wei to be claimed * @param _nftAddress NFT address * @param _tokenId Token id to be claimed * @param _expiration Unix timestamp of link expiration time * @param _linkId Address corresponding to link key * @param _signature ECDSA signature of linkdrop signer * @return True if signed with linkdrop signer's private key */ function verifyLinkdropSignerSignatureERC721 ( uint _weiAmount, address _nftAddress, uint _tokenId, uint _expiration, address _linkId, bytes memory _signature ) public view override returns (bool) { bytes32 prefixedHash = ECDSA.toEthSignedMessageHash ( keccak256 ( abi.encodePacked ( _weiAmount, _nftAddress, _tokenId, _expiration, version, chainId, _linkId, address(this) ) ) ); address signer = ECDSA.recover(prefixedHash, _signature); return isLinkdropSigner[signer]; } /** * @dev Function to verify linkdrop receiver's signature * @param _linkId Address corresponding to link key * @param _receiver Address of linkdrop receiver * @param _signature ECDSA signature of linkdrop receiver * @return True if signed with link key */ function verifyReceiverSignatureERC721 ( address _linkId, address _receiver, bytes memory _signature ) public view override returns (bool) { bytes32 prefixedHash = ECDSA.toEthSignedMessageHash(keccak256(abi.encodePacked(_receiver))); address signer = ECDSA.recover(prefixedHash, _signature); return signer == _linkId; } /** * @dev Function to verify claim params and make sure the link is not claimed or canceled * @param _weiAmount Amount of wei to be claimed * @param _nftAddress NFT address * @param _tokenId Token id to be claimed * @param _expiration Unix timestamp of link expiration time * @param _linkId Address corresponding to link key * @param _linkdropSignerSignature ECDSA signature of linkdrop signer * @param _receiver Address of linkdrop receiver * @param _receiverSignature ECDSA signature of linkdrop receiver * @return True if success */ function checkClaimParamsERC721 ( uint _weiAmount, address _nftAddress, uint _tokenId, uint _expiration, address _linkId, bytes memory _linkdropSignerSignature, address _receiver, bytes memory _receiverSignature ) public view override whenNotPaused returns (bool) { // Make sure nft address is not equal to address(0) require(_nftAddress != address(0), "INVALID_NFT_ADDRESS"); // Make sure link is not claimed require(isClaimedLink(_linkId) == false, "LINK_CLAIMED"); // Make sure link is not canceled require(isCanceledLink(_linkId) == false, "LINK_CANCELED"); // Make sure link is not expired require(_expiration >= now, "LINK_EXPIRED"); // Make sure eth amount is available for this contract require(address(this).balance >= _weiAmount, "INSUFFICIENT_ETHERS"); // Verify that link key is legit and signed by linkdrop signer's private key require ( verifyLinkdropSignerSignatureERC721 ( _weiAmount, _nftAddress, _tokenId, _expiration, _linkId, _linkdropSignerSignature ), "INVALID_LINKDROP_SIGNER_SIGNATURE" ); // Verify that receiver address is signed by ephemeral key assigned to claim link (link key) require ( verifyReceiverSignatureERC721(_linkId, _receiver, _receiverSignature), "INVALID_RECEIVER_SIGNATURE" ); return true; } /** * @dev Function to claim ETH and/or ERC721 token. Can only be called when contract is not paused * @param _weiAmount Amount of wei to be claimed * @param _nftAddress NFT address * @param _tokenId Token id to be claimed * @param _expiration Unix timestamp of link expiration time * @param _linkId Address corresponding to link key * @param _linkdropSignerSignature ECDSA signature of linkdrop signer * @param _receiver Address of linkdrop receiver * @param _receiverSignature ECDSA signature of linkdrop receiver * @return True if success */ function claimERC721 ( uint _weiAmount, address _nftAddress, uint _tokenId, uint _expiration, address _linkId, bytes calldata _linkdropSignerSignature, address payable _receiver, bytes calldata _receiverSignature ) external override whenNotPaused payable returns (bool) { // Make sure params are valid require ( checkClaimParamsERC721 ( _weiAmount, _nftAddress, _tokenId, _expiration, _linkId, _linkdropSignerSignature, _receiver, _receiverSignature ), "INVALID_CLAIM_PARAMS" ); // Mark link as claimed claimedTo[_linkId] = _receiver; // Make sure transfer succeeds require(_transferFundsERC721(_weiAmount, _nftAddress, _tokenId, _receiver), "TRANSFER_FAILED"); // Log claim emit ClaimedERC721(_linkId, _weiAmount, _nftAddress, _tokenId, _receiver); return true; } /** * @dev Internal function to mint or transfer ERC721 tokens depending on the transfer pattern chosen for the contract. * @param _nftAddress NFT address * @param _tokenId Amount of tokens to be claimed (in atomic value) * @param _receiver Address to transfer funds to */ function _mintOrTransferNFT( address _nftAddress, uint _tokenId, address payable _receiver ) internal { if (claimPattern == 0) { // transfer` IERC721(_nftAddress).safeTransferFrom(linkdropMaster, _receiver, _tokenId); return; } else if (claimPattern == 1) { IERC721Mintable(_nftAddress).safeMint(_receiver); return; } revert("UNKNOWN_TRANSFER_PATTERN"); } /** * @dev Internal function to transfer ethers and/or ERC721 tokens * @param _weiAmount Amount of wei to be claimed * @param _nftAddress NFT address * @param _tokenId Amount of tokens to be claimed (in atomic value) * @param _receiver Address to transfer funds to * @return True if success */ function _transferFundsERC721 ( uint _weiAmount, address _nftAddress, uint _tokenId, address payable _receiver ) internal returns (bool) { // pay Linkdrop fee if needed _payFee( _nftAddress, _receiver); // Transfer ethers if (_weiAmount > 0) { _receiver.transfer(_weiAmount); } // Mint or Transfer NFT _mintOrTransferNFT( _nftAddress, _tokenId, _receiver); return true; } } // Dependency file: /Users/mikhail/Documents/soft/linkdrop/linkdrop-contracts/contracts/interfaces/ILinkdropERC1155.sol // pragma solidity >=0.6.0 <0.8.0; interface ILinkdropERC1155 { function verifyLinkdropSignerSignatureERC1155 ( uint _weiAmount, address _nftAddress, uint _tokenId, uint _tokenAmount, uint _expiration, address _linkId, bytes calldata _signature ) external view returns (bool); function checkClaimParamsERC1155 ( uint _weiAmount, address _nftAddress, uint _tokenId, uint _tokenAmount, uint _expiration, address _linkId, bytes calldata _linkdropSignerSignature, address _receiver, bytes calldata _receiverSignature ) external view returns (bool); function claimERC1155 ( uint _weiAmount, address _nftAddress, uint _tokenId, uint _tokenAmount, uint _expiration, address _linkId, bytes calldata _linkdropSignerSignature, address payable _receiver, bytes calldata _receiverSignature ) external payable returns (bool); } // Dependency file: contracts/interfaces/IERC1155Mintable.sol // pragma solidity >=0.6.0 <0.8.0; interface IERC1155Mintable { // function mint(address account, uint256 id, uint256 amount, bytes memory data) external; // function mintTo(address account, uint256 id, uint256 amount, bytes memory data) external; function mintTo( address to, uint256 tokenId, string calldata uri, uint256 amount ) external; } // Dependency file: openzeppelin-solidity/contracts/token/ERC1155/IERC1155.sol // pragma solidity >=0.6.2 <0.8.0; // import "openzeppelin-solidity/contracts/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external; } // Dependency file: contracts/linkdrop/LinkdropERC1155.sol // pragma solidity >=0.6.0 <0.8.0; // import "contracts/linkdrop/LinkdropCommon.sol"; // import "/Users/mikhail/Documents/soft/linkdrop/linkdrop-contracts/contracts/interfaces/ILinkdropERC1155.sol"; // import "contracts/interfaces/IERC1155Mintable.sol"; // import "contracts/interfaces/IFeeManager.sol"; // import "openzeppelin-solidity/contracts/token/ERC1155/IERC1155.sol"; contract LinkdropERC1155 is ILinkdropERC1155, LinkdropCommon { using SafeMath for uint; /** * @dev Function to verify linkdrop signer's signature * @param _weiAmount Amount of wei to be claimed * @param _nftAddress NFT address * @param _tokenId Token id to be claimed * @param _tokenAmount Token amount to be claimed * @param _expiration Unix timestamp of link expiration time * @param _linkId Address corresponding to link key * @param _signature ECDSA signature of linkdrop signer * @return True if signed with linkdrop signer's private key */ function verifyLinkdropSignerSignatureERC1155 ( uint _weiAmount, address _nftAddress, uint _tokenId, uint _tokenAmount, uint _expiration, address _linkId, bytes memory _signature ) public view override returns (bool) { bytes32 prefixedHash = ECDSA.toEthSignedMessageHash ( keccak256 ( abi.encodePacked ( _weiAmount, _nftAddress, _tokenId, _tokenAmount, _expiration, version, chainId, _linkId, address(this) ) ) ); address signer = ECDSA.recover(prefixedHash, _signature); return isLinkdropSigner[signer]; } /** * @dev Function to verify claim params and make sure the link is not claimed or canceled * @param _weiAmount Amount of wei to be claimed * @param _nftAddress NFT address * @param _tokenId Token id to be claimed * @param _tokenAmount Token amount to be claimed * @param _expiration Unix timestamp of link expiration time * @param _linkId Address corresponding to link key * @param _linkdropSignerSignature ECDSA signature of linkdrop signer * @param _receiver Address of linkdrop receiver * @param _receiverSignature ECDSA signature of linkdrop receiver * @return True if success */ function checkClaimParamsERC1155 ( uint _weiAmount, address _nftAddress, uint _tokenId, uint _tokenAmount, uint _expiration, address _linkId, bytes memory _linkdropSignerSignature, address _receiver, bytes memory _receiverSignature ) public view override whenNotPaused returns (bool) { // Make sure nft address is not equal to address(0) require(_nftAddress != address(0), "INVALID_NFT_ADDRESS"); // Make sure link is not claimed require(isClaimedLink(_linkId) == false, "LINK_CLAIMED"); // Make sure link is not canceled require(isCanceledLink(_linkId) == false, "LINK_CANCELED"); // Make sure link is not expired require(_expiration >= now, "LINK_EXPIRED"); // Make sure eth amount is available for this contract require(address(this).balance >= _weiAmount, "INSUFFICIENT_ETHERS"); // Verify that link key is legit and signed by linkdrop signer's private key require ( verifyLinkdropSignerSignatureERC1155 ( _weiAmount, _nftAddress, _tokenId, _tokenAmount, _expiration, _linkId, _linkdropSignerSignature ), "INVALID_LINKDROP_SIGNER_SIGNATURE" ); // Verify that receiver address is signed by ephemeral key assigned to claim link (link key) require ( verifyReceiverSignature(_linkId, _receiver, _receiverSignature), "INVALID_RECEIVER_SIGNATURE" ); return true; } /** * @dev Function to claim ETH and/or ERC1155 token. Can only be called when contract is not paused * @param _weiAmount Amount of wei to be claimed * @param _nftAddress NFT address * @param _tokenId Token id to be claimed * @param _tokenAmount Token amount to be claimed * @param _expiration Unix timestamp of link expiration time * @param _linkId Address corresponding to link key * @param _linkdropSignerSignature ECDSA signature of linkdrop signer * @param _receiver Address of linkdrop receiver * @param _receiverSignature ECDSA signature of linkdrop receiver * @return True if success */ function claimERC1155 ( uint _weiAmount, address _nftAddress, uint _tokenId, uint _tokenAmount, uint _expiration, address _linkId, bytes calldata _linkdropSignerSignature, address payable _receiver, bytes calldata _receiverSignature ) external override whenNotPaused payable returns (bool) { // Make sure params are valid require ( checkClaimParamsERC1155 ( _weiAmount, _nftAddress, _tokenId, _tokenAmount, _expiration, _linkId, _linkdropSignerSignature, _receiver, _receiverSignature ), "INVALID_CLAIM_PARAMS" ); // Mark link as claimed claimedTo[_linkId] = _receiver; // Make sure transfer succeeds require(_transferFundsERC1155(_weiAmount, _nftAddress, _tokenId, _tokenAmount, _receiver), "TRANSFER_FAILED"); // Log claim emit ClaimedERC1155(_linkId, _weiAmount, _nftAddress, _tokenId, _tokenAmount, _receiver); return true; } /** * @dev Internal function to mint or transfer ERC1155 tokens depending on the transfer pattern chosen for the contract. * @param _nftAddress NFT address * @param _tokenId Amount of tokens to be claimed (in atomic value) * @param _tokenAmount Token amount to transfer * @param _receiver Address to transfer funds to */ function _mintOrTransferNFT( address _nftAddress, uint _tokenId, uint _tokenAmount, address payable _receiver ) internal { if (claimPattern == 0) { // transfer` IERC1155(_nftAddress).safeTransferFrom(linkdropMaster, _receiver, _tokenId, _tokenAmount, new bytes(0)); return; } else if (claimPattern == 1) { IERC1155Mintable(_nftAddress).mintTo(_receiver, _tokenId, "", _tokenAmount); return; } revert("UNKNOWN_TRANSFER_PATTERN"); } /** * @dev Internal function to transfer ethers and/or ERC1155 tokens * @param _weiAmount Amount of wei to be claimed * @param _nftAddress NFT address * @param _tokenId token id to transfer * @param _tokenAmount Token amount to transfer * @param _receiver Address to transfer funds to * @return True if success */ function _transferFundsERC1155 ( uint _weiAmount, address _nftAddress, uint _tokenId, uint _tokenAmount, address payable _receiver ) internal returns (bool) { // pay Linkdrop fee if needed _payFee( _nftAddress, _receiver); // Transfer ethers if (_weiAmount > 0) { _receiver.transfer(_weiAmount); } // Mint or Transfer NFT _mintOrTransferNFT( _nftAddress, _tokenId, _tokenAmount, _receiver); return true; } } // Root file: contracts/linkdrop/LinkdropMastercopy.sol pragma solidity >=0.6.0 <0.8.0; // import "contracts/linkdrop/LinkdropERC20.sol"; // import "contracts/linkdrop/LinkdropERC721.sol"; // import "contracts/linkdrop/LinkdropERC1155.sol"; contract LinkdropMastercopy is LinkdropERC20, LinkdropERC721, LinkdropERC1155 { }
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"linkdropSigner","type":"address"}],"name":"AddedSigningKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"linkId","type":"address"}],"name":"Canceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"linkId","type":"address"},{"indexed":false,"internalType":"uint256","name":"ethAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"linkId","type":"address"},{"indexed":false,"internalType":"uint256","name":"ethAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"nft","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"}],"name":"ClaimedERC1155","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"linkId","type":"address"},{"indexed":false,"internalType":"uint256","name":"ethAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"nft","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"}],"name":"ClaimedERC721","type":"event"},{"anonymous":false,"inputs":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"linkdropSigner","type":"address"}],"name":"RemovedSigningKey","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"address","name":"_linkdropSigner","type":"address"}],"name":"addSigner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_linkId","type":"address"}],"name":"cancel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_weiAmount","type":"uint256"},{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"},{"internalType":"uint256","name":"_expiration","type":"uint256"},{"internalType":"address","name":"_linkId","type":"address"},{"internalType":"bytes","name":"_linkdropSignerSignature","type":"bytes"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"bytes","name":"_receiverSignature","type":"bytes"}],"name":"checkClaimParams","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_weiAmount","type":"uint256"},{"internalType":"address","name":"_nftAddress","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"},{"internalType":"uint256","name":"_expiration","type":"uint256"},{"internalType":"address","name":"_linkId","type":"address"},{"internalType":"bytes","name":"_linkdropSignerSignature","type":"bytes"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"bytes","name":"_receiverSignature","type":"bytes"}],"name":"checkClaimParamsERC1155","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_weiAmount","type":"uint256"},{"internalType":"address","name":"_nftAddress","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_expiration","type":"uint256"},{"internalType":"address","name":"_linkId","type":"address"},{"internalType":"bytes","name":"_linkdropSignerSignature","type":"bytes"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"bytes","name":"_receiverSignature","type":"bytes"}],"name":"checkClaimParamsERC721","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_weiAmount","type":"uint256"},{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"},{"internalType":"uint256","name":"_expiration","type":"uint256"},{"internalType":"address","name":"_linkId","type":"address"},{"internalType":"bytes","name":"_linkdropSignerSignature","type":"bytes"},{"internalType":"address payable","name":"_receiver","type":"address"},{"internalType":"bytes","name":"_receiverSignature","type":"bytes"}],"name":"claim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_weiAmount","type":"uint256"},{"internalType":"address","name":"_nftAddress","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"},{"internalType":"uint256","name":"_expiration","type":"uint256"},{"internalType":"address","name":"_linkId","type":"address"},{"internalType":"bytes","name":"_linkdropSignerSignature","type":"bytes"},{"internalType":"address payable","name":"_receiver","type":"address"},{"internalType":"bytes","name":"_receiverSignature","type":"bytes"}],"name":"claimERC1155","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_weiAmount","type":"uint256"},{"internalType":"address","name":"_nftAddress","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_expiration","type":"uint256"},{"internalType":"address","name":"_linkId","type":"address"},{"internalType":"bytes","name":"_linkdropSignerSignature","type":"bytes"},{"internalType":"address payable","name":"_receiver","type":"address"},{"internalType":"bytes","name":"_receiverSignature","type":"bytes"}],"name":"claimERC721","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"claimPattern","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimedTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"destroy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract ILinkdropFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkdropMaster","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMasterCopyVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address payable","name":"_linkdropMaster","type":"address"},{"internalType":"uint256","name":"_version","type":"uint256"},{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"uint256","name":"_claimPattern","type":"uint256"}],"name":"initialize","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_linkId","type":"address"}],"name":"isCanceledLink","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_linkId","type":"address"}],"name":"isClaimedLink","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isLinkdropSigner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"linkdropMaster","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"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":[{"internalType":"address","name":"_linkdropSigner","type":"address"}],"name":"removeSigner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_weiAmount","type":"uint256"},{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"},{"internalType":"uint256","name":"_expiration","type":"uint256"},{"internalType":"address","name":"_linkId","type":"address"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"verifyLinkdropSignerSignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_weiAmount","type":"uint256"},{"internalType":"address","name":"_nftAddress","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"},{"internalType":"uint256","name":"_expiration","type":"uint256"},{"internalType":"address","name":"_linkId","type":"address"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"verifyLinkdropSignerSignatureERC1155","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_weiAmount","type":"uint256"},{"internalType":"address","name":"_nftAddress","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_expiration","type":"uint256"},{"internalType":"address","name":"_linkId","type":"address"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"verifyLinkdropSignerSignatureERC721","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_linkId","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"verifyReceiverSignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_linkId","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"verifyReceiverSignatureERC721","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.