-
Notifications
You must be signed in to change notification settings - Fork 16
Multichain Inputs #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
reednaa
wants to merge
32
commits into
main
Choose a base branch
from
compact-multichain-1
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
3bd2c48
Multichain escrowed inputs
reednaa 0d8fdbc
forge fmt
reednaa 77352ae
Compact multichain claim
reednaa a6afeae
Standardize both escrow and compact settler with a single order
reednaa 5b2f60e
Use chainId field to specify which chains an input belongs to
reednaa a5b6217
fix coverage
reednaa cc8cc22
Fix typos
reednaa ebc624a
Update escrow chain hash documentation
reednaa 07b01d8
Merge branch 'main' into compact-multichain-1
reednaa 3b6f051
Merge fixes
reednaa 059e7f4
fmt
reednaa dd6c392
Significantly optimise the order identifier computation for multichai…
reednaa 7c05be1
fmt
reednaa 34a9b7e
Merge branch 'main' into compact-multichain-1
reednaa d2766d5
Cleanup merge issued
reednaa e63427d
Fix stack too deep in test
reednaa 9d0738a
Test MultichainOrderComponentType
reednaa a524ee2
fmt
reednaa 67dc7e2
Multichain compact order identifier
reednaa c70ce36
Test for InputSettlerMultichainCompact
reednaa 201a0b1
Improve coverage by adding a signature finalise test to existing
reednaa 66bb0e0
Improve CI run time by decreasing runs
reednaa fbe0a34
Fix compile errors
reednaa ff40047
Initial draft for permit2 support for multichain escrow
reednaa efc8287
Add permit2 support to multichain escrow
reednaa b12f660
Update documentation
reednaa b91cc0f
Merge remote-tracking branch 'origin/main' into compact-multichain-1
reednaa 68cc406
Fix merge issues
reednaa 3d6783c
Merge branch 'main' of https://github.com/openintentsframework/OIF in…
reednaa 826521a
Merge branch 'main' of https://github.com/openintentsframework/OIF in…
reednaa d2e6096
fmt
reednaa d9d9768
Remote console log used for debugging
reednaa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,9 @@ | ||
| { | ||
| "outputSettlerCoinFill": "83343", | ||
| "outputSettlerCoinFillDutchAuction": "84573", | ||
| "outputSettlerCoinFillExclusive": "84739", | ||
| "outputSettlerCoinFillExclusiveDutchAuction": "85453", | ||
| "outputSettlerCoinFillNative": "89358", | ||
| "outputSettlerCoinFillOrderOutputsNative": "128860", | ||
| "outputSettlerCoinfillOrderOutputs": "119906" | ||
| "outputSettlerSimpleFill": "83343", | ||
| "outputSettlerSimpleFillDutchAuction": "84573", | ||
| "outputSettlerSimpleFillExclusive": "84739", | ||
| "outputSettlerSimpleFillExclusiveDutchAuction": "85453", | ||
| "outputSettlerSimpleFillNative": "89358", | ||
| "outputSettlerSimpleFillOrderOutputsNative": "128860", | ||
| "outputSettlerSimplefillOrderOutputs": "119906" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,226 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.26; | ||
|
|
||
| import { IERC20 } from "openzeppelin/token/ERC20/IERC20.sol"; | ||
| import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; | ||
| import { EIP712 } from "openzeppelin/utils/cryptography/EIP712.sol"; | ||
|
|
||
| import { TheCompact } from "the-compact/src/TheCompact.sol"; | ||
| import { EfficiencyLib } from "the-compact/src/lib/EfficiencyLib.sol"; | ||
| import { IdLib } from "the-compact/src/lib/IdLib.sol"; | ||
| import { BatchMultichainClaim, ExogenousBatchMultichainClaim } from "the-compact/src/types/BatchMultichainClaims.sol"; | ||
| import { BatchClaimComponent, Component } from "the-compact/src/types/Components.sol"; | ||
|
|
||
| import { IInputCallback } from "../../interfaces/IInputCallback.sol"; | ||
| import { IInputOracle } from "../../interfaces/IInputOracle.sol"; | ||
|
|
||
| import { BytesLib } from "../../libs/BytesLib.sol"; | ||
| import { LibAddress } from "../../libs/LibAddress.sol"; | ||
| import { MandateOutputEncodingLib } from "../../libs/MandateOutputEncodingLib.sol"; | ||
|
|
||
| import { InputSettlerBase } from "../InputSettlerBase.sol"; | ||
| import { MandateOutput } from "../types/MandateOutputType.sol"; | ||
|
|
||
| import { MultichainCompactOrderType, MultichainOrderComponent } from "../types/MultichainCompactOrderType.sol"; | ||
| import { OrderPurchase } from "../types/OrderPurchaseType.sol"; | ||
|
|
||
| /** | ||
| * @title Multichain Input Settler using `The Compact` as an escrow. | ||
| * @notice This Input Settler implementation uses The Compact as the deposit scheme. It is a Output first scheme that | ||
| * allows users with a deposit inside The Compact to execute transactions that will be paid **after** the outputs have | ||
| * been proven. This has the advantage that failed orders can be quickly retried. These orders are also entirely gasless | ||
| * since neither valid nor failed transactions does not require any transactions to redeem. | ||
| * | ||
| * Users are expected to have an existing deposit inside the Compact or purposefully deposit for the intent. Then either | ||
| * register or sign a supported claim with the intent outputs as the witness. | ||
| * | ||
| * A multichain intent is an intent that collects tokens on multiple chains in exchange for single set of outputs. Using | ||
| * TheCompact allows users to issue a multichain input intent using a single Multichain Compact signature. | ||
| * | ||
| * The contract is intended to be entirely ownerless, permissionlessly deployable, and unstoppable. | ||
| */ | ||
| contract InputSettlerMultichainCompact is InputSettlerBase { | ||
| using LibAddress for bytes32; | ||
| using LibAddress for uint256; | ||
| error UserCannotBeSettler(); | ||
|
|
||
| TheCompact public immutable COMPACT; | ||
|
|
||
| constructor( | ||
| address compact | ||
| ) EIP712("OIFMultichainEscrow", "1") { | ||
| COMPACT = TheCompact(compact); | ||
| } | ||
|
|
||
| // --- Generic order identifier --- // | ||
|
|
||
| function _orderIdentifier( | ||
| MultichainOrderComponent calldata order | ||
| ) internal view returns (bytes32) { | ||
| return MultichainCompactOrderType.orderIdentifier(order); | ||
| } | ||
|
|
||
| function orderIdentifier( | ||
| MultichainOrderComponent calldata order | ||
| ) external view returns (bytes32) { | ||
| return _orderIdentifier(order); | ||
| } | ||
|
|
||
| // --- Finalise Orders --- // | ||
|
|
||
| /** | ||
| * @notice Finalise an order, paying the inputs to the solver. | ||
| * @param order that has been filled. | ||
| * @param signatures For the signed intent. Is packed: abi.encode(sponsorSignature, allocatorData). | ||
| * @param solver Solver of the outputs. | ||
| * @param destination Destination of the inputs funds signed for by the user. | ||
| * @return orderId Returns a unique global order identifier. | ||
| */ | ||
| function _finalise( | ||
| MultichainOrderComponent calldata order, | ||
| bytes calldata signatures, | ||
| bytes32 solver, | ||
| bytes32 destination | ||
| ) internal virtual returns (bytes32 orderId) { | ||
| bytes calldata sponsorSignature = BytesLib.toBytes(signatures, 0x00); | ||
| bytes calldata allocatorData = BytesLib.toBytes(signatures, 0x20); | ||
| orderId = _resolveLock(order, sponsorSignature, allocatorData, destination); | ||
| emit Finalised(orderId, solver, destination); | ||
| } | ||
|
|
||
| /** | ||
| * @notice Finalises an order when called directly by the solver | ||
| * @dev The caller must be the address corresponding to the first solver in the solvers array. | ||
| * @param order MultichainOrderComponent signed in conjunction with a Compact to form an order | ||
| * @param signatures A signature for the sponsor and the allocator. abi.encode(bytes(sponsorSignature), | ||
| * bytes(allocatorData)) | ||
| * @param solveParams List of solve parameters for when the outputs were filled | ||
| * @param destination Where to send the inputs. If the solver wants to send the inputs to themselves, they should | ||
| * pass their address to this parameter. | ||
| * @param call Optional callback data. If non-empty, will call orderFinalised on the destination | ||
| */ | ||
| function finalise( | ||
| MultichainOrderComponent calldata order, | ||
| bytes calldata signatures, | ||
| SolveParams[] calldata solveParams, | ||
| bytes32 destination, | ||
| bytes calldata call | ||
| ) external virtual { | ||
| _validateDestination(destination); | ||
|
|
||
| _validateIsCaller(solveParams[0].solver); | ||
|
|
||
| bytes32 orderId = _finalise(order, signatures, solveParams[0].solver, destination); | ||
|
|
||
| _validateFills(order.fillDeadline, order.inputOracle, order.outputs, orderId, solveParams); | ||
|
|
||
| if (call.length > 0) { | ||
| IInputCallback(EfficiencyLib.asSanitizedAddress(uint256(destination))).orderFinalised(order.inputs, call); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @notice Finalises a cross-chain order on behalf of someone else using their signature | ||
| * @dev This function serves to finalise intents on the origin chain with proper authorization from the order owner. | ||
| * @param order MultichainOrderComponent signed in conjunction with a Compact to form an order | ||
| * @param signatures A signature for the sponsor and the allocator. abi.encode(bytes(sponsorSignature), | ||
| * bytes(allocatorData)) | ||
| * @param solveParams List of solve parameters for when the outputs were filled | ||
| * @param destination Where to send the inputs | ||
| * @param call Optional callback data. If non-empty, will call orderFinalised on the destination | ||
| * @param orderOwnerSignature Signature from the order owner authorizing this external call | ||
| */ | ||
| function finaliseWithSignature( | ||
| MultichainOrderComponent calldata order, | ||
| bytes calldata signatures, | ||
| SolveParams[] calldata solveParams, | ||
| bytes32 destination, | ||
| bytes calldata call, | ||
| bytes calldata orderOwnerSignature | ||
| ) external virtual { | ||
| if (destination == bytes32(0)) revert NoDestination(); | ||
|
|
||
| bytes32 orderId = _finalise(order, signatures, solveParams[0].solver, destination); | ||
|
|
||
| // Validate the external claimant with signature | ||
| _allowExternalClaimant(orderId, solveParams[0].solver.fromIdentifier(), destination, call, orderOwnerSignature); | ||
|
|
||
| _validateFills(order.fillDeadline, order.inputOracle, order.outputs, orderId, solveParams); | ||
|
|
||
| if (call.length > 0) IInputCallback(destination.fromIdentifier()).orderFinalised(order.inputs, call); | ||
| } | ||
|
|
||
| //--- The Compact & Resource Locks ---// | ||
|
|
||
| /** | ||
| * @notice Resolves a Compact Claim for a Standard Order. | ||
| * @param order that should be converted into a Compact Claim. | ||
| * @param sponsorSignature The user's signature for the Compact Claim. | ||
| * @param allocatorData The allocator's signature for the Compact Claim. | ||
| * @param claimant Destination of the inputs funds signed for by the user. | ||
| * @return claimHash The compact claimhash is used as the order identifier, as it is identical for a specific order | ||
| * cross-chain. | ||
| */ | ||
| function _resolveLock( | ||
| MultichainOrderComponent calldata order, | ||
| bytes calldata sponsorSignature, | ||
| bytes calldata allocatorData, | ||
| bytes32 claimant | ||
| ) internal virtual returns (bytes32 claimHash) { | ||
| BatchClaimComponent[] memory batchClaimComponents; | ||
| { | ||
| uint256 numInputs = order.inputs.length; | ||
| batchClaimComponents = new BatchClaimComponent[](numInputs); | ||
| uint256[2][] calldata maxInputs = order.inputs; | ||
| for (uint256 i; i < numInputs; ++i) { | ||
| uint256[2] calldata input = maxInputs[i]; | ||
| uint256 tokenId = input[0]; | ||
| uint256 allocatedAmount = input[1]; | ||
|
|
||
| Component[] memory components = new Component[](1); | ||
| components[0] = Component({ claimant: uint256(claimant), amount: allocatedAmount }); | ||
| batchClaimComponents[i] = BatchClaimComponent({ | ||
| id: tokenId, // The token ID of the ERC6909 token to allocate. | ||
| allocatedAmount: allocatedAmount, // The original allocated amount of ERC6909 tokens. | ||
| portions: components | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| address user = order.user; | ||
| // The Compact skips signature checks for msg.sender. Ensure no accidental intents are issued. | ||
| if (user == address(this)) revert UserCannotBeSettler(); | ||
| if (order.chainIdField == block.chainid) { | ||
| claimHash = COMPACT.batchMultichainClaim( | ||
| BatchMultichainClaim({ | ||
| allocatorData: allocatorData, | ||
| sponsorSignature: sponsorSignature, | ||
| sponsor: user, | ||
| nonce: order.nonce, | ||
| expires: order.expires, | ||
| witness: MultichainCompactOrderType.witnessHash(order), | ||
| witnessTypestring: string(MultichainCompactOrderType.BATCH_COMPACT_SUB_TYPES), | ||
| claims: batchClaimComponents, | ||
| additionalChains: order.additionalChains | ||
| }) | ||
| ); | ||
| } else { | ||
| claimHash = COMPACT.exogenousBatchClaim( | ||
| ExogenousBatchMultichainClaim({ | ||
| allocatorData: allocatorData, | ||
| sponsorSignature: sponsorSignature, | ||
| sponsor: user, | ||
| nonce: order.nonce, | ||
| expires: order.expires, | ||
| witness: MultichainCompactOrderType.witnessHash(order), | ||
| witnessTypestring: string(MultichainCompactOrderType.BATCH_COMPACT_SUB_TYPES), | ||
| claims: batchClaimComponents, | ||
| additionalChains: order.additionalChains, | ||
| chainIndex: order.chainIndex - 1, // We use chainIndex as the offset to elements array where compact | ||
| // uses it as offset to the notarized. | ||
| notarizedChainId: order.chainIdField | ||
| }) | ||
| ); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard
chainIndex - 1to avoid underflow on exogenous chains.In the exogenous path we do
chainIndex: order.chainIndex - 1. If a component for a non-origin chain is positioned at index0in the global elements ordering (totally valid for two components ordered[remote, origin]), this subtraction underflows and hard reverts, making those orders impossible to finalise. Please requireorder.chainIndex > 0(and revert with a clear error) before subtracting, or otherwise adjust the logic so we never subtract blindly.🤖 Prompt for AI Agents