Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/evm/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ AXIA=0x3F4C47E37A94caeE31d0B585f54F3fFA1f2294C9
SOLVER=0xE0D76433Edd9f5df370561bd0AF231E72c83Cd3a
VALIDATOR=0xc76B16fA2Fa75D93e08099DC16413D9a083404A1

SETTLER_PROXY=

ETHERSCAN_KEY=
DEPLOYER_PRIVATE_KEY=
142 changes: 91 additions & 51 deletions packages/evm/contracts/Intents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,19 @@
pragma solidity ^0.8.20;

/**
* @dev Enum representing the type of intent operation.
* - Swap: Swap tokens between chains or tokens.
* @dev Enum representing the operation type.
* - Swap: Swap tokens in the same chain.
* - Transfer: Transfer tokens to one or more recipients.
* - Call: Execute arbitrary contract calls.
* - CrossChainSwap: Swap tokens between chains.
* - DynamicCall: Execute arbitrary dynamic contract calls.
*/
enum OpType {
Swap,
Transfer,
Call
}

/**
* @dev Execution structure.
* @param intent Intent to be fulfilled.
* @param proposal Proposal to be executed.
* @param signature Proposal signature.
*/
struct Execution {
Intent intent;
Proposal proposal;
bytes signature;
Call,
CrossChainSwap,
DynamicCall
}

/**
Expand All @@ -35,31 +27,41 @@ struct Validation {
}

/**
* @dev General intent structure used to abstract over different intent types.
* @param op The type of operation this intent represents.
* @param user The originator of the intent.
* @dev General intent structure with different operations.
* @param feePayer The payer of the intent.
* @param settler The address responsible for executing the intent on-chain.
* @param nonce A unique value used to prevent replay attacks and distinguish intents.
* @param deadline The timestamp by which the intent must be executed.
* @param data ABI-encoded data representing a specific intent type (e.g. SwapIntent, TransferIntent, CallIntent).
* @param maxFees List of max fees the user is willing to pay for the intent.
* @param events List of custom intent events to be emitted.
* @param configSig The signature of the configuration that this intent belongs to
* @param maxFees List of max fees the feePayer is willing to pay for the intent.
* @param triggerSig The signature of the trigger that this intent belongs to
* @param minValidations The minimum number of validator approvals required for this intent to be considered valid.
* @param validations The list validator signatures attesting to this intent.
* @param operations List of operations of the intent.
*/
struct Intent {
uint8 op;
address user;
address feePayer;
address settler;
bytes32 nonce;
uint256 deadline;
bytes data;
MaxFee[] maxFees;
IntentEvent[] events;
bytes configSig;
bytes triggerSig;
uint256 minValidations;
bytes[] validations;
Operation[] operations;
}

/**
* @dev Operation structure used to abstract over different operation types.
* @param opType The type of operation this operation represents.
* @param user The user of the operation.
* @param data ABI-encoded data representing a specific operation type (e.g. SwapOperation, TransferOperation, CallOperation).
* @param events List of custom operation events to be emitted.
*/
struct Operation {
uint8 opType;
address user;
bytes data;
OperationEvent[] events;
}

