An intent-based application allows a user to express an intent and encodes it as an order for an underlying protocol. The order is signed by the user, and the signed order is submitted to a network of fillers. The fillers are then able to fill the order on chain, satisfying the user intent, and can claim a payment by providing the signed order and validation of the fill.
Each intent protocol defines its own type of orders with a specific set of parameters and with different requirements and implications for fillers. As a result, before a filler can participate in an intent protocol they have to build out the integration for that specific protocol. The goal of ERC-7683 is to provide a protocol-agnostic order type, and to reduce to a minimum the protocol-specific integration requirements for fillers.
An ERC-7683 order consists of a payload bytestring and the address of a resolver contract.
A resolver must implement the IOrderResolver interface.
An ERC-7683-compatible filler, upon receiving an order, may use the resolver to decode the payload by performing an eth_call to the resolve function.
// SPDX-License-Identifier: CC0
pragma solidity 0.8.30;
interface IOrderResolver {
function resolve(bytes calldata payload)
external view returns (ResolvedOrder memory);
}
struct ResolvedOrder {
bytes[] steps; // Step[] (Tagged Union Encoding)
bytes[] variables; // VariableRole[] (Tagged Union Encoding)
Assumption[] assumptions;
bytes[] payments;
}
interface Step {
function Call(
bytes memory target, // ERC-7930 Address
bytes4 selector,
bytes[] memory arguments, // Argument Encoding
bytes[] memory attributes, // Attribute[] (Tagged Union Encoding)
uint256[] memory dependencySteps, // Steps by index in resolved order
bytes[] memory payments // Payment[] (Tagged Union Encoding)
) external;
function FromResolver(
bytes memory target, // ERC-7930 Address
bytes4 selector,
bytes[] memory arguments, // Argument Encoding
uint256[] memory dependencies // Steps by index in resolved order
) external;
}
interface Attribute {
function SpendsERC20(
bytes memory token, // ERC-7930 Address
bytes memory amountFormula, // Formula (Tagged Union Encoding)
bytes memory spender // ERC-7930 Address
) external;
function OnlyBefore(uint256 deadline) external;
function OnlyFillerUntil(
address exclusiveFiller,
uint256 deadline
) external;
function OnlyWhenCallResult(
bytes memory target, // ERC-7930 Address
bytes4 selector,
bytes[] memory arguments, // Argument Encoding
bytes memory result,
uint256 maxGasCost
) external;
function UnlessRevert(bytes memory reason) external;
function WithTimestamp(uint256 timestampVarIdx) external;
function WithBlockNumber(uint256 blockNumberVarIdx) external;
function WithEffectiveGasPrice(uint256 gasPriceVarIdx) external;
function WithLog(byte1 mask, uint256[] topicVarIdxs, uint256 dataVarIdx) external;
}
interface Formula {
function Const(uint256 val) external;
function VarRef(uint256 varIdx) external;
}
interface Payment {
function ERC20(
bytes memory token, // ERC-7930 Address
bytes memory amountFormula, // Formula (Tagged Union Encoding)
uint256 recipientVarIdx,
uint256 estimatedDelaySeconds
) external;
}
interface VariableRole {
function PaymentRecipient(uint256 chainId) external;
function PaymentChain() external;
function Pricing() external;
function TxOutput() external;
function Witness(
string memory kind,
bytes memory data,
uint256[] memory variables
) external;
function Query(
bytes memory target, // ERC-7930 Address
bytes4 selector,
bytes[] memory arguments, // Argument Encoding
uint256 blockNumber
) external;
}
struct Assumption {
bytes memory trusted; // ERC-7930 Address
string memory kind;
}
Tagged unions are encoded as bytes by ABI encoding function calls from a given interface. The functions in the interface are the variants of the tagged union. The function selector is used as the tag.
interface E {
function A(uint256 x) external;
function B(string s) external;
}
bytes a = abi.encodeCall(E.A, (x));
bytes b = abi.encodeCall(E.B, (s));
enum E {
A(x: U256),
B(s: String),
}
let a = E::A(x);
let b = E::B(s);
An array bytes[] arguments encodes the arguments for a function call as follows:
arguments[i] has length 32, it must be ABI decoded as a uint256, and this integer k denotes that the ith argument takes the value of the kth variable.arguments[i] is the encoding of a constant value v given by the Solidity expression abi.encode("", v).See Aggregation for how to encode a function call given these arguments.
A resolved order returned by a trusted resolver is a promise that, given a set of choices for variables, if steps are executed within the constraints specified by attributes, any payments described within will be made, provided the trust assumptions hold.