Skip to content

Commit 36ca293

Browse files
howydevactions-user
authored andcommitted
feat: remove intent struct (#365)
* feat: simplify multichain nonce design * chore: readd merkle verification prefix * chore: undo blank line addns * chore: lint * . * ~50 failing tests down to 5 * down to 1 failing test * fixed failing test * chore: remove console logs and bench * . * Update test/Base.t.sol * Update src/Orchestrator.sol * Update test/utils/mocks/MockPayerWithSignatureOptimized.sol * chore: final cleanup, rebench * Update src/Orchestrator.sol * chore: bump contract versions due to bytecode changes - Contracts updated: IthacaAccount,Orchestrator,SimpleFunder,Simulator * chore: cleanup * rebase * fix --------- Co-authored-by: GitHub Action <[email protected]>
1 parent 5fcda11 commit 36ca293

34 files changed

+921
-659
lines changed

src/Escrow.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,9 @@ contract Escrow is IEscrow {
235235
statuses[escrowId] = EscrowStatus.FINALIZED;
236236

237237
// Check with the settler if the message has been sent from the correct sender and chainId.
238-
bool isSettled = ISettler(_escrow.settler)
239-
.read(_escrow.settlementId, _escrow.sender, _escrow.senderChainId);
238+
bool isSettled = ISettler(_escrow.settler).read(
239+
_escrow.settlementId, _escrow.sender, _escrow.senderChainId
240+
);
240241

241242
if (!isSettled) {
242243
revert SettlementInvalid();

src/GuardedExecutor.sol

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,9 @@ abstract contract GuardedExecutor is ERC7821 {
384384
if (_isSelfExecute(target, fnSel)) revert CannotSelfExecute();
385385

386386
// Impose a max capacity of 2048 for set enumeration, which should be more than enough.
387-
_getGuardedExecutorKeyStorage(keyHash).canExecute
388-
.update(_packCanExecute(target, fnSel), can, 2048);
387+
_getGuardedExecutorKeyStorage(keyHash).canExecute.update(
388+
_packCanExecute(target, fnSel), can, 2048
389+
);
389390
emit CanExecuteSet(keyHash, target, fnSel, can);
390391
}
391392

@@ -408,7 +409,7 @@ abstract contract GuardedExecutor is ERC7821 {
408409
// check it in `canExecute` before any custom call checker.
409410

410411
EnumerableMapLib.AddressToAddressMap storage checkers =
411-
_getGuardedExecutorKeyStorage(keyHash).callCheckers;
412+
_getGuardedExecutorKeyStorage(keyHash).callCheckers;
412413

413414
// Impose a max capacity of 2048 for map enumeration, which should be more than enough.
414415
checkers.update(target, checker, checker != address(0), 2048);
@@ -517,7 +518,12 @@ abstract contract GuardedExecutor is ERC7821 {
517518
/// @dev Returns an array of packed (`target`, `fnSel`) that `keyHash` is authorized to execute on.
518519
/// - `target` is in the upper 20 bytes.
519520
/// - `fnSel` is in the lower 4 bytes.
520-
function canExecutePackedInfos(bytes32 keyHash) public view virtual returns (bytes32[] memory) {
521+
function canExecutePackedInfos(bytes32 keyHash)
522+
public
523+
view
524+
virtual
525+
returns (bytes32[] memory)
526+
{
521527
return _getGuardedExecutorKeyStorage(keyHash).canExecute.values();
522528
}
523529

@@ -561,7 +567,7 @@ abstract contract GuardedExecutor is ERC7821 {
561567
returns (CallCheckerInfo[] memory results)
562568
{
563569
EnumerableMapLib.AddressToAddressMap storage checkers =
564-
_getGuardedExecutorKeyStorage(keyHash).callCheckers;
570+
_getGuardedExecutorKeyStorage(keyHash).callCheckers;
565571
results = new CallCheckerInfo[](checkers.length());
566572
for (uint256 i; i < results.length; ++i) {
567573
(results[i].target, results[i].checker) = checkers.at(i);

src/IthacaAccount.sol

Lines changed: 26 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,8 @@ contract IthacaAccount is IIthacaAccount, EIP712, GuardedExecutor {
274274

275275
(bool isValid, bytes32 keyHash) = unwrapAndValidateSignature(digest, signature);
276276
if (LibBit.and(keyHash != 0, isValid)) {
277-
isValid = _isSuperAdmin(keyHash)
278-
|| _getKeyExtraStorage(keyHash).checkers.contains(msg.sender);
277+
isValid =
278+
_isSuperAdmin(keyHash) || _getKeyExtraStorage(keyHash).checkers.contains(msg.sender);
279279
}
280280
// `bytes4(keccak256("isValidSignature(bytes32,bytes)")) = 0x1626ba7e`.
281281
// We use `0xffffffff` for invalid, in convention with the reference implementation.
@@ -399,7 +399,12 @@ contract IthacaAccount is IIthacaAccount, EIP712, GuardedExecutor {
399399
}
400400

401401
/// @dev Returns arrays of all (non-expired) authorized keys and their hashes.
402-
function getKeys() public view virtual returns (Key[] memory keys, bytes32[] memory keyHashes) {
402+
function getKeys()
403+
public
404+
view
405+
virtual
406+
returns (Key[] memory keys, bytes32[] memory keyHashes)
407+
{
403408
uint256 totalCount = keyCount();
404409

405410
keys = new Key[](totalCount);
@@ -573,8 +578,9 @@ contract IthacaAccount is IIthacaAccount, EIP712, GuardedExecutor {
573578
// `keccak256(abi.encode(key.keyType, keccak256(key.publicKey)))`.
574579
keyHash = hash(key);
575580
AccountStorage storage $ = _getAccountStorage();
576-
$.keyStorage[keyHash]
577-
.set(abi.encodePacked(key.publicKey, key.expiry, key.keyType, key.isSuperAdmin));
581+
$.keyStorage[keyHash].set(
582+
abi.encodePacked(key.publicKey, key.expiry, key.keyType, key.isSuperAdmin)
583+
);
578584
$.keyHashes.add(keyHash);
579585
}
580586

@@ -603,41 +609,28 @@ contract IthacaAccount is IIthacaAccount, EIP712, GuardedExecutor {
603609
uint256 paymentAmount,
604610
bytes32 keyHash,
605611
bytes32 intentDigest,
606-
bytes calldata encodedIntent
612+
address eoa,
613+
address payer,
614+
address paymentToken,
615+
address paymentRecipient,
616+
bytes calldata paymentSignature
607617
) public virtual {
608-
Intent calldata intent;
609-
// Equivalent Solidity Code: (In the assembly intent is stored in calldata, instead of memory)
610-
// Intent memory intent = abi.decode(encodedIntent, (Intent));
611-
// Gas Savings:
612-
// ~2.5-3k gas for general cases, by avoiding duplicated bounds checks, and avoiding writing the intent to memory.
613-
// Extracts the Intent from the calldata bytes, with minimal checks.
614-
// NOTE: Only use this implementation if you are sure that the encodedIntent is coming from a trusted source.
615-
// We can avoid standard bound checks here, because the Orchestrator already does these checks when it interacts with ALL the fields in the intent using solidity.
616-
assembly ("memory-safe") {
617-
let t := calldataload(encodedIntent.offset)
618-
intent := add(t, encodedIntent.offset)
619-
// Bounds check. We don't need to explicitly check the fields here.
620-
// In the self call functions, we will use regular Solidity to access the
621-
// dynamic fields like `signature`, which generate the implicit bounds checks.
622-
if or(shr(64, t), lt(encodedIntent.length, 0x20)) { revert(0x00, 0x00) }
623-
}
624-
625-
if (!LibBit.and(
626-
msg.sender == ORCHESTRATOR,
627-
LibBit.or(intent.eoa == address(this), intent.payer == address(this))
628-
)) {
618+
if (
619+
!LibBit.and(
620+
msg.sender == ORCHESTRATOR, LibBit.or(eoa == address(this), payer == address(this))
621+
)
622+
) {
629623
revert Unauthorized();
630624
}
631625

632626
// If this account is the paymaster, validate the paymaster signature.
633-
if (intent.payer == address(this)) {
627+
if (payer == address(this)) {
634628
if (_getAccountStorage().paymasterNonces[intentDigest]) {
635629
revert PaymasterNonceError();
636630
}
637631
_getAccountStorage().paymasterNonces[intentDigest] = true;
638632

639-
(bool isValid, bytes32 k) =
640-
unwrapAndValidateSignature(intentDigest, intent.paymentSignature);
633+
(bool isValid, bytes32 k) = unwrapAndValidateSignature(intentDigest, paymentSignature);
641634

642635
// Set the target key hash to the payer's.
643636
keyHash = k;
@@ -654,13 +647,13 @@ contract IthacaAccount is IIthacaAccount, EIP712, GuardedExecutor {
654647
}
655648
}
656649

657-
TokenTransferLib.safeTransfer(intent.paymentToken, intent.paymentRecipient, paymentAmount);
650+
TokenTransferLib.safeTransfer(paymentToken, paymentRecipient, paymentAmount);
651+
658652
// Increase spend.
659653
if (!(keyHash == bytes32(0) || _isSuperAdmin(keyHash))) {
660654
SpendStorage storage spends = _getGuardedExecutorKeyStorage(keyHash).spends;
661-
_incrementSpent(spends.spends[intent.paymentToken], intent.paymentToken, paymentAmount);
655+
_incrementSpent(spends.spends[paymentToken], paymentToken, paymentAmount);
662656
}
663-
664657
// Done to avoid compiler warnings.
665658
intentDigest = intentDigest;
666659
}

src/LayerZeroSettler.sol

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,13 @@ contract LayerZeroSettler is OApp, ISettler, EIP712 {
102102
}
103103
}
104104

105-
function _getPeerOrRevert(uint32 /* _eid */) internal view virtual override returns (bytes32) {
105+
function _getPeerOrRevert(uint32 /* _eid */ )
106+
internal
107+
view
108+
virtual
109+
override
110+
returns (bytes32)
111+
{
106112
// The peer address for all chains is automatically set to `address(this)`
107113
return bytes32(uint256(uint160(address(this))));
108114
}
@@ -133,10 +139,7 @@ contract LayerZeroSettler is OApp, ISettler, EIP712 {
133139
bytes calldata _payload,
134140
address, /*_executor*/
135141
bytes calldata /*_extraData*/
136-
)
137-
internal
138-
override
139-
{
142+
) internal override {
140143
// Decode the settlement data
141144
(bytes32 settlementId, address sender, uint256 senderChainId) =
142145
abi.decode(_payload, (bytes32, address, uint256));

0 commit comments

Comments
 (0)