UNPKG

bnpl

Version:

The smart contracts for bnpl

29 lines 334 kB
{ "language": "Solidity", "sources": { "contracts/BNPL.sol": { "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.13;\n\nimport {\n Consideration\n} from \"./lib/Consideration.sol\";\n\ncontract BNPL is Consideration {\n\n constructor(address conduitController, address shadowToken) Consideration(conduitController, shadowToken) {}\n\n function _nameString() internal pure override returns (string memory) {\n return \"BNPL\";\n }\n}" }, "contracts/lib/Consideration.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport {\n OrderParameters,\n OrderComponents,\n OrderStatus,\n Order\n} from \"./ConsiderationStructs.sol\";\n\nimport {\n OrderFulfiller\n} from \"./OrderFulfiller.sol\";\n\ncontract Consideration is OrderFulfiller {\n\n mapping(bytes32 => OrderStatus) private _orderStatus;\n\n constructor(address conduitController, address shadowToken) OrderFulfiller(conduitController, shadowToken) {}\n\n function fulfillOrder(Order calldata order, bytes32 fulfillerConduitKey)\n external\n payable\n returns (bool fulfilled)\n {\n fulfilled = _validateAndFulfillOrder(order, fulfillerConduitKey);\n }\n\n function repayOrder(OrderParameters calldata parameters, bytes32 fulfillerConduitKey, uint256 payTimes)\n external\n payable\n returns (bool repaid)\n {\n repaid = _validateAndRepayOrder(parameters, fulfillerConduitKey, payTimes);\n }\n\n function breakOrder(OrderParameters calldata parameters)\n external\n returns (bool broken)\n {\n broken = _validateAndBreakOrder(parameters);\n }\n\n function cancel(OrderComponents[] calldata orders)\n external\n returns (bool cancelled)\n {\n cancelled = _cancel(orders);\n }\n\n function validate(Order[] calldata orders)\n external\n returns (bool validated)\n {\n validated = _validate(orders);\n }\n\n function incrementCounter() external returns (uint256 newCounter) {\n newCounter = _incrementCounter();\n }\n\n function getOrderHash(OrderComponents calldata order)\n external\n view\n returns (bytes32 orderHash)\n {\n orderHash = _deriveOrderHash(\n OrderParameters(\n order.offerer,\n order.token,\n order.identifier,\n order.currency,\n order.artist,\n order.platform,\n order.startTime,\n order.endTime,\n order.duration,\n order.periods,\n order.amount,\n order.ratio,\n order.royalty,\n order.fee,\n order.withdrawFee,\n order.salt,\n order.conduitKey\n ),\n order.counter\n );\n }\n\n function getOrderStatus(bytes32 orderHash)\n external\n view\n returns (\n bool isValidated,\n bool isCancelled,\n bool isFinalized,\n bool isBroken,\n address fulfiller,\n uint256 startedAt,\n uint256 shadowId,\n uint256 paidTimes\n )\n {\n return _getOrderStatus(orderHash);\n }\n\n function getCounter(address offerer)\n external\n view\n returns (uint256 counter)\n {\n counter = _getCounter(offerer);\n }\n\n function information()\n external\n view\n returns (\n string memory version,\n bytes32 domainSeparator,\n address conduitController\n )\n {\n return _information();\n }\n}" }, "contracts/lib/ConsiderationStructs.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nstruct OrderComponents {\n address offerer;\n address token;\n uint256 identifier;\n address currency;\n address artist;\n address platform;\n uint256 startTime;\n uint256 endTime;\n uint256 duration;\n uint256 periods;\n uint256 amount;\n uint256 ratio;\n uint256 royalty;\n uint256 fee;\n uint256 withdrawFee;\n uint256 salt;\n bytes32 conduitKey;\n uint256 counter;\n}\n\nstruct OrderParameters {\n address offerer; // 0x00\n address token; // 0x20\n uint256 identifier; // 0x40\n address currency; // 0x60\n address artist; // 0x80\n address platform; // 0xa0\n uint256 startTime; // 0xc0\n uint256 endTime; // 0xe0\n uint256 duration; // 0x100\n uint256 periods; // 0x120\n uint256 amount; // 0x140\n uint256 ratio; // 0x160\n uint256 royalty; // 0x180\n uint256 fee; // 0x1a0\n uint256 withdrawFee;// 0x1c0\n uint256 salt; // 0x1e0\n bytes32 conduitKey; // 0x200\n}\n\nstruct Order {\n OrderParameters parameters;\n bytes signature;\n}\n\nstruct OrderStatus {\n bool isValidated;\n bool isCancelled;\n bool isFinalized;\n bool isBroken;\n address fulfiller;\n uint256 startedAt;\n uint256 shadowId;\n uint256 paidTimes;\n}" }, "contracts/lib/OrderFulfiller.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { ConduitInterface } from \"../interfaces/ConduitInterface.sol\";\n\nimport {\n ItemType\n} from \"./ConsiderationEnums.sol\";\n\nimport {\n Order,\n OrderParameters\n} from \"./ConsiderationStructs.sol\";\n\nimport { OrderValidator } from \"./OrderValidator.sol\";\n\nimport \"./ConsiderationConstants.sol\";\n\ncontract OrderFulfiller is OrderValidator {\n\n struct Dispatch {\n uint256 payment;\n uint256 toOfferer;\n uint256 toPlatform;\n uint256 toArtist;\n }\n\n constructor(address conduitController, address shadowToken) OrderValidator(conduitController, shadowToken) {}\n\n function _calculateDispatch(\n OrderParameters calldata params,\n uint256 payTimes,\n bool isFirst,\n bool isFinalize\n )\n internal\n pure\n returns (Dispatch memory ret)\n {\n uint256 royalty;\n uint256 paidTimes = params.periods - payTimes;\n\n ret.toPlatform = params.withdrawFee;\n if (isFinalize) {\n royalty = params.royalty - paidTimes * (params.royalty / params.periods);\n ret.payment = params.amount - paidTimes* (params.amount / params.periods);\n ret.toOfferer = params.amount - (params.amount / params.periods) * params.ratio / 10000 * paidTimes - ret.toPlatform - royalty;\n ret.toArtist = params.royalty;\n } else {\n royalty = payTimes * (params.royalty / params.periods);\n ret.payment = payTimes * (params.amount / params.periods); \n ret.toOfferer = ret.payment * params.ratio / 10000 - ret.toPlatform - royalty;\n if (isFirst) {\n ret.payment += params.fee;\n ret.toPlatform += params.fee;\n }\n }\n }\n\n function _validateAndFulfillOrder(Order calldata order, bytes32 fulfillerConduitKey)\n internal\n returns (bool)\n {\n (\n bytes32 orderHash,\n bool valid,\n uint256 shadowId\n ) = _validateOrderAndUpdateStatus(\n order,\n true\n );\n\n if (!valid) {\n return false;\n }\n\n OrderParameters calldata orderParameters = order.parameters;\n Dispatch memory dispatch = _calculateDispatch(orderParameters, 1, true, false);\n\n if (orderParameters.currency == address(0)) {\n _transferIndividual721Or1155Item(\n ItemType.ERC721,\n orderParameters.token,\n orderParameters.offerer,\n address(this),\n orderParameters.identifier,\n 1,\n orderParameters.conduitKey\n );\n\n _transferEthAndFinalize(orderParameters, dispatch);\n } else {\n bytes memory accumulator = new bytes(AccumulatorDisarmed);\n _transferERC721(\n orderParameters.token,\n orderParameters.offerer,\n address(this),\n orderParameters.identifier,\n 1,\n orderParameters.conduitKey,\n accumulator\n );\n\n _transferERC20AndFinalize(\n orderParameters,\n dispatch,\n fulfillerConduitKey,\n accumulator\n );\n }\n\n emit OrderFulfilled(\n orderHash,\n orderParameters.offerer,\n shadowId\n );\n\n return true;\n }\n\n function _validateAndRepayOrder(OrderParameters calldata parameters, bytes32 fulfillerConduitKey, uint256 payTimes)\n internal\n returns (bool)\n {\n bytes32 orderHash;\n address fulfiller;\n bool isFinalized;\n {\n bool valid;\n (\n orderHash,\n fulfiller,\n valid,\n isFinalized\n ) = _validateOrderAndUpdateRepayStatus(\n parameters,\n payTimes,\n true\n );\n\n if (!valid) {\n return false;\n }\n }\n\n Dispatch memory dispatch = _calculateDispatch(parameters, payTimes, false, isFinalized);\n\n if (parameters.currency == address(0)) {\n _transferEthAndFinalize(parameters, dispatch);\n } else {\n bytes memory accumulator = new bytes(AccumulatorDisarmed);\n _transferERC20AndFinalize(\n parameters,\n dispatch,\n fulfillerConduitKey,\n accumulator\n );\n }\n\n if (isFinalized) {\n _transferIndividual721Or1155Item(\n ItemType.ERC721,\n parameters.token,\n address(this),\n fulfiller,\n parameters.identifier,\n 1,\n bytes32(0)\n );\n }\n\n emit OrderRepaid(\n orderHash,\n payTimes,\n isFinalized\n );\n\n return true;\n }\n\n function _validateAndBreakOrder(OrderParameters calldata parameters)\n internal\n returns (bool)\n {\n (\n bytes32 orderHash,\n uint256 paidTimes,\n bool valid\n ) = _validateOrderAndUpdateBreakStatus(\n parameters,\n true\n );\n\n if (!valid) {\n return false;\n }\n\n _transferIndividual721Or1155Item(\n ItemType.ERC721,\n parameters.token,\n address(this),\n parameters.offerer,\n parameters.identifier,\n 1,\n bytes32(0)\n );\n\n if (parameters.currency == address(0)) {\n _transferEthBroken(parameters, paidTimes);\n } else {\n _transferERC20Broken(\n parameters,\n paidTimes\n );\n }\n\n emit OrderBroken(\n orderHash,\n parameters.offerer\n );\n\n return true;\n }\n\n function _transferEthBroken(\n OrderParameters calldata orderParameters,\n uint256 paidTimes\n ) internal {\n _transferEth(\n payable(orderParameters.offerer),\n orderParameters.royalty / orderParameters.periods * paidTimes\n );\n uint256 toPlatform = orderParameters.amount / orderParameters.periods * paidTimes;\n toPlatform = toPlatform - toPlatform * orderParameters.ratio / 10000;\n _transferEth(\n payable(orderParameters.platform),\n toPlatform\n );\n }\n\n function _transferERC20Broken(\n OrderParameters calldata parameters,\n uint256 paidTimes\n ) internal {\n _performSelfERC20Transfer(parameters.currency, parameters.offerer, parameters.royalty / parameters.periods * paidTimes);\n\n uint256 toPlatform = parameters.amount / parameters.periods * paidTimes;\n toPlatform = toPlatform - toPlatform * parameters.ratio / 10000;\n _performSelfERC20Transfer(parameters.currency, parameters.platform, toPlatform);\n }\n\n function _transferEthAndFinalize(\n OrderParameters calldata orderParameters,\n Dispatch memory dispatch\n ) internal {\n uint256 etherRemaining = msg.value;\n\n if (dispatch.payment > etherRemaining) {\n revert InsufficientEtherSupplied();\n }\n\n _transferEth(\n payable(orderParameters.offerer),\n dispatch.toOfferer\n );\n\n _transferEth(\n payable(orderParameters.platform),\n dispatch.toPlatform\n );\n\n if (dispatch.toArtist > 0) {\n _transferEth(\n payable(orderParameters.artist),\n dispatch.toArtist\n );\n }\n\n etherRemaining -= dispatch.payment;\n\n if (etherRemaining > 0) {\n unchecked {\n _transferEth(payable(msg.sender), etherRemaining);\n }\n }\n }\n\n function _transferERC20AndFinalize(\n OrderParameters calldata parameters,\n Dispatch memory dispatch,\n bytes32 conduitKey,\n bytes memory accumulator\n ) internal {\n address from = msg.sender;\n address token = parameters.currency;\n\n _transferERC20(\n token,\n from,\n parameters.platform,\n dispatch.toPlatform,\n conduitKey,\n accumulator\n );\n\n if (dispatch.toArtist > 0) {\n _transferERC20(\n token,\n from,\n parameters.artist,\n dispatch.toArtist,\n conduitKey,\n accumulator\n );\n }\n\n uint256 left = dispatch.payment - dispatch.toPlatform - dispatch.toArtist;\n if (left >= dispatch.toOfferer) {\n _transferERC20(\n token,\n from,\n parameters.offerer,\n dispatch.toOfferer,\n conduitKey,\n accumulator\n );\n left -= dispatch.toOfferer;\n if (left > 0) {\n _transferERC20(\n token,\n from,\n address(this),\n left,\n conduitKey,\n accumulator\n );\n }\n _triggerIfArmed(accumulator);\n } else {\n _transferERC20(\n token,\n from,\n parameters.offerer,\n left,\n conduitKey,\n accumulator\n );\n _triggerIfArmed(accumulator);\n\n _performSelfERC20Transfer(token, parameters.offerer, dispatch.toOfferer - left);\n }\n }\n}\n" }, "contracts/interfaces/ConduitInterface.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nimport {\n ConduitTransfer,\n ConduitBatch1155Transfer\n} from \"../conduit/lib/ConduitStructs.sol\";\n\n/**\n * @title ConduitInterface\n * @author 0age\n * @notice ConduitInterface contains all external function interfaces, events,\n * and errors for conduit contracts.\n */\ninterface ConduitInterface {\n /**\n * @dev Revert with an error when attempting to execute transfers using a\n * caller that does not have an open channel.\n */\n error ChannelClosed(address channel);\n\n /**\n * @dev Revert with an error when attempting to update a channel to the\n * current status of that channel.\n */\n error ChannelStatusAlreadySet(address channel, bool isOpen);\n\n /**\n * @dev Revert with an error when attempting to execute a transfer for an\n * item that does not have an ERC20/721/1155 item type.\n */\n error InvalidItemType();\n\n /**\n * @dev Revert with an error when attempting to update the status of a\n * channel from a caller that is not the conduit controller.\n */\n error InvalidController();\n\n /**\n * @dev Emit an event whenever a channel is opened or closed.\n *\n * @param channel The channel that has been updated.\n * @param open A boolean indicating whether the conduit is open or not.\n */\n event ChannelUpdated(address indexed channel, bool open);\n\n /**\n * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller\n * with an open channel can call this function.\n *\n * @param transfers The ERC20/721/1155 transfers to perform.\n *\n * @return magicValue A magic value indicating that the transfers were\n * performed successfully.\n */\n function execute(ConduitTransfer[] calldata transfers)\n external\n returns (bytes4 magicValue);\n\n /**\n * @notice Execute a sequence of batch 1155 transfers. Only a caller with an\n * open channel can call this function.\n *\n * @param batch1155Transfers The 1155 batch transfers to perform.\n *\n * @return magicValue A magic value indicating that the transfers were\n * performed successfully.\n */\n function executeBatch1155(\n ConduitBatch1155Transfer[] calldata batch1155Transfers\n ) external returns (bytes4 magicValue);\n\n /**\n * @notice Execute a sequence of transfers, both single and batch 1155. Only\n * a caller with an open channel can call this function.\n *\n * @param standardTransfers The ERC20/721/1155 transfers to perform.\n * @param batch1155Transfers The 1155 batch transfers to perform.\n *\n * @return magicValue A magic value indicating that the transfers were\n * performed successfully.\n */\n function executeWithBatch1155(\n ConduitTransfer[] calldata standardTransfers,\n ConduitBatch1155Transfer[] calldata batch1155Transfers\n ) external returns (bytes4 magicValue);\n\n /**\n * @notice Open or close a given channel. Only callable by the controller.\n *\n * @param channel The channel to open or close.\n * @param isOpen The status of the channel (either open or closed).\n */\n function updateChannel(address channel, bool isOpen) external;\n}\n" }, "contracts/lib/ConsiderationEnums.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nenum ItemType {\n NATIVE,\n ERC20,\n ERC721,\n ERC1155\n}" }, "contracts/lib/OrderValidator.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport {\n OrderParameters,\n Order,\n OrderComponents,\n OrderStatus\n} from \"./ConsiderationStructs.sol\";\n\nimport \"./ConsiderationConstants.sol\";\n\nimport { Executor } from \"./Executor.sol\";\nimport { Shadow } from \"./Shadow.sol\";\n\ncontract OrderValidator is Executor, Shadow {\n\n mapping(bytes32 => OrderStatus) private _orderStatus;\n\n constructor(address conduitController, address shadowToken) Executor(conduitController) Shadow(shadowToken) {}\n\n function _validateOrderAndUpdateStatus(\n Order calldata order,\n bool revertOnInvalid\n )\n internal\n returns (\n bytes32 orderHash,\n bool valid,\n uint256 shadowId\n )\n {\n OrderParameters calldata orderParameters = order.parameters;\n if (\n !_verifyTime(\n orderParameters.startTime,\n orderParameters.endTime,\n revertOnInvalid\n )\n ) {\n return (bytes32(0), false, 0);\n }\n\n if (orderParameters.periods < 2) {\n if (revertOnInvalid) {\n revert InvalidOrderParameters();\n }\n return (bytes32(0), false, 0);\n }\n\n orderHash = _deriveOrderHash(\n orderParameters,\n _getCounter(orderParameters.offerer)\n );\n\n OrderStatus storage orderStatus = _orderStatus[orderHash];\n\n if (\n !_verifyOrderStatus(\n orderHash,\n orderStatus,\n true,\n revertOnInvalid\n )\n ) {\n return (orderHash, false, 0);\n }\n\n if (!orderStatus.isValidated) {\n _verifySignature(\n orderParameters.offerer,\n orderHash,\n order.signature\n );\n }\n\n shadowId = _mintToken(\n msg.sender,\n orderParameters.token,\n orderParameters.identifier,\n orderParameters.duration\n );\n\n orderStatus.isValidated = true;\n orderStatus.isCancelled = false;\n orderStatus.isBroken = false;\n orderStatus.fulfiller = msg.sender;\n orderStatus.startedAt = block.timestamp;\n orderStatus.shadowId = shadowId;\n orderStatus.paidTimes = 1;\n\n valid = true;\n }\n\n function _validateOrderAndUpdateRepayStatus(\n OrderParameters calldata parameters,\n uint256 payTimes,\n bool revertOnInvalid\n )\n internal\n returns (\n bytes32 orderHash,\n address fulfiller,\n bool valid,\n bool isFinalized\n )\n {\n orderHash = _deriveOrderHash(\n parameters,\n _getCounter(parameters.offerer)\n );\n\n OrderStatus storage orderStatus = _orderStatus[orderHash];\n if (!orderStatus.isValidated) {\n if (revertOnInvalid) {\n revert OrderNotValidated(orderHash);\n }\n return (orderHash, address(0), false, false);\n }\n\n if (\n !_verifyOrderStatus(\n orderHash,\n orderStatus,\n false,\n revertOnInvalid\n )\n ) {\n return (orderHash, address(0), false, false);\n }\n\n if (orderStatus.paidTimes + payTimes > parameters.periods || payTimes < 1) {\n if (revertOnInvalid) {\n revert OrderInvalidRepayParameters(orderHash);\n }\n return (orderHash, address(0), false, false);\n }\n\n if (orderStatus.startedAt + orderStatus.paidTimes * parameters.duration < block.timestamp) {\n if (revertOnInvalid) {\n revert OrderExpired(orderHash);\n }\n return (orderHash, address(0), false, false);\n }\n\n orderStatus.paidTimes += payTimes;\n if (orderStatus.paidTimes == parameters.periods) {\n orderStatus.isFinalized = true;\n isFinalized = true;\n _burnToken(orderStatus.shadowId);\n } else {\n _extendToken(\n orderStatus.fulfiller,\n orderStatus.shadowId,\n orderStatus.startedAt + orderStatus.paidTimes * parameters.duration\n );\n }\n\n valid = true;\n fulfiller = orderStatus.fulfiller;\n }\n\n function _validateOrderAndUpdateBreakStatus(\n OrderParameters calldata parameters,\n bool revertOnInvalid\n )\n internal\n returns (\n bytes32 orderHash,\n uint256 paidTimes,\n bool valid\n )\n {\n orderHash = _deriveOrderHash(\n parameters,\n _getCounter(parameters.offerer)\n );\n\n OrderStatus storage orderStatus = _orderStatus[orderHash];\n if (!orderStatus.isValidated) {\n if (revertOnInvalid) {\n revert OrderNotValidated(orderHash);\n }\n return (orderHash, paidTimes, false);\n }\n\n paidTimes = orderStatus.paidTimes;\n\n if (\n !_verifyOrderStatus(\n orderHash,\n orderStatus,\n false,\n revertOnInvalid\n )\n ) {\n return (orderHash, paidTimes, false);\n }\n\n if (orderStatus.startedAt + paidTimes * parameters.duration > block.timestamp) {\n if (revertOnInvalid) {\n revert OrderNotExpired(orderHash);\n }\n return (orderHash, paidTimes, false);\n }\n\n _burnToken(orderStatus.shadowId);\n\n orderStatus.isFinalized = true;\n orderStatus.isBroken = true;\n valid = true;\n }\n\n function _cancel(OrderComponents[] calldata orders)\n internal\n returns (bool cancelled)\n {\n // Ensure that the reentrancy guard is not currently set.\n _assertNonReentrant();\n\n // Declare variables outside of the loop.\n OrderStatus storage orderStatus;\n address offerer;\n\n // Skip overflow check as for loop is indexed starting at zero.\n unchecked {\n // Read length of the orders array from memory and place on stack.\n uint256 totalOrders = orders.length;\n\n // Iterate over each order.\n for (uint256 i = 0; i < totalOrders; ) {\n // Retrieve the order.\n OrderComponents calldata order = orders[i];\n\n offerer = order.offerer;\n\n if (msg.sender != offerer) {\n revert InvalidCanceller();\n }\n\n // Derive order hash using the order parameters and the counter.\n bytes32 orderHash = _deriveOrderHash(\n OrderParameters(\n offerer,\n order.token,\n order.identifier,\n order.currency,\n order.artist,\n order.platform,\n order.startTime,\n order.endTime,\n order.duration,\n order.periods,\n order.amount,\n order.ratio,\n order.royalty,\n order.fee,\n order.withdrawFee,\n order.salt,\n order.conduitKey\n ),\n order.counter\n );\n\n // Retrieve the order status using the derived order hash.\n orderStatus = _orderStatus[orderHash];\n\n if (orderStatus.startedAt > 0) {\n revert OrderAlreadyStarted(orderHash);\n }\n\n // Update the order status as not valid and cancelled.\n orderStatus.isValidated = false;\n orderStatus.isCancelled = true;\n\n // Emit an event signifying that the order has been cancelled.\n emit OrderCancelled(orderHash, offerer);\n\n // Increment counter inside body of loop for gas efficiency.\n ++i;\n }\n }\n\n // Return a boolean indicating that orders were successfully cancelled.\n cancelled = true;\n }\n\n function _validate(Order[] calldata orders)\n internal\n returns (bool validated)\n {\n // Ensure that the reentrancy guard is not currently set.\n _assertNonReentrant();\n\n // Declare variables outside of the loop.\n OrderStatus storage orderStatus;\n bytes32 orderHash;\n address offerer;\n\n // Skip overflow check as for loop is indexed starting at zero.\n unchecked {\n // Read length of the orders array from memory and place on stack.\n uint256 totalOrders = orders.length;\n\n // Iterate over each order.\n for (uint256 i = 0; i < totalOrders; ) {\n // Retrieve the order.\n Order calldata order = orders[i];\n\n // Retrieve the order parameters.\n OrderParameters calldata orderParameters = order.parameters;\n\n // Move offerer from memory to the stack.\n offerer = orderParameters.offerer;\n\n // Get current counter & use it w/ params to derive order hash.\n orderHash = _deriveOrderHash(\n OrderParameters(\n offerer,\n orderParameters.token,\n orderParameters.identifier,\n orderParameters.currency,\n orderParameters.artist,\n orderParameters.platform,\n orderParameters.startTime,\n orderParameters.endTime,\n orderParameters.duration,\n orderParameters.periods,\n orderParameters.amount,\n orderParameters.ratio,\n orderParameters.royalty,\n orderParameters.fee,\n orderParameters.withdrawFee,\n orderParameters.salt,\n orderParameters.conduitKey\n ),\n _getCounter(orderParameters.offerer)\n );\n\n // Retrieve the order status using the derived order hash.\n orderStatus = _orderStatus[orderHash];\n\n // Ensure order is fillable and retrieve the filled amount.\n _verifyOrderStatus(\n orderHash,\n orderStatus,\n true, // Signifies that partially filled orders are valid.\n true // Signifies to revert if the order is invalid.\n );\n\n // If the order has not already been validated...\n if (!orderStatus.isValidated) {\n // Verify the supplied signature.\n _verifySignature(offerer, orderHash, order.signature);\n\n // Update order status to mark the order as valid.\n orderStatus.isValidated = true;\n\n // Emit an event signifying the order has been validated.\n emit OrderValidated(\n orderHash,\n offerer\n );\n }\n\n // Increment counter inside body of the loop for gas efficiency.\n ++i;\n }\n }\n\n // Return a boolean indicating that orders were successfully validated.\n validated = true;\n }\n\n function _getOrderStatus(bytes32 orderHash)\n internal\n view\n returns (\n bool isValidated,\n bool isCancelled,\n bool isFinalized,\n bool isBroken,\n address fulfiller,\n uint256 startedAt,\n uint256 shadowId,\n uint256 paidTimes\n )\n {\n OrderStatus storage orderStatus = _orderStatus[orderHash];\n return (\n orderStatus.isValidated,\n orderStatus.isCancelled,\n orderStatus.isFinalized,\n orderStatus.isBroken,\n orderStatus.fulfiller,\n orderStatus.startedAt,\n orderStatus.shadowId,\n orderStatus.paidTimes\n );\n }\n}\n" }, "contracts/lib/ConsiderationConstants.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\n/*\n * -------------------------- Disambiguation & Other Notes ---------------------\n * - The term \"head\" is used as it is in the documentation for ABI encoding,\n * but only in reference to dynamic types, i.e. it always refers to the\n * offset or pointer to the body of a dynamic type. In calldata, the head\n * is always an offset (relative to the parent object), while in memory,\n * the head is always the pointer to the body. More information found here:\n * https://docs.soliditylang.org/en/v0.8.14/abi-spec.html#argument-encoding\n * - Note that the length of an array is separate from and precedes the\n * head of the array.\n *\n * - The term \"body\" is used in place of the term \"head\" used in the ABI\n * documentation. It refers to the start of the data for a dynamic type,\n * e.g. the first word of a struct or the first word of the first element\n * in an array.\n *\n * - The term \"pointer\" is used to describe the absolute position of a value\n * and never an offset relative to another value.\n * - The suffix \"_ptr\" refers to a memory pointer.\n * - The suffix \"_cdPtr\" refers to a calldata pointer.\n *\n * - The term \"offset\" is used to describe the position of a value relative\n * to some parent value. For example, OrderParameters_conduit_offset is the\n * offset to the \"conduit\" value in the OrderParameters struct relative to\n * the start of the body.\n * - Note: Offsets are used to derive pointers.\n *\n * - Some structs have pointers defined for all of their fields in this file.\n * Lines which are commented out are fields that are not used in the\n * codebase but have been left in for readability.\n */\n\n// Declare constants for name, version, and reentrancy sentinel values.\n\n// Name is right padded, so it touches the length which is left padded. This\n// enables writing both values at once. Length goes at byte 95 in memory, and\n// name fills bytes 96-109, so both values can be written left-padded to 77.\nuint256 constant NameLengthPtr = 77;\nuint256 constant NameWithLength = 0x0d436F6E73696465726174696F6E;\n\nuint256 constant Version = 0x312e31;\nuint256 constant Version_length = 3;\nuint256 constant Version_shift = 0xe8;\n\nuint256 constant _NOT_ENTERED = 1;\nuint256 constant _ENTERED = 2;\n\n// Common Offsets\n// Offsets for identically positioned fields shared by:\n// OfferItem, ConsiderationItem, SpentItem, ReceivedItem\n\nuint256 constant Common_token_offset = 0x20;\nuint256 constant Common_identifier_offset = 0x40;\nuint256 constant Common_amount_offset = 0x60;\n\nuint256 constant ReceivedItem_size = 0xa0;\nuint256 constant ReceivedItem_amount_offset = 0x60;\nuint256 constant ReceivedItem_recipient_offset = 0x80;\n\nuint256 constant ReceivedItem_CommonParams_size = 0x60;\n\nuint256 constant ConsiderationItem_recipient_offset = 0xa0;\n// Store the same constant in an abbreviated format for a line length fix.\nuint256 constant ConsiderItem_recipient_offset = 0xa0;\n\nuint256 constant Execution_offerer_offset = 0x20;\nuint256 constant Execution_conduit_offset = 0x40;\n\nuint256 constant InvalidFulfillmentComponentData_error_signature = (\n 0x7fda727900000000000000000000000000000000000000000000000000000000\n);\nuint256 constant InvalidFulfillmentComponentData_error_len = 0x04;\n\nuint256 constant Panic_error_signature = (\n 0x4e487b7100000000000000000000000000000000000000000000000000000000\n);\nuint256 constant Panic_error_offset = 0x04;\nuint256 constant Panic_error_length = 0x24;\nuint256 constant Panic_arithmetic = 0x11;\n\nuint256 constant MissingItemAmount_error_signature = (\n 0x91b3e51400000000000000000000000000000000000000000000000000000000\n);\nuint256 constant MissingItemAmount_error_len = 0x04;\n\nuint256 constant OrderParameters_offer_head_offset = 0x20;\nuint256 constant OrderParameters_consideration_head_offset = 0x40;\nuint256 constant OrderParameters_conduit_offset = 0x200;\nuint256 constant OrderParameters_counter_offset = 0x220;\n\nuint256 constant Fulfillment_itemIndex_offset = 0x20;\n\nuint256 constant AdvancedOrder_numerator_offset = 0x20;\n\nuint256 constant AlmostOneWord = 0x1f;\nuint256 constant OneWord = 0x20;\nuint256 constant TwoWords = 0x40;\nuint256 constant ThreeWords = 0x60;\nuint256 constant FourWords = 0x80;\nuint256 constant FiveWords = 0xa0;\n\nuint256 constant FreeMemoryPointerSlot = 0x40;\nuint256 constant ZeroSlot = 0x60;\nuint256 constant DefaultFreeMemoryPointer = 0x80;\n\nuint256 constant Slot0x80 = 0x80;\nuint256 constant Slot0xA0 = 0xa0;\n\nuint256 constant BasicOrder_endAmount_cdPtr = 0x104;\nuint256 constant BasicOrder_common_params_size = 0xa0;\nuint256 constant BasicOrder_considerationHashesArray_ptr = 0x160;\n\nuint256 constant EIP712_Order_size = 0x260;\nuint256 constant AdditionalRecipients_size = 0x40;\n\nuint256 constant EIP712_DomainSeparator_offset = 0x02;\nuint256 constant EIP712_OrderHash_offset = 0x22;\nuint256 constant EIP712_DigestPayload_size = 0x42;\n\nuint256 constant receivedItemsHash_ptr = 0x60;\n\n/*\n * Memory layout in _prepareBasicFulfillmentFromCalldata of\n * data for OrderFulfilled\n *\n * event OrderFulfilled(\n * bytes32 orderHash,\n * address indexed offerer,\n * address indexed zone,\n * address fulfiller,\n * SpentItem[] offer,\n * > (itemType, token, id, amount)\n * ReceivedItem[] consideration\n * > (itemType, token, id, amount, recipient)\n * )\n *\n * - 0x00: orderHash\n * - 0x20: fulfiller\n * - 0x40: offer offset (0x80)\n * - 0x60: consideration offset (0x120)\n * - 0x80: offer.length (1)\n * - 0xa0: offerItemType\n * - 0xc0: offerToken\n * - 0xe0: offerIdentifier\n * - 0x100: offerAmount\n * - 0x120: consideration.length (1 + additionalRecipients.length)\n * - 0x140: considerationItemType\n * - 0x160: considerationToken\n * - 0x180: considerationIdentifier\n * - 0x1a0: considerationAmount\n * - 0x1c0: considerationRecipient\n * - ...\n */\n\n// Minimum length of the OrderFulfilled event data.\n// Must be added to the size of the ReceivedItem array for additionalRecipients\n// (0xa0 * additionalRecipients.length) to calculate full size of the buffer.\nuint256 constant OrderFulfilled_baseSize = 0x1e0;\nuint256 constant OrderFulfilled_selector = (\n 0x9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31\n);\n\n// Minimum offset in memory to OrderFulfilled event data.\n// Must be added to the size of the EIP712 hash array for additionalRecipients\n// (32 * additionalRecipients.length) to calculate the pointer to event data.\nuint256 constant OrderFulfilled_baseOffset = 0x180;\nuint256 constant OrderFulfilled_consideration_length_baseOffset = 0x2a0;\nuint256 constant OrderFulfilled_offer_length_baseOffset = 0x200;\n\n// uint256 constant OrderFulfilled_orderHash_offset = 0x00;\nuint256 constant OrderFulfilled_fulfiller_offset = 0x20;\nuint256 constant OrderFulfilled_offer_head_offset = 0x40;\nuint256 constant OrderFulfilled_offer_body_offset = 0x80;\nuint256 constant OrderFulfilled_consideration_head_offset = 0x60;\nuint256 constant OrderFulfilled_consideration_body_offset = 0x120;\n\n// BasicOrderParameters\nuint256 constant BasicOrder_parameters_cdPtr = 0x04;\nuint256 constant BasicOrder_considerationToken_cdPtr = 0x24;\n// uint256 constant BasicOrder_considerationIdentifier_cdPtr = 0x44;\nuint256 constant BasicOrder_considerationAmount_cdPtr = 0x64;\nuint256 constant BasicOrder_offerer_cdPtr = 0x84;\nuint256 constant BasicOrder_zone_cdPtr = 0xa4;\nuint256 constant BasicOrder_offerToken_cdPtr = 0xc4;\n// uint256 constant BasicOrder_offerIdentifier_cdPtr = 0xe4;\nuint256 constant BasicOrder_offerAmount_cdPtr = 0x104;\nuint256 constant BasicOrder_basicOrderType_cdPtr = 0x124;\nuint256 constant BasicOrder_startTime_cdPtr = 0x144;\n// uint256 constant BasicOrder_endTime_cdPtr = 0x164;\n// uint256 constant BasicOrder_zoneHash_cdPtr = 0x184;\n// uint256 constant BasicOrder_salt_cdPtr = 0x1a4;\nuint256 constant BasicOrder_offererConduit_cdPtr = 0x1c4;\nuint256 constant BasicOrder_fulfillerConduit_cdPtr = 0x1e4;\nuint256 constant BasicOrder_totalOriginalAdditionalRecipients_cdPtr = 0x204;\nuint256 constant BasicOrder_additionalRecipients_head_cdPtr = 0x224;\nuint256 constant BasicOrder_signature_cdPtr = 0x244;\nuint256 constant BasicOrder_additionalRecipients_length_cdPtr = 0x264;\nuint256 constant BasicOrder_additionalRecipients_data_cdPtr = 0x284;\n\nuint256 constant BasicOrder_parameters_ptr = 0x20;\n\nuint256 constant BasicOrder_basicOrderType_range = 0x18; // 24 values\n\n/*\n * Memory layout in _prepareBasicFulfillmentFromCalldata of\n * EIP712 data for ConsiderationItem\n * - 0x80: ConsiderationItem EIP-712 typehash (constant)\n * - 0xa0: itemType\n * - 0xc0: token\n * - 0xe0: identifier\n * - 0x100: startAmount\n * - 0x120: endAmount\n * - 0x140: recipient\n */\nuint256 constant BasicOrder_considerationItem_typeHash_ptr = 0x80; // memoryPtr\nuint256 constant BasicOrder_considerationItem_itemType_ptr = 0xa0;\nuint256 constant BasicOrder_considerationItem_token_ptr = 0xc0;\nuint256 constant BasicOrder_considerationItem_identifier_ptr = 0xe0;\nuint256 constant BasicOrder_considerationItem_startAmount_ptr = 0x100;\nuint256 constant BasicOrder_considerationItem_endAmount_ptr = 0x120;\n// uint256 constant BasicOrder_considerationItem_recipient_ptr = 0x140;\n\n/*\n * Memory layout in _prepareBasicFulfillmentFromCalldata of\n * EIP712 data for OfferItem\n * - 0x80: OfferItem EIP-712 typehash (constant)\n * - 0xa0: itemType\n * - 0xc0: token\n * - 0xe0: identifier (reused for offeredItemsHash)\n * - 0x100: startAmount\n * - 0x120: endAmount\n */\nuint256 constant BasicOrder_offerItem_typeHash_ptr = DefaultFreeMemoryPointer;\nuint256 constant BasicOrder_offerItem_itemType_ptr = 0xa0;\nuint256 constant BasicOrder_offerItem_token_ptr = 0xc0;\n// uint256 constant BasicOrder_offerItem_identifier_ptr = 0xe0;\n// uint256 constant BasicOrder_offerItem_startAmount_ptr = 0x100;\nuint256 constant BasicOrder_offerItem_endAmount_ptr = 0x120;\n\n/*\n * Memory layout in _prepareBasicFulfillmentFromCalldata of\n * EIP712 data for Order\n * - 0x80: Order EIP-712 typehash (constant)\n * - 0xa0: orderParameters.offerer\n * - 0xc0: orderParameters.zone\n * - 0xe0: keccak256(abi.encodePacked(offerHashes))\n * - 0x100: keccak256(abi.encodePacked(considerationHashes))\n * - 0x120: orderType\n * - 0x140: startTime\n * - 0x160: endTime\n * - 0x180: zoneHash\n * - 0x1a0: salt\n * - 0x1c0: conduit\n * - 0x1e0: _counters[orderParameters.offerer] (from storage)\n */\nuint256 constant BasicOrder_order_typeHash_ptr = 0x80;\nuint256 constant BasicOrder_order_offerer_ptr = 0xa0;\n// uint256 constant BasicOrder_order_zone_ptr = 0xc0;\nuint256 constant BasicOrder_order_offerHashes_ptr = 0xe0;\nuint256 constant BasicOrder_order_considerationHashes_ptr = 0x100;\nuint256 constant BasicOrder_order_orderType_ptr = 0x120;\nuint256 constant BasicOrder_order_startTime_ptr = 0x140;\n// uint256 constant BasicOrder_order_endTime_ptr = 0x160;\n// uint256 constant BasicOrder_order_zoneHash_ptr = 0x180;\n// uint256 constant BasicOrder_order_salt_ptr = 0x1a0;\n// uint256 constant BasicOrder_order_conduitKey_ptr = 0x1c0;\nuint256 constant BasicOrder_order_counter_ptr = 0x1e0;\nuint256 constant BasicOrder_additionalRecipients_head_ptr = 0x240;\nuint256 constant BasicOrder_signature_ptr = 0x260;\n\n// Signature-related\nbytes32 constant EIP2098_allButHighestBitMask = (\n 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n);\nbytes32 constant ECDSA_twentySeventhAndTwentyEighthBytesSet = (\n 0x0000000000000000000000000000000000000000000000000000000101000000\n);\nuint256 constant ECDSA_MaxLength = 65;\nuint256 constant ECDSA_signature_s_offset = 0x40;\nuint256 constant ECDSA_signature_v_offset = 0x60;\n\nbytes32 constant EIP1271_isValidSignature_selector = (\n 0x1626ba7e00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant EIP1271_isValidSignature_signatureHead_negativeOffset = 0x20;\nuint256 constant EIP1271_isValidSignature_digest_negativeOffset = 0x40;\nuint256 constant EIP1271_isValidSignature_selector_negativeOffset = 0x44;\nuint256 constant EIP1271_isValidSignature_calldata_baseLength = 0x64;\n\nuint256 constant EIP1271_isValidSignature_signature_head_offset = 0x40;\n\n// abi.encodeWithSignature(\"NoContract(address)\")\nuint256 constant NoContract_error_signature = (\n 0x5f15d67200000000000000000000000000000000000000000000000000000000\n);\nuint256 constant NoContract_error_sig_ptr = 0x0;\nuint256 constant NoContract_error_token_ptr = 0x4;\nuint256 constant NoContract_error_length = 0x24; // 4 + 32 == 36\n\nuint256 constant EIP_712_PREFIX = (\n 0x1901000000000000000000000000000000000000000000000000000000000000\n);\n\nuint256 constant ExtraGasBuffer = 0x20;\nuint256 constant CostPerWord = 3;\nuint256 constant MemoryExpansionCoefficient = 0x200; // 512\n\nuint256 constant Create2AddressDerivation_ptr = 0x0b;\nuint256 constant Create2AddressDerivation_length = 0x55;\n\nuint256 constant MaskOverByteTwelve = (\n 0x0000000000000000000000ff0000000000000000000000000000000000000000\n);\n\nuint256 constant MaskOverLastTwentyBytes = (\n 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff\n);\n\nuint256 constant MaskOverFirstFourBytes = (\n 0xffffffff00000000000000000000000000000000000000000000000000000000\n);\n\nuint256 constant Conduit_execute_signature = (\n 0x4ce34aa200000000000000000000000000000000000000000000000000000000\n);\n\nuint256 constant MaxUint8 = 0xff;\nuint256 constant MaxUint120 = 0xffffffffffffffffffffffffffffff;\n\nuint256 constant Conduit_execute_ConduitTransfer_ptr = 0x20;\nuint256 constant Conduit_execute_ConduitTransfer_length = 0x01;\n\nuint256 constant Conduit_execute_ConduitTransfer_offset_ptr = 0x04;\nuint256 constant Conduit_execute_ConduitTransfer_length_ptr = 0x24;\nuint256 constant Conduit_execute_transferItemType_ptr = 0x44;\nuint256 constant Conduit_execute_transferToken_ptr = 0x64;\nuint256 constant Conduit_execute_transferFrom_ptr = 0x84;\nuint256 constant Conduit_execute_transferTo_ptr = 0xa4;\nuint256 constant Conduit_execute_transferIdentifier_ptr = 0xc4;\nuint256 constant Conduit_execute_transferAmount_ptr = 0xe4;\n\nuint256 constant OneConduitExecute_size = 0x104;\n\n// Sentinel value to indicate that the conduit accumulator is not armed.\nuint256 constant AccumulatorDisarmed = 0x20;\nuint256 constant AccumulatorArmed = 0x40;\nuint256 constant Accumulator_conduitKey_ptr = 0x20;\nuint256 constant Accumulator_selector_ptr = 0x40;\nuint256 constant Accumulator_array_offset_ptr = 0x44;\nuint256 constant Accumulator_array_length_ptr = 0x64;\n\nuint256 constant Accumulator_itemSizeOffsetDifference = 0x3c;\n\nuint256 constant Accumulator_array_offset = 0x20;\nuint256 constant Conduit_transferItem_size = 0xc0;\nuint256 constant Conduit_transferItem_token_ptr = 0x20;\nuint256 constant Conduit_transferItem_from_ptr = 0x40;\nuint256 constant Conduit_transferItem_to_ptr = 0x60;\nuint256 constant Conduit_transferItem_identifier_ptr = 0x80;\nuint256 constant Conduit_transferItem_amount_ptr = 0xa0;\n\n// Declare constant for errors related to amount derivation.\n// error InexactFraction() @ AmountDerivationErrors.sol\nuint256 constant InexactFraction_error_signature = (\n 0xc63cf08900000000000000000000000000000000000000000000000000000000\n);\nuint256 constant InexactFraction_error_len = 0x04;\n\n// Declare constant for errors related to signature verification.\nuint256 constant Ecrecover_precompile = 1;\nuint256 constant Ecrecover_args_size = 0x80;\nuint256 constant Signature_lower_v = 27;\n\n// error BadSignatureV(uint8) @ SignatureVerificationErrors.sol\nuint256 constant BadSignatureV_error_signature = (\n 0x1f003d0a00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant BadSignatureV_error_offset = 0x04;\nuint256 constant BadSignatureV_error_length = 0x24;\n\n// error InvalidSigner() @ SignatureVerificationErrors.sol\nuint256 constant InvalidSigner_error_signature = (\n 0x815e1d6400000000000000000000000000000000000000000000000000000000\n);\nuint256 constant InvalidSigner_error_length = 0x04;\n\n// error InvalidSignature() @ SignatureVerificationErrors.sol\nuint256 constant InvalidSignature_error_signature = (\n 0x8baa579f00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant InvalidSignature_error_length = 0x04;\n\n// error BadContractSignature() @ SignatureVerificationErrors.sol\nuint256 constant BadContractSignature_error_signature = (\n 0x4f7fb80d00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant BadContractSignature_error_length = 0x04;\n\nuint256 constant NumBitsAfterSelector = 0xe0;\n\n// 69 is the lowest modulus for which the remainder\n// of every selector other than the two match functions\n// is greater than those of the match functions.\nuint256 constant NonMatchSelector_MagicModulus = 69;\n// Of the two match function selectors, the highest\n// remainder modulo 69 is 29.\nuint256 constant NonMatchSelector_MagicRemainder = 0x1d;\n" }, "contracts/conduit/lib/ConduitStructs.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nimport { ConduitItemType } from \"./ConduitEnums.sol\";\n\nstruct ConduitTransfer {\n ConduitItemType itemType;\n address token;\n address from;\n address to;\n uint256 identifier;\n uint256 amount;\n}\n\nstruct ConduitBatch1155Transfer {\n address token;\n address from;\n address to;\n uint256[] ids;