Overview
APE Balance
0 APE
APE Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Update Admin | 5696759 | 34 days ago | IN | 0 APE | 0.00068668 |
Loading...
Loading
Contract Name:
CyanConduit
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 500 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import "../helpers/CyanConduitConstants.sol"; import { ICyanConduit, ConduitTransfer, ConduitBatch1155Transfer, ConduitItemType } from "../interfaces/conduit/ICyanConduit.sol"; import { TokenTransferrer } from "./TokenTransferrer.sol"; /** * @title CyanConduit * @notice This contract serves as an originator for "proxied" transfers. Each * conduit is deployed and controlled by a "conduit admin" that can * add and remove "channels" or contracts that can instruct the conduit * to transfer approved ERC20/721/1155 tokens. *IMPORTANT NOTE: each * conduit has an owner that can arbitrarily add or remove channels, and * a malicious or negligent owner can add a channel that allows for any * approved ERC20/721/1155 tokens to be taken immediately — be extremely * cautious with what conduits you give token approvals to!* */ contract CyanConduit is ICyanConduit, TokenTransferrer { address private _admin; // Track the status of each channel. mapping(address => bool) private _channels; /** * @notice Ensure that the caller is currently registered as an open channel * on the conduit. */ modifier onlyOpenChannel() { // Utilize assembly to access channel storage mapping directly. assembly { // Write the caller to scratch space. mstore(ChannelKey_channel_ptr, caller()) // Write the storage slot for _channels to scratch space. mstore(ChannelKey_slot_ptr, _channels.slot) // Derive the position in storage of _channels[msg.sender] // and check if the stored value is zero. if iszero(sload(keccak256(ChannelKey_channel_ptr, ChannelKey_length))) { // The caller is not an open channel; revert with // ChannelClosed(caller). First, set error signature in memory. mstore(ChannelClosed_error_ptr, ChannelClosed_error_signature) // Next, set the caller as the argument. mstore(ChannelClosed_channel_ptr, caller()) // Finally, revert, returning full custom error with argument. revert(ChannelClosed_error_ptr, ChannelClosed_error_length) } } // Continue with function execution. _; } constructor() { _admin = msg.sender; } /** * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller * with an open channel can call this function. Note that channels * are expected to implement reentrancy protection if desired, and * that cross-channel reentrancy may be possible if the conduit has * multiple open channels at once. Also note that channels are * expected to implement checks against transferring any zero-amount * items if that constraint is desired. * * @param transfers The ERC20/721/1155 transfers to perform. * * @return magicValue A magic value indicating that the transfers were * performed successfully. */ function execute(ConduitTransfer[] calldata transfers) external override onlyOpenChannel returns (bytes4 magicValue) { // Retrieve the total number of transfers and place on the stack. uint256 totalStandardTransfers = transfers.length; // Iterate over each transfer. for (uint256 i = 0; i < totalStandardTransfers; ) { // Retrieve the transfer in question and perform the transfer. _transfer(transfers[i]); // Skip overflow check as for loop is indexed starting at zero. unchecked { ++i; } } // Return a magic value indicating that the transfers were performed. magicValue = this.execute.selector; } /** * @notice Execute a sequence of batch 1155 item transfers. Only a caller * with an open channel can call this function. Note that channels * are expected to implement reentrancy protection if desired, and * that cross-channel reentrancy may be possible if the conduit has * multiple open channels at once. Also note that channels are * expected to implement checks against transferring any zero-amount * items if that constraint is desired. * * @param batchTransfers The 1155 batch item transfers to perform. * * @return magicValue A magic value indicating that the item transfers were * performed successfully. */ function executeBatch1155(ConduitBatch1155Transfer[] calldata batchTransfers) external override onlyOpenChannel returns (bytes4 magicValue) { // Perform 1155 batch transfers. Note that memory should be considered // entirely corrupted from this point forward. _performERC1155BatchTransfers(batchTransfers); // Return a magic value indicating that the transfers were performed. magicValue = this.executeBatch1155.selector; } /** * @notice Execute a sequence of transfers, both single ERC20/721/1155 item * transfers as well as batch 1155 item transfers. Only a caller * with an open channel can call this function. Note that channels * are expected to implement reentrancy protection if desired, and * that cross-channel reentrancy may be possible if the conduit has * multiple open channels at once. Also note that channels are * expected to implement checks against transferring any zero-amount * items if that constraint is desired. * * @param standardTransfers The ERC20/721/1155 item transfers to perform. * @param batchTransfers The 1155 batch item transfers to perform. * * @return magicValue A magic value indicating that the item transfers were * performed successfully. */ function executeWithBatch1155( ConduitTransfer[] calldata standardTransfers, ConduitBatch1155Transfer[] calldata batchTransfers ) external override onlyOpenChannel returns (bytes4 magicValue) { // Retrieve the total number of transfers and place on the stack. uint256 totalStandardTransfers = standardTransfers.length; // Iterate over each standard transfer. for (uint256 i = 0; i < totalStandardTransfers; ) { // Retrieve the transfer in question and perform the transfer. _transfer(standardTransfers[i]); // Skip overflow check as for loop is indexed starting at zero. unchecked { ++i; } } // Perform 1155 batch transfers. Note that memory should be considered // entirely corrupted from this point forward aside from the free memory // pointer having the default value. _performERC1155BatchTransfers(batchTransfers); // Return a magic value indicating that the transfers were performed. magicValue = this.executeWithBatch1155.selector; } /** * @notice Open or close a given channel. Only callable by the admin. * * @param channel The channel to open or close. * @param isOpen The status of the channel (either open or closed). */ function updateChannel(address channel, bool isOpen) external override { // Ensure that the caller is the admin of this contract. if (msg.sender != _admin) { revert InvalidAdmin(); } // Ensure that the channel does not already have the indicated status. if (_channels[channel] == isOpen) { revert ChannelStatusAlreadySet(channel, isOpen); } // Update the status of the channel. _channels[channel] = isOpen; // Emit a corresponding event. emit ChannelUpdated(channel, isOpen); } /** * @dev Internal function to transfer a given ERC20/721/1155 item. Note that * channels are expected to implement checks against transferring any * zero-amount items if that constraint is desired. * * @param item The ERC20/721/1155 item to transfer. */ function _transfer(ConduitTransfer calldata item) internal { // Determine the transfer method based on the respective item type. if (item.itemType == ConduitItemType.ERC20) { // Transfer ERC20 token. Note that item.identifier is ignored and // therefore ERC20 transfer items are potentially malleable — this // check should be performed by the calling channel if a constraint // on item malleability is desired. _performERC20Transfer(item.collection, item.from, item.to, item.amount); } else if (item.itemType == ConduitItemType.ERC721) { // Ensure that exactly one 721 item is being transferred. if (item.amount != 1) { revert InvalidERC721TransferAmount(item.amount); } // Transfer ERC721 token. _performERC721Transfer(item.collection, item.from, item.to, item.identifier); } else if (item.itemType == ConduitItemType.ERC1155) { // Transfer ERC1155 token. _performERC1155Transfer(item.collection, item.from, item.to, item.identifier, item.amount); } else { // Throw with an error. revert InvalidItemType(); } } /** * @notice Update current admin. Only callable by the admin. * * @param newAdmin New admin address. */ function updateAdmin(address newAdmin) external { if (msg.sender != _admin) revert InvalidAdmin(); _admin = newAdmin; } function transferERC20( address from, address to, address token, uint256 amount ) external onlyOpenChannel { _performERC20Transfer(token, from, to, amount); } function transferERC721( address from, address to, address collection, uint256 tokenId ) external onlyOpenChannel { _performERC721Transfer(collection, from, to, tokenId); } function transferERC1155( address from, address to, address collection, uint256 tokenId, uint256 amount ) external onlyOpenChannel { _performERC1155Transfer(collection, from, to, tokenId, amount); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import "../helpers/CyanConduitConstants.sol"; import { ConduitBatch1155Transfer } from "../interfaces/conduit/ICyanConduit.sol"; import { ITokenTransferrerErrors } from "../interfaces/conduit/ITokenTransferrerErrors.sol"; /** * @title TokenTransferrer * @author 0age * @custom:coauthor d1ll0n * @custom:coauthor transmissions11 * @notice TokenTransferrer is a library for performing optimized ERC20, ERC721, * ERC1155, and batch ERC1155 transfers, used by both Seaport as well as * by conduits deployed by the ConduitController. Use great caution when * considering these functions for use in other codebases, as there are * significant side effects and edge cases that need to be thoroughly * understood and carefully addressed. */ contract TokenTransferrer is ITokenTransferrerErrors { /** * @dev Internal function to transfer ERC20 tokens from a given originator * to a given recipient. Sufficient approvals must be set on the * contract performing the transfer. * * @param token The ERC20 token to transfer. * @param from The originator of the transfer. * @param to The recipient of the transfer. * @param amount The amount to transfer. */ function _performERC20Transfer( address token, address from, address to, uint256 amount ) internal { // Utilize assembly to perform an optimized ERC20 token transfer. assembly { // The free memory pointer memory slot will be used when populating // call data for the transfer; read the value and restore it later. let memPointer := mload(FreeMemoryPointerSlot) // Write call data into memory, starting with function selector. mstore(ERC20_transferFrom_sig_ptr, ERC20_transferFrom_signature) mstore(ERC20_transferFrom_from_ptr, from) mstore(ERC20_transferFrom_to_ptr, to) mstore(ERC20_transferFrom_amount_ptr, amount) // Make call & copy up to 32 bytes of return data to scratch space. // Scratch space does not need to be cleared ahead of time, as the // subsequent check will ensure that either at least a full word of // return data is received (in which case it will be overwritten) or // that no data is received (in which case scratch space will be // ignored) on a successful call to the given token. let callStatus := call(gas(), token, 0, ERC20_transferFrom_sig_ptr, ERC20_transferFrom_length, 0, OneWord) // Determine whether transfer was successful using status & result. let success := and( // Set success to whether the call reverted, if not check it // either returned exactly 1 (can't just be non-zero data), or // had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), callStatus ) // Handle cases where either the transfer failed or no data was // returned. Group these, as most transfers will succeed with data. // Equivalent to `or(iszero(success), iszero(returndatasize()))` // but after it's inverted for JUMPI this expression is cheaper. if iszero(and(success, iszero(iszero(returndatasize())))) { // If the token has no code or the transfer failed: Equivalent // to `or(iszero(success), iszero(extcodesize(token)))` but // after it's inverted for JUMPI this expression is cheaper. if iszero(and(iszero(iszero(extcodesize(token))), success)) { // If the transfer failed: if iszero(success) { // If it was due to a revert: if iszero(callStatus) { // If it returned a message, bubble it up as long as // sufficient gas remains to do so: if returndatasize() { // Ensure that sufficient gas is available to // copy returndata while expanding memory where // necessary. Start by computing the word size // of returndata and allocated memory. Round up // to the nearest full word. let returnDataWords := shr(OneWordShift, add(returndatasize(), ThirtyOneBytes)) // Note: use the free memory pointer in place of // msize() to work around a Yul warning that // prevents accessing msize directly when the IR // pipeline is activated. let msizeWords := shr(OneWordShift, memPointer) // Next, compute the cost of the returndatacopy. let cost := mul(CostPerWord, returnDataWords) // Then, compute cost of new memory allocation. if gt(returnDataWords, msizeWords) { cost := add( cost, add( mul(sub(returnDataWords, msizeWords), CostPerWord), shr( MemoryExpansionCoefficientShift, sub(mul(returnDataWords, returnDataWords), mul(msizeWords, msizeWords)) ) ) ) } // Finally, add a small constant and compare to // gas remaining; bubble up the revert data if // enough gas is still available. if lt(add(cost, ExtraGasBuffer), gas()) { // Copy returndata to memory; overwrite // existing memory. returndatacopy(0, 0, returndatasize()) // Revert, specifying memory region with // copied returndata. revert(0, returndatasize()) } } // Store left-padded selector with push4, mem[28:32] mstore(0, TokenTransferGenericFailure_error_selector) mstore(TokenTransferGenericFailure_error_token_ptr, token) mstore(TokenTransferGenericFailure_error_from_ptr, from) mstore(TokenTransferGenericFailure_error_to_ptr, to) mstore(TokenTransferGenericFailure_err_identifier_ptr, 0) mstore(TokenTransferGenericFailure_error_amount_ptr, amount) // revert(abi.encodeWithSignature( // "TokenTransferGenericFailure( // address,address,address,uint256,uint256 // )", token, from, to, identifier, amount // )) revert(Generic_error_selector_offset, TokenTransferGenericFailure_error_length) } // Otherwise revert with a message about the token // returning false or non-compliant return values. // Store left-padded selector with push4, mem[28:32] mstore(0, BadReturnValueFromERC20OnTransfer_error_selector) mstore(BadReturnValueFromERC20OnTransfer_error_token_ptr, token) mstore(BadReturnValueFromERC20OnTransfer_error_from_ptr, from) mstore(BadReturnValueFromERC20OnTransfer_error_to_ptr, to) mstore(BadReturnValueFromERC20OnTransfer_error_amount_ptr, amount) // revert(abi.encodeWithSignature( // "BadReturnValueFromERC20OnTransfer( // address,address,address,uint256 // )", token, from, to, amount // )) revert(Generic_error_selector_offset, BadReturnValueFromERC20OnTransfer_error_length) } // Otherwise, revert with error about token not having code: // Store left-padded selector with push4, mem[28:32] mstore(0, NoContract_error_selector) mstore(NoContract_error_account_ptr, token) // revert(abi.encodeWithSignature( // "NoContract(address)", account // )) revert(Generic_error_selector_offset, NoContract_error_length) } // Otherwise, the token just returned no data despite the call // having succeeded; no need to optimize for this as it's not // technically ERC20 compliant. } // Restore the original free memory pointer. mstore(FreeMemoryPointerSlot, memPointer) // Restore the zero slot to zero. mstore(ZeroSlot, 0) } } /** * @dev Internal function to transfer an ERC721 token from a given * originator to a given recipient. Sufficient approvals must be set on * the contract performing the transfer. Note that this function does * not check whether the receiver can accept the ERC721 token (i.e. it * does not use `safeTransferFrom`). * * @param token The ERC721 token to transfer. * @param from The originator of the transfer. * @param to The recipient of the transfer. * @param identifier The tokenId to transfer. */ function _performERC721Transfer( address token, address from, address to, uint256 identifier ) internal { // Utilize assembly to perform an optimized ERC721 token transfer. assembly { // If the token has no code, revert. if iszero(extcodesize(token)) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, NoContract_error_selector) mstore(NoContract_error_account_ptr, token) // revert(abi.encodeWithSignature( // "NoContract(address)", account // )) revert(Generic_error_selector_offset, NoContract_error_length) } // The free memory pointer memory slot will be used when populating // call data for the transfer; read the value and restore it later. let memPointer := mload(FreeMemoryPointerSlot) // Write call data to memory starting with function selector. mstore(ERC721_transferFrom_sig_ptr, ERC721_transferFrom_signature) mstore(ERC721_transferFrom_from_ptr, from) mstore(ERC721_transferFrom_to_ptr, to) mstore(ERC721_transferFrom_id_ptr, identifier) // Perform the call, ignoring return data. let success := call(gas(), token, 0, ERC721_transferFrom_sig_ptr, ERC721_transferFrom_length, 0, 0) // If the transfer reverted: if iszero(success) { // If it returned a message, bubble it up as long as sufficient // gas remains to do so: if returndatasize() { // Ensure that sufficient gas is available to copy // returndata while expanding memory where necessary. Start // by computing word size of returndata & allocated memory. // Round up to the nearest full word. let returnDataWords := shr(OneWordShift, add(returndatasize(), ThirtyOneBytes)) // Note: use the free memory pointer in place of msize() to // work around a Yul warning that prevents accessing msize // directly when the IR pipeline is activated. let msizeWords := shr(OneWordShift, memPointer) // Next, compute the cost of the returndatacopy. let cost := mul(CostPerWord, returnDataWords) // Then, compute cost of new memory allocation. if gt(returnDataWords, msizeWords) { cost := add( cost, add( mul(sub(returnDataWords, msizeWords), CostPerWord), shr( MemoryExpansionCoefficientShift, sub(mul(returnDataWords, returnDataWords), mul(msizeWords, msizeWords)) ) ) ) } // Finally, add a small constant and compare to gas // remaining; bubble up the revert data if enough gas is // still available. if lt(add(cost, ExtraGasBuffer), gas()) { // Copy returndata to memory; overwrite existing memory. returndatacopy(0, 0, returndatasize()) // Revert, giving memory region with copied returndata. revert(0, returndatasize()) } } // Otherwise revert with a generic error message. // Store left-padded selector with push4, mem[28:32] = selector mstore(0, TokenTransferGenericFailure_error_selector) mstore(TokenTransferGenericFailure_error_token_ptr, token) mstore(TokenTransferGenericFailure_error_from_ptr, from) mstore(TokenTransferGenericFailure_error_to_ptr, to) mstore(TokenTransferGenericFailure_error_identifier_ptr, identifier) mstore(TokenTransferGenericFailure_error_amount_ptr, 1) // revert(abi.encodeWithSignature( // "TokenTransferGenericFailure( // address,address,address,uint256,uint256 // )", token, from, to, identifier, amount // )) revert(Generic_error_selector_offset, TokenTransferGenericFailure_error_length) } // Restore the original free memory pointer. mstore(FreeMemoryPointerSlot, memPointer) // Restore the zero slot to zero. mstore(ZeroSlot, 0) } } /** * @dev Internal function to transfer ERC1155 tokens from a given * originator to a given recipient. Sufficient approvals must be set on * the contract performing the transfer and contract recipients must * implement the ERC1155TokenReceiver interface to indicate that they * are willing to accept the transfer. * * @param token The ERC1155 token to transfer. * @param from The originator of the transfer. * @param to The recipient of the transfer. * @param identifier The id to transfer. * @param amount The amount to transfer. */ function _performERC1155Transfer( address token, address from, address to, uint256 identifier, uint256 amount ) internal { // Utilize assembly to perform an optimized ERC1155 token transfer. assembly { // If the token has no code, revert. if iszero(extcodesize(token)) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, NoContract_error_selector) mstore(NoContract_error_account_ptr, token) // revert(abi.encodeWithSignature( // "NoContract(address)", account // )) revert(Generic_error_selector_offset, NoContract_error_length) } // The following memory slots will be used when populating call data // for the transfer; read the values and restore them later. let memPointer := mload(FreeMemoryPointerSlot) let slot0x80 := mload(Slot0x80) let slot0xA0 := mload(Slot0xA0) let slot0xC0 := mload(Slot0xC0) // Write call data into memory, beginning with function selector. mstore(ERC1155_safeTransferFrom_sig_ptr, ERC1155_safeTransferFrom_signature) mstore(ERC1155_safeTransferFrom_from_ptr, from) mstore(ERC1155_safeTransferFrom_to_ptr, to) mstore(ERC1155_safeTransferFrom_id_ptr, identifier) mstore(ERC1155_safeTransferFrom_amount_ptr, amount) mstore(ERC1155_safeTransferFrom_data_offset_ptr, ERC1155_safeTransferFrom_data_length_offset) mstore(ERC1155_safeTransferFrom_data_length_ptr, 0) // Perform the call, ignoring return data. let success := call( gas(), token, 0, ERC1155_safeTransferFrom_sig_ptr, ERC1155_safeTransferFrom_length, 0, 0 ) // If the transfer reverted: if iszero(success) { // If it returned a message, bubble it up as long as sufficient // gas remains to do so: if returndatasize() { // Ensure that sufficient gas is available to copy // returndata while expanding memory where necessary. Start // by computing word size of returndata & allocated memory. // Round up to the nearest full word. let returnDataWords := shr(OneWordShift, add(returndatasize(), ThirtyOneBytes)) // Note: use the free memory pointer in place of msize() to // work around a Yul warning that prevents accessing msize // directly when the IR pipeline is activated. let msizeWords := shr(OneWordShift, memPointer) // Next, compute the cost of the returndatacopy. let cost := mul(CostPerWord, returnDataWords) // Then, compute cost of new memory allocation. if gt(returnDataWords, msizeWords) { cost := add( cost, add( mul(sub(returnDataWords, msizeWords), CostPerWord), shr( MemoryExpansionCoefficientShift, sub(mul(returnDataWords, returnDataWords), mul(msizeWords, msizeWords)) ) ) ) } // Finally, add a small constant and compare to gas // remaining; bubble up the revert data if enough gas is // still available. if lt(add(cost, ExtraGasBuffer), gas()) { // Copy returndata to memory; overwrite existing memory. returndatacopy(0, 0, returndatasize()) // Revert, giving memory region with copied returndata. revert(0, returndatasize()) } } // Otherwise revert with a generic error message. // Store left-padded selector with push4, mem[28:32] = selector mstore(0, TokenTransferGenericFailure_error_selector) mstore(TokenTransferGenericFailure_error_token_ptr, token) mstore(TokenTransferGenericFailure_error_from_ptr, from) mstore(TokenTransferGenericFailure_error_to_ptr, to) mstore(TokenTransferGenericFailure_error_identifier_ptr, identifier) mstore(TokenTransferGenericFailure_error_amount_ptr, amount) // revert(abi.encodeWithSignature( // "TokenTransferGenericFailure( // address,address,address,uint256,uint256 // )", token, from, to, identifier, amount // )) revert(Generic_error_selector_offset, TokenTransferGenericFailure_error_length) } mstore(Slot0x80, slot0x80) // Restore slot 0x80. mstore(Slot0xA0, slot0xA0) // Restore slot 0xA0. mstore(Slot0xC0, slot0xC0) // Restore slot 0xC0. // Restore the original free memory pointer. mstore(FreeMemoryPointerSlot, memPointer) // Restore the zero slot to zero. mstore(ZeroSlot, 0) } } /** * @dev Internal function to transfer ERC1155 tokens from a given * originator to a given recipient. Sufficient approvals must be set on * the contract performing the transfer and contract recipients must * implement the ERC1155TokenReceiver interface to indicate that they * are willing to accept the transfer. NOTE: this function is not * memory-safe; it will overwrite existing memory, restore the free * memory pointer to the default value, and overwrite the zero slot. * This function should only be called once memory is no longer * required and when uninitialized arrays are not utilized, and memory * should be considered fully corrupted (aside from the existence of a * default-value free memory pointer) after calling this function. * * @param batchTransfers The group of 1155 batch transfers to perform. */ function _performERC1155BatchTransfers(ConduitBatch1155Transfer[] calldata batchTransfers) internal { // Utilize assembly to perform optimized batch 1155 transfers. assembly { let len := batchTransfers.length // Pointer to first head in the array, which is offset to the struct // at each index. This gets incremented after each loop to avoid // multiplying by 32 to get the offset for each element. let nextElementHeadPtr := batchTransfers.offset // Pointer to beginning of the head of the array. This is the // reference position each offset references. It's held static to // let each loop calculate the data position for an element. let arrayHeadPtr := nextElementHeadPtr // Write the function selector, which will be reused for each call: // safeBatchTransferFrom(address,address,uint256[],uint256[],bytes) mstore(ConduitBatch1155Transfer_from_offset, ERC1155_safeBatchTransferFrom_signature) // Iterate over each batch transfer. for { let i := 0 } lt(i, len) { i := add(i, 1) } { // Read the offset to the beginning of the element and add // it to pointer to the beginning of the array head to get // the absolute position of the element in calldata. let elementPtr := add(arrayHeadPtr, calldataload(nextElementHeadPtr)) // Retrieve the token from calldata. let token := calldataload(elementPtr) // If the token has no code, revert. if iszero(extcodesize(token)) { // Store left-padded selector with push4, mem[28:32] mstore(0, NoContract_error_selector) mstore(NoContract_error_account_ptr, token) // revert(abi.encodeWithSignature( // "NoContract(address)", account // )) revert(Generic_error_selector_offset, NoContract_error_length) } // Get the total number of supplied ids. let idsLength := calldataload(add(elementPtr, ConduitBatch1155Transfer_ids_length_offset)) // Determine the expected offset for the amounts array. let expectedAmountsOffset := add( ConduitBatch1155Transfer_amounts_length_baseOffset, shl(OneWordShift, idsLength) ) // Validate struct encoding. let invalidEncoding := iszero( and( // ids.length == amounts.length eq(idsLength, calldataload(add(elementPtr, expectedAmountsOffset))), and( // ids_offset == 0xa0 eq( calldataload(add(elementPtr, ConduitBatch1155Transfer_ids_head_offset)), ConduitBatch1155Transfer_ids_length_offset ), // amounts_offset == 0xc0 + ids.length*32 eq( calldataload(add(elementPtr, ConduitBatchTransfer_amounts_head_offset)), expectedAmountsOffset ) ) ) ) // Revert with an error if the encoding is not valid. if invalidEncoding { // Store left-padded selector with push4, mem[28:32] mstore(Invalid1155BatchTransferEncoding_ptr, Invalid1155BatchTransferEncoding_selector) // revert(abi.encodeWithSignature( // "Invalid1155BatchTransferEncoding()" // )) revert(Invalid1155BatchTransferEncoding_ptr, Invalid1155BatchTransferEncoding_length) } // Update the offset position for the next loop nextElementHeadPtr := add(nextElementHeadPtr, OneWord) // Copy the first section of calldata (before dynamic values). calldatacopy( BatchTransfer1155Params_ptr, add(elementPtr, ConduitBatch1155Transfer_from_offset), ConduitBatch1155Transfer_usable_head_size ) // Determine size of calldata required for ids and amounts. Note // that the size includes both lengths as well as the data. let idsAndAmountsSize := add(TwoWords, shl(TwoWordsShift, idsLength)) // Update the offset for the data array in memory. mstore( BatchTransfer1155Params_data_head_ptr, add(BatchTransfer1155Params_ids_length_offset, idsAndAmountsSize) ) // Set the length of the data array in memory to zero. mstore(add(BatchTransfer1155Params_data_length_basePtr, idsAndAmountsSize), 0) // Determine the total calldata size for the call to transfer. let transferDataSize := add(BatchTransfer1155Params_calldata_baseSize, idsAndAmountsSize) // Copy second section of calldata (including dynamic values). calldatacopy( BatchTransfer1155Params_ids_length_ptr, add(elementPtr, ConduitBatch1155Transfer_ids_length_offset), idsAndAmountsSize ) // Perform the call to transfer 1155 tokens. let success := call( gas(), token, 0, ConduitBatch1155Transfer_from_offset, // Data portion start. transferDataSize, // Location of the length of callData. 0, 0 ) // If the transfer reverted: if iszero(success) { // If it returned a message, bubble it up as long as // sufficient gas remains to do so: if returndatasize() { // Ensure that sufficient gas is available to copy // returndata while expanding memory where necessary. // Start by computing word size of returndata and // allocated memory. Round up to the nearest full word. let returnDataWords := shr(OneWordShift, add(returndatasize(), ThirtyOneBytes)) // Note: use transferDataSize in place of msize() to // work around a Yul warning that prevents accessing // msize directly when the IR pipeline is activated. // The free memory pointer is not used here because // this function does almost all memory management // manually and does not update it, and transferDataSize // should be the largest memory value used (unless a // previous batch was larger). let msizeWords := shr(OneWordShift, transferDataSize) // Next, compute the cost of the returndatacopy. let cost := mul(CostPerWord, returnDataWords) // Then, compute cost of new memory allocation. if gt(returnDataWords, msizeWords) { cost := add( cost, add( mul(sub(returnDataWords, msizeWords), CostPerWord), shr( MemoryExpansionCoefficientShift, sub(mul(returnDataWords, returnDataWords), mul(msizeWords, msizeWords)) ) ) ) } // Finally, add a small constant and compare to gas // remaining; bubble up the revert data if enough gas is // still available. if lt(add(cost, ExtraGasBuffer), gas()) { // Copy returndata to memory; overwrite existing. returndatacopy(0, 0, returndatasize()) // Revert with memory region containing returndata. revert(0, returndatasize()) } } // Set the error signature. mstore(0, ERC1155BatchTransferGenericFailure_error_signature) // Write the token. mstore(ERC1155BatchTransferGenericFailure_token_ptr, token) // Increase the offset to ids by 32. mstore(BatchTransfer1155Params_ids_head_ptr, ERC1155BatchTransferGenericFailure_ids_offset) // Increase the offset to amounts by 32. mstore( BatchTransfer1155Params_amounts_head_ptr, add(OneWord, mload(BatchTransfer1155Params_amounts_head_ptr)) ) // Return modified region. The total size stays the same as // `token` uses the same number of bytes as `data.length`. revert(0, transferDataSize) } } // Reset the free memory pointer to the default value; memory must // be assumed to be dirtied and not reused from this point forward. // Also note that the zero slot is not reset to zero, meaning empty // arrays cannot be safely created or utilized until it is restored. mstore(FreeMemoryPointerSlot, DefaultFreeMemoryPointer) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; /* * -------------------------- Disambiguation & Other Notes --------------------- * - The term "head" is used as it is in the documentation for ABI encoding, * but only in reference to dynamic types, i.e. it always refers to the * offset or pointer to the body of a dynamic type. In calldata, the head * is always an offset (relative to the parent object), while in memory, * the head is always the pointer to the body. More information found here: * https://docs.soliditylang.org/en/v0.8.17/abi-spec.html#argument-encoding * - Note that the length of an array is separate from and precedes the * head of the array. * * - The term "body" is used in place of the term "head" used in the ABI * documentation. It refers to the start of the data for a dynamic type, * e.g. the first word of a struct or the first word of the first element * in an array. * * - The term "pointer" is used to describe the absolute position of a value * and never an offset relative to another value. * - The suffix "_ptr" refers to a memory pointer. * - The suffix "_cdPtr" refers to a calldata pointer. * * - The term "offset" is used to describe the position of a value relative * to some parent value. For example, OrderParameters_conduit_offset is the * offset to the "conduit" value in the OrderParameters struct relative to * the start of the body. * - Note: Offsets are used to derive pointers. * * - Some structs have pointers defined for all of their fields in this file. * Lines which are commented out are fields that are not used in the * codebase but have been left in for readability. */ uint256 constant ThirtyOneBytes = 0x1f; uint256 constant OneWord = 0x20; uint256 constant TwoWords = 0x40; uint256 constant ThreeWords = 0x60; uint256 constant OneWordShift = 0x5; uint256 constant TwoWordsShift = 0x6; uint256 constant FreeMemoryPointerSlot = 0x40; uint256 constant ZeroSlot = 0x60; uint256 constant DefaultFreeMemoryPointer = 0x80; uint256 constant Slot0x80 = 0x80; uint256 constant Slot0xA0 = 0xa0; uint256 constant Slot0xC0 = 0xc0; uint256 constant Generic_error_selector_offset = 0x1c; // abi.encodeWithSignature("transferFrom(address,address,uint256)") uint256 constant ERC20_transferFrom_signature = (0x23b872dd00000000000000000000000000000000000000000000000000000000); uint256 constant ERC20_transferFrom_sig_ptr = 0x0; uint256 constant ERC20_transferFrom_from_ptr = 0x04; uint256 constant ERC20_transferFrom_to_ptr = 0x24; uint256 constant ERC20_transferFrom_amount_ptr = 0x44; uint256 constant ERC20_transferFrom_length = 0x64; // 4 + 32 * 3 == 100 // abi.encodeWithSignature( // "safeTransferFrom(address,address,uint256,uint256,bytes)" // ) uint256 constant ERC1155_safeTransferFrom_signature = ( 0xf242432a00000000000000000000000000000000000000000000000000000000 ); uint256 constant ERC1155_safeTransferFrom_sig_ptr = 0x0; uint256 constant ERC1155_safeTransferFrom_from_ptr = 0x04; uint256 constant ERC1155_safeTransferFrom_to_ptr = 0x24; uint256 constant ERC1155_safeTransferFrom_id_ptr = 0x44; uint256 constant ERC1155_safeTransferFrom_amount_ptr = 0x64; uint256 constant ERC1155_safeTransferFrom_data_offset_ptr = 0x84; uint256 constant ERC1155_safeTransferFrom_data_length_ptr = 0xa4; uint256 constant ERC1155_safeTransferFrom_length = 0xc4; // 4 + 32 * 6 == 196 uint256 constant ERC1155_safeTransferFrom_data_length_offset = 0xa0; // abi.encodeWithSignature( // "safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)" // ) uint256 constant ERC1155_safeBatchTransferFrom_signature = ( 0x2eb2c2d600000000000000000000000000000000000000000000000000000000 ); // bytes4 constant ERC1155_safeBatchTransferFrom_selector = bytes4( // bytes32(ERC1155_safeBatchTransferFrom_signature) // ); uint256 constant ERC721_transferFrom_signature = (0x23b872dd00000000000000000000000000000000000000000000000000000000); uint256 constant ERC721_transferFrom_sig_ptr = 0x0; uint256 constant ERC721_transferFrom_from_ptr = 0x04; uint256 constant ERC721_transferFrom_to_ptr = 0x24; uint256 constant ERC721_transferFrom_id_ptr = 0x44; uint256 constant ERC721_transferFrom_length = 0x64; // 4 + 32 * 3 == 100 /* * error NoContract(address account) * - Defined in TokenTransferrerErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x00: account * Revert buffer is memory[0x1c:0x40] */ uint256 constant NoContract_error_selector = 0x5f15d672; uint256 constant NoContract_error_account_ptr = 0x20; uint256 constant NoContract_error_length = 0x24; /* * error TokenTransferGenericFailure( * address token, * address from, * address to, * uint256 identifier, * uint256 amount * ) * - Defined in TokenTransferrerErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: token * - 0x40: from * - 0x60: to * - 0x80: identifier * - 0xa0: amount * Revert buffer is memory[0x1c:0xc0] */ uint256 constant TokenTransferGenericFailure_error_selector = 0xf486bc87; uint256 constant TokenTransferGenericFailure_error_token_ptr = 0x20; uint256 constant TokenTransferGenericFailure_error_from_ptr = 0x40; uint256 constant TokenTransferGenericFailure_error_to_ptr = 0x60; uint256 constant TokenTransferGenericFailure_error_identifier_ptr = 0x80; uint256 constant TokenTransferGenericFailure_err_identifier_ptr = 0x80; uint256 constant TokenTransferGenericFailure_error_amount_ptr = 0xa0; uint256 constant TokenTransferGenericFailure_error_length = 0xa4; uint256 constant ExtraGasBuffer = 0x20; uint256 constant CostPerWord = 0x3; uint256 constant MemoryExpansionCoefficientShift = 0x9; // Values are offset by 32 bytes in order to write the token to the beginning // in the event of a revert uint256 constant BatchTransfer1155Params_ptr = 0x24; uint256 constant BatchTransfer1155Params_ids_head_ptr = 0x64; uint256 constant BatchTransfer1155Params_amounts_head_ptr = 0x84; uint256 constant BatchTransfer1155Params_data_head_ptr = 0xa4; uint256 constant BatchTransfer1155Params_data_length_basePtr = 0xc4; uint256 constant BatchTransfer1155Params_calldata_baseSize = 0xc4; uint256 constant BatchTransfer1155Params_ids_length_ptr = 0xc4; uint256 constant BatchTransfer1155Params_ids_length_offset = 0xa0; // uint256 constant BatchTransfer1155Params_amounts_length_baseOffset = 0xc0; // uint256 constant BatchTransfer1155Params_data_length_baseOffset = 0xe0; uint256 constant ConduitBatch1155Transfer_usable_head_size = 0x80; uint256 constant ConduitBatch1155Transfer_from_offset = 0x20; uint256 constant ConduitBatch1155Transfer_ids_head_offset = 0x60; // uint256 constant ConduitBatch1155Transfer_amounts_head_offset = 0x80; uint256 constant ConduitBatch1155Transfer_ids_length_offset = 0xa0; uint256 constant ConduitBatch1155Transfer_amounts_length_baseOffset = 0xc0; // uint256 constant ConduitBatch1155Transfer_calldata_baseSize = 0xc0; // Note: abbreviated version of above constant to adhere to line length limit. uint256 constant ConduitBatchTransfer_amounts_head_offset = 0x80; uint256 constant Invalid1155BatchTransferEncoding_ptr = 0x00; uint256 constant Invalid1155BatchTransferEncoding_length = 0x04; uint256 constant Invalid1155BatchTransferEncoding_selector = ( 0xeba2084c00000000000000000000000000000000000000000000000000000000 ); uint256 constant ERC1155BatchTransferGenericFailure_error_signature = ( 0xafc445e200000000000000000000000000000000000000000000000000000000 ); uint256 constant ERC1155BatchTransferGenericFailure_token_ptr = 0x04; uint256 constant ERC1155BatchTransferGenericFailure_ids_offset = 0xc0; /* * error BadReturnValueFromERC20OnTransfer( * address token, address from, address to, uint256 amount * ) * - Defined in TokenTransferrerErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x00: token * - 0x20: from * - 0x40: to * - 0x60: amount * Revert buffer is memory[0x1c:0xa0] */ uint256 constant BadReturnValueFromERC20OnTransfer_error_selector = 0x98891923; uint256 constant BadReturnValueFromERC20OnTransfer_error_token_ptr = 0x20; uint256 constant BadReturnValueFromERC20OnTransfer_error_from_ptr = 0x40; uint256 constant BadReturnValueFromERC20OnTransfer_error_to_ptr = 0x60; uint256 constant BadReturnValueFromERC20OnTransfer_error_amount_ptr = 0x80; uint256 constant BadReturnValueFromERC20OnTransfer_error_length = 0x84; // error ChannelClosed(address channel) uint256 constant ChannelClosed_error_signature = (0x93daadf200000000000000000000000000000000000000000000000000000000); uint256 constant ChannelClosed_error_ptr = 0x00; uint256 constant ChannelClosed_channel_ptr = 0x4; uint256 constant ChannelClosed_error_length = 0x24; // For the mapping: // mapping(address => bool) channels // The position in storage for a particular account is: // keccak256(abi.encode(account, channels.slot)) uint256 constant ChannelKey_channel_ptr = 0x00; uint256 constant ChannelKey_slot_ptr = 0x20; uint256 constant ChannelKey_length = 0x40;
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; enum ConduitItemType { NATIVE, // unused ERC20, ERC721, ERC1155 } struct ConduitTransfer { ConduitItemType itemType; address collection; address from; address to; uint256 identifier; uint256 amount; } struct ConduitBatch1155Transfer { address collection; address from; address to; uint256[] ids; uint256[] amounts; } interface ICyanConduit { error ChannelClosed(address channel); error ChannelStatusAlreadySet(address channel, bool isOpen); error InvalidItemType(); error InvalidAdmin(); event ChannelUpdated(address indexed channel, bool open); function execute(ConduitTransfer[] calldata transfers) external returns (bytes4 magicValue); function executeBatch1155(ConduitBatch1155Transfer[] calldata batch1155Transfers) external returns (bytes4 magicValue); function executeWithBatch1155( ConduitTransfer[] calldata standardTransfers, ConduitBatch1155Transfer[] calldata batch1155Transfers ) external returns (bytes4 magicValue); function transferERC20( address from, address to, address token, uint256 amount ) external; function transferERC721( address from, address to, address collection, uint256 tokenId ) external; function transferERC1155( address from, address to, address collection, uint256 tokenId, uint256 amount ) external; function updateChannel(address channel, bool isOpen) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; /** * @title ITokenTransferrerErrors */ interface ITokenTransferrerErrors { /** * @dev Revert with an error when an ERC721 transfer with amount other than * one is attempted. * * @param amount The amount of the ERC721 tokens to transfer. */ error InvalidERC721TransferAmount(uint256 amount); /** * @dev Revert with an error when attempting to fulfill an order where an * item has an amount of zero. */ error MissingItemAmount(); /** * @dev Revert with an error when attempting to fulfill an order where an * item has unused parameters. This includes both the token and the * identifier parameters for native transfers as well as the identifier * parameter for ERC20 transfers. Note that the conduit does not * perform this check, leaving it up to the calling channel to enforce * when desired. */ error UnusedItemParameters(); /** * @dev Revert with an error when an ERC20, ERC721, or ERC1155 token * transfer reverts. * * @param token The token for which the transfer was attempted. * @param from The source of the attempted transfer. * @param to The recipient of the attempted transfer. * @param identifier The identifier for the attempted transfer. * @param amount The amount for the attempted transfer. */ error TokenTransferGenericFailure(address token, address from, address to, uint256 identifier, uint256 amount); /** * @dev Revert with an error when a batch ERC1155 token transfer reverts. * * @param token The token for which the transfer was attempted. * @param from The source of the attempted transfer. * @param to The recipient of the attempted transfer. * @param identifiers The identifiers for the attempted transfer. * @param amounts The amounts for the attempted transfer. */ error ERC1155BatchTransferGenericFailure( address token, address from, address to, uint256[] identifiers, uint256[] amounts ); /** * @dev Revert with an error when an ERC20 token transfer returns a falsey * value. * * @param token The token for which the ERC20 transfer was attempted. * @param from The source of the attempted ERC20 transfer. * @param to The recipient of the attempted ERC20 transfer. * @param amount The amount for the attempted ERC20 transfer. */ error BadReturnValueFromERC20OnTransfer(address token, address from, address to, uint256 amount); /** * @dev Revert with an error when an account being called as an assumed * contract does not have code and returns no data. * * @param account The account that should contain code. */ error NoContract(address account); /** * @dev Revert with an error when attempting to execute an 1155 batch * transfer using calldata not produced by default ABI encoding or with * different lengths for ids and amounts arrays. */ error Invalid1155BatchTransferEncoding(); }
{ "optimizer": { "enabled": true, "runs": 500 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BadReturnValueFromERC20OnTransfer","type":"error"},{"inputs":[{"internalType":"address","name":"channel","type":"address"}],"name":"ChannelClosed","type":"error"},{"inputs":[{"internalType":"address","name":"channel","type":"address"},{"internalType":"bool","name":"isOpen","type":"bool"}],"name":"ChannelStatusAlreadySet","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"identifiers","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"ERC1155BatchTransferGenericFailure","type":"error"},{"inputs":[],"name":"Invalid1155BatchTransferEncoding","type":"error"},{"inputs":[],"name":"InvalidAdmin","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InvalidERC721TransferAmount","type":"error"},{"inputs":[],"name":"InvalidItemType","type":"error"},{"inputs":[],"name":"MissingItemAmount","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NoContract","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenTransferGenericFailure","type":"error"},{"inputs":[],"name":"UnusedItemParameters","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"channel","type":"address"},{"indexed":false,"internalType":"bool","name":"open","type":"bool"}],"name":"ChannelUpdated","type":"event"},{"inputs":[{"components":[{"internalType":"enum ConduitItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ConduitTransfer[]","name":"transfers","type":"tuple[]"}],"name":"execute","outputs":[{"internalType":"bytes4","name":"magicValue","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct ConduitBatch1155Transfer[]","name":"batchTransfers","type":"tuple[]"}],"name":"executeBatch1155","outputs":[{"internalType":"bytes4","name":"magicValue","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum ConduitItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ConduitTransfer[]","name":"standardTransfers","type":"tuple[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct ConduitBatch1155Transfer[]","name":"batchTransfers","type":"tuple[]"}],"name":"executeWithBatch1155","outputs":[{"internalType":"bytes4","name":"magicValue","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"updateAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"channel","type":"address"},{"internalType":"bool","name":"isOpen","type":"bool"}],"name":"updateChannel","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50600080546001600160a01b03191633179055610cc6806100326000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c80638df25d921161005b5780638df25d9214610110578063c4e8fcb514610123578063da3e8ce414610136578063e2f273bd1461014957600080fd5b80634ce34aa21461008d57806374a9402e146100d5578063789f93f6146100ea578063899e104c146100fd575b600080fd5b6100a061009b366004610a00565b61015c565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b6100e86100e3366004610a5e565b6101cb565b005b6100e86100f8366004610ab3565b610207565b6100a061010b366004610b43565b610241565b6100a061011e366004610baf565b6102b1565b6100e8610131366004610be5565b6102f4565b6100e8610144366004610ab3565b6103d7565b6100e8610157366004610c21565b61040b565b6000336000526001602052604060002054610186576349ed56f960e11b6000523360045260246000fd5b8160005b818110156101ba576101b28585838181106101a7576101a7610c43565b905060c00201610465565b60010161018a565b50632671a55160e11b949350505050565b3360005260016020526040600020546101f3576349ed56f960e11b6000523360045260246000fd5b61020083868685856105d7565b5050505050565b33600052600160205260406000205461022f576349ed56f960e11b6000523360045260246000fd5b61023b828585846106b7565b50505050565b600033600052600160205260406000205461026b576349ed56f960e11b6000523360045260246000fd5b8360005b818110156102945761028c8787838181106101a7576101a7610c43565b60010161026f565b5061029f8484610774565b50632267841360e21b95945050505050565b60003360005260016020526040600020546102db576349ed56f960e11b6000523360045260246000fd5b6102e58383610774565b506346f92ec960e11b92915050565b6000546001600160a01b0316331461031f57604051630b5eba9f60e41b815260040160405180910390fd5b6001600160a01b03821660009081526001602052604090205481151560ff909116151503610378576040516349271a0f60e11b81526001600160a01b038316600482015281151560248201526044015b60405180910390fd5b6001600160a01b038216600081815260016020908152604091829020805460ff191685151590811790915591519182527fae63067d43ac07563b7eb8db6595635fc77f1578a2a5ea06ba91b63e2afa37e2910160405180910390a25050565b3360005260016020526040600020546103ff576349ed56f960e11b6000523360045260246000fd5b61023b828585846108b5565b6000546001600160a01b0316331461043657604051630b5eba9f60e41b815260040160405180910390fd5b6000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b60016104746020830183610c6f565b600381111561048557610485610c59565b036104ca576104c761049d6040830160208401610c21565b6104ad6060840160408501610c21565b6104bd6080850160608601610c21565b8460a001356108b5565b50565b60026104d96020830183610c6f565b60038111156104ea576104ea610c59565b03610557578060a0013560011461051a576040516369f9582760e01b815260a0820135600482015260240161036f565b6104c761052d6040830160208401610c21565b61053d6060840160408501610c21565b61054d6080850160608601610c21565b84608001356106b7565b60036105666020830183610c6f565b600381111561057757610577610c59565b036105be576104c761058f6040830160208401610c21565b61059f6060840160408501610c21565b6105af6080850160608601610c21565b84608001358560a001356105d7565b604051631e4cbc7f60e21b815260040160405180910390fd5b843b6105ef57635f15d672600052846020526024601cfd5b60405160805160a05160c051637921219560e11b6000528760045286602452856044528460645260a0608452600060a45260008060c46000808d5af18061069b573d1561067957601f3d0160051c8560051c8160030281831115610660578183036003028280028480020360091c01015b5a602082011015610675573d6000803e3d6000fd5b5050505b63f486bc87600052896020528860405287606052866080528560a05260a4601cfd5b5060809290925260a05260c05260405250506000606052505050565b833b6106cf57635f15d672600052836020526024601cfd5b6040516323b872dd60e01b6000528360045282602452816044526000806064600080895af180610765573d1561074257601f3d0160051c8260051c8160030281831115610729578183036003028280028480020360091c01015b5a60208201101561073e573d6000803e3d6000fd5b5050505b63f486bc8760005285602052846040528360605282608052600160a05260a4601cfd5b50604052505060006060525050565b808280631759616b60e11b60205260005b838110156108a857823582018035803b6107ab57635f15d672600052806020526024601cfd5b60a08201358060051b60c0018060808501351460a0606086013514168185013583141615905080156107e857633ae8821360e21b60005260046000fd5b506020860195506080602084016024378060061b60400190508060a00160a45260008160c401528060c4018160a0850160c4376000808260206000875af1935083610899573d1561087757601f3d0160051c91508060051c826003028184111561085f578184036003028280028580020360091c01015b5a602082011015610874573d6000803e3d6000fd5b50505b6357e222f160e11b6000528260045260c0606452608451602001608452806000fd5b50505050600181019050610785565b5050505060806040525050565b6040516323b872dd60e01b600052836004528260245281604452602060006064600080895af1803d15601f3d116001600051141617163d151581166109a45780873b1515166109a457806109925781610974573d1561095157601f3d0160051c8360051c8160030281831115610938578183036003028280028480020360091c01015b5a60208201101561094d573d6000803e3d6000fd5b5050505b63f486bc8760005286602052856040528460605260006080528360a05260a4601cfd5b6398891923600052866020528560405284606052836080526084601cfd5b635f15d672600052866020526024601cfd5b5050604052505060006060525050565b60008083601f8401126109c657600080fd5b50813567ffffffffffffffff8111156109de57600080fd5b60208301915083602060c0830285010111156109f957600080fd5b9250929050565b60008060208385031215610a1357600080fd5b823567ffffffffffffffff811115610a2a57600080fd5b610a36858286016109b4565b90969095509350505050565b80356001600160a01b0381168114610a5957600080fd5b919050565b600080600080600060a08688031215610a7657600080fd5b610a7f86610a42565b9450610a8d60208701610a42565b9350610a9b60408701610a42565b94979396509394606081013594506080013592915050565b60008060008060808587031215610ac957600080fd5b610ad285610a42565b9350610ae060208601610a42565b9250610aee60408601610a42565b9396929550929360600135925050565b60008083601f840112610b1057600080fd5b50813567ffffffffffffffff811115610b2857600080fd5b6020830191508360208260051b85010111156109f957600080fd5b60008060008060408587031215610b5957600080fd5b843567ffffffffffffffff80821115610b7157600080fd5b610b7d888389016109b4565b90965094506020870135915080821115610b9657600080fd5b50610ba387828801610afe565b95989497509550505050565b60008060208385031215610bc257600080fd5b823567ffffffffffffffff811115610bd957600080fd5b610a3685828601610afe565b60008060408385031215610bf857600080fd5b610c0183610a42565b915060208301358015158114610c1657600080fd5b809150509250929050565b600060208284031215610c3357600080fd5b610c3c82610a42565b9392505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215610c8157600080fd5b813560048110610c3c57600080fdfea2646970667358221220c26a2fcf8a12b910cd4a5907f34b8a555e088cfb821a044330bf829c7265a51a64736f6c63430008130033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100885760003560e01c80638df25d921161005b5780638df25d9214610110578063c4e8fcb514610123578063da3e8ce414610136578063e2f273bd1461014957600080fd5b80634ce34aa21461008d57806374a9402e146100d5578063789f93f6146100ea578063899e104c146100fd575b600080fd5b6100a061009b366004610a00565b61015c565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b6100e86100e3366004610a5e565b6101cb565b005b6100e86100f8366004610ab3565b610207565b6100a061010b366004610b43565b610241565b6100a061011e366004610baf565b6102b1565b6100e8610131366004610be5565b6102f4565b6100e8610144366004610ab3565b6103d7565b6100e8610157366004610c21565b61040b565b6000336000526001602052604060002054610186576349ed56f960e11b6000523360045260246000fd5b8160005b818110156101ba576101b28585838181106101a7576101a7610c43565b905060c00201610465565b60010161018a565b50632671a55160e11b949350505050565b3360005260016020526040600020546101f3576349ed56f960e11b6000523360045260246000fd5b61020083868685856105d7565b5050505050565b33600052600160205260406000205461022f576349ed56f960e11b6000523360045260246000fd5b61023b828585846106b7565b50505050565b600033600052600160205260406000205461026b576349ed56f960e11b6000523360045260246000fd5b8360005b818110156102945761028c8787838181106101a7576101a7610c43565b60010161026f565b5061029f8484610774565b50632267841360e21b95945050505050565b60003360005260016020526040600020546102db576349ed56f960e11b6000523360045260246000fd5b6102e58383610774565b506346f92ec960e11b92915050565b6000546001600160a01b0316331461031f57604051630b5eba9f60e41b815260040160405180910390fd5b6001600160a01b03821660009081526001602052604090205481151560ff909116151503610378576040516349271a0f60e11b81526001600160a01b038316600482015281151560248201526044015b60405180910390fd5b6001600160a01b038216600081815260016020908152604091829020805460ff191685151590811790915591519182527fae63067d43ac07563b7eb8db6595635fc77f1578a2a5ea06ba91b63e2afa37e2910160405180910390a25050565b3360005260016020526040600020546103ff576349ed56f960e11b6000523360045260246000fd5b61023b828585846108b5565b6000546001600160a01b0316331461043657604051630b5eba9f60e41b815260040160405180910390fd5b6000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b60016104746020830183610c6f565b600381111561048557610485610c59565b036104ca576104c761049d6040830160208401610c21565b6104ad6060840160408501610c21565b6104bd6080850160608601610c21565b8460a001356108b5565b50565b60026104d96020830183610c6f565b60038111156104ea576104ea610c59565b03610557578060a0013560011461051a576040516369f9582760e01b815260a0820135600482015260240161036f565b6104c761052d6040830160208401610c21565b61053d6060840160408501610c21565b61054d6080850160608601610c21565b84608001356106b7565b60036105666020830183610c6f565b600381111561057757610577610c59565b036105be576104c761058f6040830160208401610c21565b61059f6060840160408501610c21565b6105af6080850160608601610c21565b84608001358560a001356105d7565b604051631e4cbc7f60e21b815260040160405180910390fd5b843b6105ef57635f15d672600052846020526024601cfd5b60405160805160a05160c051637921219560e11b6000528760045286602452856044528460645260a0608452600060a45260008060c46000808d5af18061069b573d1561067957601f3d0160051c8560051c8160030281831115610660578183036003028280028480020360091c01015b5a602082011015610675573d6000803e3d6000fd5b5050505b63f486bc87600052896020528860405287606052866080528560a05260a4601cfd5b5060809290925260a05260c05260405250506000606052505050565b833b6106cf57635f15d672600052836020526024601cfd5b6040516323b872dd60e01b6000528360045282602452816044526000806064600080895af180610765573d1561074257601f3d0160051c8260051c8160030281831115610729578183036003028280028480020360091c01015b5a60208201101561073e573d6000803e3d6000fd5b5050505b63f486bc8760005285602052846040528360605282608052600160a05260a4601cfd5b50604052505060006060525050565b808280631759616b60e11b60205260005b838110156108a857823582018035803b6107ab57635f15d672600052806020526024601cfd5b60a08201358060051b60c0018060808501351460a0606086013514168185013583141615905080156107e857633ae8821360e21b60005260046000fd5b506020860195506080602084016024378060061b60400190508060a00160a45260008160c401528060c4018160a0850160c4376000808260206000875af1935083610899573d1561087757601f3d0160051c91508060051c826003028184111561085f578184036003028280028580020360091c01015b5a602082011015610874573d6000803e3d6000fd5b50505b6357e222f160e11b6000528260045260c0606452608451602001608452806000fd5b50505050600181019050610785565b5050505060806040525050565b6040516323b872dd60e01b600052836004528260245281604452602060006064600080895af1803d15601f3d116001600051141617163d151581166109a45780873b1515166109a457806109925781610974573d1561095157601f3d0160051c8360051c8160030281831115610938578183036003028280028480020360091c01015b5a60208201101561094d573d6000803e3d6000fd5b5050505b63f486bc8760005286602052856040528460605260006080528360a05260a4601cfd5b6398891923600052866020528560405284606052836080526084601cfd5b635f15d672600052866020526024601cfd5b5050604052505060006060525050565b60008083601f8401126109c657600080fd5b50813567ffffffffffffffff8111156109de57600080fd5b60208301915083602060c0830285010111156109f957600080fd5b9250929050565b60008060208385031215610a1357600080fd5b823567ffffffffffffffff811115610a2a57600080fd5b610a36858286016109b4565b90969095509350505050565b80356001600160a01b0381168114610a5957600080fd5b919050565b600080600080600060a08688031215610a7657600080fd5b610a7f86610a42565b9450610a8d60208701610a42565b9350610a9b60408701610a42565b94979396509394606081013594506080013592915050565b60008060008060808587031215610ac957600080fd5b610ad285610a42565b9350610ae060208601610a42565b9250610aee60408601610a42565b9396929550929360600135925050565b60008083601f840112610b1057600080fd5b50813567ffffffffffffffff811115610b2857600080fd5b6020830191508360208260051b85010111156109f957600080fd5b60008060008060408587031215610b5957600080fd5b843567ffffffffffffffff80821115610b7157600080fd5b610b7d888389016109b4565b90965094506020870135915080821115610b9657600080fd5b50610ba387828801610afe565b95989497509550505050565b60008060208385031215610bc257600080fd5b823567ffffffffffffffff811115610bd957600080fd5b610a3685828601610afe565b60008060408385031215610bf857600080fd5b610c0183610a42565b915060208301358015158114610c1657600080fd5b809150509250929050565b600060208284031215610c3357600080fd5b610c3c82610a42565b9392505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215610c8157600080fd5b813560048110610c3c57600080fdfea2646970667358221220c26a2fcf8a12b910cd4a5907f34b8a555e088cfb821a044330bf829c7265a51a64736f6c63430008130033
Loading...
Loading
Loading...
Loading
[ 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.