/**
Expand All @@ -73,23 +75,23 @@ struct MaxFee {
}

/**
* @dev Intent event representation.
* @dev Operation event representation.
* @param topic Event topic to be emitted.
* @param data Event data to be emitted.
*/
struct IntentEvent {
struct OperationEvent {
bytes32 topic;
bytes data;
}

/**
* @dev Represents a swap intent between two chains.
* @dev Represents a swap operation between two chains.
* @param sourceChain Chain ID where tokens will be sent from.
* @param destinationChain Chain ID where tokens will be received.
* @param tokensIn List of input tokens and amounts to swap.
* @param tokensOut List of expected output tokens, minimum amounts, and recipients.
*/
struct SwapIntent {
struct SwapOperation {
uint256 sourceChain;
uint256 destinationChain;
TokenIn[] tokensIn;
Expand Down Expand Up @@ -119,11 +121,11 @@ struct TokenOut {
}

/**
* @dev Represents a transfer intent containing multiple token transfers.
* @dev Represents a transfer operation containing multiple token transfers.
* @param chainId Chain ID where the transfers should be executed.
* @param transfers List of token transfers to be performed.
*/
struct TransferIntent {
struct TransferOperation {
uint256 chainId;
TransferData[] transfers;
}
Expand All @@ -141,11 +143,11 @@ struct TransferData {
}

/**
* @dev Represents a generic call intent consisting of one or more contract calls.
* @dev Represents a generic call operation consisting of one or more contract calls.
* @param chainId Chain ID where the calls should be executed.
* @param calls List of low-level contract calls to be executed.
*/
struct CallIntent {
struct CallOperation {
uint256 chainId;
CallData[] calls;
}
Expand All @@ -162,21 +164,31 @@ struct CallData {
uint256 value;
}

/**
* @dev Represents a generic dynamic call operation consisting of one or more dynamic contract calls.
* @param chainId Chain ID where the calls should be executed.
* @param calls List of ABI-encoded low-level dynamic contract calls to be executed.
*/
struct DynamicCallOperation {
uint256 chainId;
bytes[] calls;
}

/**
* @dev Generic proposal structure representing a solver’s response to an intent.
* @param deadline Timestamp until when the proposal is valid.
* @param data ABI-encoded proposal-specific data (e.g. SwapProposal).
* @param datas List of ABI-encoded proposal-specific data (e.g. SwapProposal).
* @param fees List of fee amounts the solver requires for execution.
*/
struct Proposal {
uint256 deadline;
bytes data;
bytes[] datas;
uint256[] fees;
}

/**
* @dev Swap proposal representation for a swap intent.
* @param executor Address of the executor contract that should be called during intent execution.
* @dev Swap proposal representation for a swap operation.
* @param executor Address of the executor contract that should be called during operation execution.
* @param data Arbitrary data used to call the executor contract.
* @param amountsOut List of amounts of tokens out proposed by the solver.
*/
Expand All @@ -189,33 +201,34 @@ struct SwapProposal {
library IntentsHelpers {
bytes32 internal constant INTENT_TYPE_HASH =
keccak256(
'Intent(uint8 op,address user,address settler,bytes32 nonce,uint256 deadline,bytes data,MaxFee[] maxFees,IntentEvent[] events,bytes configSig,uint256 minValidations)IntentEvent(bytes32 topic,bytes data)MaxFee(address token,uint256 amount)'
'Intent(address feePayer,address settler,bytes32 nonce,uint256 deadline,MaxFee[] maxFees,bytes triggerSig,uint256 minValidations,Operation[] operations)MaxFee(address token,uint256 amount)Operation(uint8 opType,address user,bytes data,OperationEvent[] events)OperationEvent(bytes32 topic,bytes data)'
);

bytes32 internal constant PROPOSAL_TYPE_HASH =
keccak256('Proposal(bytes32 intent,address solver,uint256 deadline,bytes data,uint256[] fees)');
keccak256('Proposal(bytes32 intent,address solver,uint256 deadline,bytes[] datas,uint256[] fees)');

bytes32 internal constant VALIDATION_TYPE_HASH = keccak256('Validation(bytes32 intent)');

bytes32 internal constant MAX_FEE_TYPE_HASH = keccak256('MaxFee(address token,uint256 amount)');

bytes32 internal constant INTENT_EVENT_TYPE_HASH = keccak256('IntentEvent(bytes32 topic,bytes data)');
bytes32 internal constant OPERATION_TYPE_HASH =
keccak256('Operation(uint8 opType,address user,bytes data,OperationEvent[] events)');

bytes32 internal constant OPERATION_EVENT_TYPE_HASH = keccak256('OperationEvent(bytes32 topic,bytes data)');

function hash(Intent memory intent) internal pure returns (bytes32) {
return
keccak256(
abi.encode(
INTENT_TYPE_HASH,
intent.op,
intent.user,
intent.feePayer,
intent.settler,
intent.nonce,
intent.deadline,
keccak256(intent.data),
hash(intent.maxFees),
hash(intent.events),
intent.configSig,
intent.minValidations
intent.triggerSig,
intent.minValidations,
hash(intent.operations)
)
);
}
Expand All @@ -228,7 +241,7 @@ library IntentsHelpers {
hash(intent),
solver,
proposal.deadline,
keccak256(proposal.data),
hash(proposal.datas),
hash(proposal.fees)
)
);
Expand All @@ -242,10 +255,29 @@ library IntentsHelpers {
return keccak256(abi.encodePacked(hashes));
}

function hash(IntentEvent[] memory events) internal pure returns (bytes32) {
function hash(Operation[] memory operations) internal pure returns (bytes32) {
bytes32[] memory hashes = new bytes32[](operations.length);
for (uint256 i = 0; i < operations.length; i++) hashes[i] = hash(operations[i]);
return keccak256(abi.encodePacked(hashes));
}

function hash(Operation memory operation) internal pure returns (bytes32) {
return
keccak256(
abi.encode(
OPERATION_TYPE_HASH,
operation.opType,
operation.user,
keccak256(operation.data),
hash(operation.events)
)
);
}

function hash(OperationEvent[] memory events) internal pure returns (bytes32) {
bytes32[] memory hashes = new bytes32[](events.length);
for (uint256 i = 0; i < events.length; i++) {
hashes[i] = keccak256(abi.encode(INTENT_EVENT_TYPE_HASH, events[i].topic, keccak256(events[i].data)));
hashes[i] = keccak256(abi.encode(OPERATION_EVENT_TYPE_HASH, events[i].topic, keccak256(events[i].data)));
}
return keccak256(abi.encodePacked(hashes));
}
Expand All @@ -254,6 +286,14 @@ library IntentsHelpers {
return keccak256(abi.encodePacked(fees));
}

function hash(bytes[] memory datas) internal pure returns (bytes32) {
bytes32[] memory hashes = new bytes32[](datas.length);
for (uint256 i = 0; i < datas.length; i++) {
hashes[i] = keccak256(datas[i]);
}
return keccak256(abi.encodePacked(hashes));
}

function hash(Validation memory validation) internal pure returns (bytes32) {
return keccak256(abi.encode(VALIDATION_TYPE_HASH, validation.intent));
}
Expand Down
Loading
Loading