Skip to content

Conversation

@nkrishang
Copy link
Contributor

No description provided.

assembly {
// Use a Yul function to enable use of the `leave` keyword
// to stop searching once the appropriate type hash is found.
function lookupTypeHash(treeHeight) -> typeHash {

Check warning

Code scanning / Slither

Write after write

AccountSeaportBulkSigSupport._lookupBulkOrderTypehash.asm_0.lookupTypeHash().typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash (contracts/extension/SeaportOrderParser.sol#359) is written in both typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash = ternary(treeHeight__lookupBulkOrderTypehash_asm_0_lookupTypeHash == 9,BulkOrder_Typehash_Height_Nine,BulkOrder_Typehash_Height_Ten) (contracts/extension/SeaportOrderParser.sol#407-408) typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash = ternary(treeHeight__lookupBulkOrderTypehash_asm_0_lookupTypeHash == 11,BulkOrder_Typehash_Height_Eleven,BulkOrder_Typehash_Height_Twelve) (contracts/extension/SeaportOrderParser.sol#415-416)
assembly {
// Use a Yul function to enable use of the `leave` keyword
// to stop searching once the appropriate type hash is found.
function lookupTypeHash(treeHeight) -> typeHash {

Check warning

Code scanning / Slither

Write after write

AccountSeaportBulkSigSupport._lookupBulkOrderTypehash.asm_0.lookupTypeHash().typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash (contracts/extension/SeaportOrderParser.sol#359) is written in both typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash = ternary(treeHeight__lookupBulkOrderTypehash_asm_0_lookupTypeHash == 17,BulkOrder_Typehash_Height_Seventeen,BulkOrder_Typehash_Height_Eighteen) (contracts/extension/SeaportOrderParser.sol#446-449) typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash = ternary(treeHeight__lookupBulkOrderTypehash_asm_0_lookupTypeHash == 19,BulkOrder_Typehash_Height_Nineteen,BulkOrder_Typehash_Height_Twenty) (contracts/extension/SeaportOrderParser.sol#456-457)
assembly {
// Use a Yul function to enable use of the `leave` keyword
// to stop searching once the appropriate type hash is found.
function lookupTypeHash(treeHeight) -> typeHash {

Check warning

Code scanning / Slither

Write after write

AccountSeaportBulkSigSupport._lookupBulkOrderTypehash.asm_0.lookupTypeHash().typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash (contracts/extension/SeaportOrderParser.sol#359) is written in both typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash = ternary(treeHeight__lookupBulkOrderTypehash_asm_0_lookupTypeHash == 1,BulkOrder_Typehash_Height_One,BulkOrder_Typehash_Height_Two) (contracts/extension/SeaportOrderParser.sol#367-368) typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash = ternary(treeHeight__lookupBulkOrderTypehash_asm_0_lookupTypeHash == 3,BulkOrder_Typehash_Height_Three,BulkOrder_Typehash_Height_Four) (contracts/extension/SeaportOrderParser.sol#375-376)
assembly {
// Use a Yul function to enable use of the `leave` keyword
// to stop searching once the appropriate type hash is found.
function lookupTypeHash(treeHeight) -> typeHash {

Check warning

Code scanning / Slither

Write after write

AccountSeaportBulkSigSupport._lookupBulkOrderTypehash.asm_0.lookupTypeHash().typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash (contracts/extension/SeaportOrderParser.sol#359) is written in both typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash = ternary(treeHeight__lookupBulkOrderTypehash_asm_0_lookupTypeHash == 13,BulkOrder_Typehash_Height_Thirteen,BulkOrder_Typehash_Height_Fourteen) (contracts/extension/SeaportOrderParser.sol#425-428) typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash = ternary(treeHeight__lookupBulkOrderTypehash_asm_0_lookupTypeHash == 15,BulkOrder_Typehash_Height_Fifteen,BulkOrder_Typehash_Height_Sixteen) (contracts/extension/SeaportOrderParser.sol#434-435)
assembly {
// Use a Yul function to enable use of the `leave` keyword
// to stop searching once the appropriate type hash is found.
function lookupTypeHash(treeHeight) -> typeHash {

Check warning

Code scanning / Slither

Write after write

AccountSeaportBulkSigSupport._lookupBulkOrderTypehash.asm_0.lookupTypeHash().typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash (contracts/extension/SeaportOrderParser.sol#359) is written in both typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash = ternary(treeHeight__lookupBulkOrderTypehash_asm_0_lookupTypeHash == 5,BulkOrder_Typehash_Height_Five,BulkOrder_Typehash_Height_Six) (contracts/extension/SeaportOrderParser.sol#385-386) typeHash__lookupBulkOrderTypehash_asm_0_lookupTypeHash = ternary(treeHeight__lookupBulkOrderTypehash_asm_0_lookupTypeHash == 7,BulkOrder_Typehash_Height_Seven,BulkOrder_Typehash_Height_Eight) (contracts/extension/SeaportOrderParser.sol#393-394)
Comment on lines 359 to 481
function lookupTypeHash(treeHeight) -> typeHash {
// Handle tree heights one through eight.
if lt(treeHeight, 9) {
// Handle tree heights one through four.
if lt(treeHeight, 5) {
// Handle tree heights one and two.
if lt(treeHeight, 3) {
// Utilize branchless logic to determine typehash.
typeHash :=
ternary(eq(treeHeight, 1), BulkOrder_Typehash_Height_One, BulkOrder_Typehash_Height_Two)

// Exit the function once typehash has been located.
leave
}

// Handle height three and four via branchless logic.
typeHash :=
ternary(eq(treeHeight, 3), BulkOrder_Typehash_Height_Three, BulkOrder_Typehash_Height_Four)

// Exit the function once typehash has been located.
leave
}

// Handle tree height five and six.
if lt(treeHeight, 7) {
// Utilize branchless logic to determine typehash.
typeHash :=
ternary(eq(treeHeight, 5), BulkOrder_Typehash_Height_Five, BulkOrder_Typehash_Height_Six)

// Exit the function once typehash has been located.
leave
}

// Handle height seven and eight via branchless logic.
typeHash :=
ternary(eq(treeHeight, 7), BulkOrder_Typehash_Height_Seven, BulkOrder_Typehash_Height_Eight)

// Exit the function once typehash has been located.
leave
}

// Handle tree height nine through sixteen.
if lt(treeHeight, 17) {
// Handle tree height nine through twelve.
if lt(treeHeight, 13) {
// Handle tree height nine and ten.
if lt(treeHeight, 11) {
// Utilize branchless logic to determine typehash.
typeHash :=
ternary(eq(treeHeight, 9), BulkOrder_Typehash_Height_Nine, BulkOrder_Typehash_Height_Ten)

// Exit the function once typehash has been located.
leave
}

// Handle height eleven and twelve via branchless logic.
typeHash :=
ternary(eq(treeHeight, 11), BulkOrder_Typehash_Height_Eleven, BulkOrder_Typehash_Height_Twelve)

// Exit the function once typehash has been located.
leave
}

// Handle tree height thirteen and fourteen.
if lt(treeHeight, 15) {
// Utilize branchless logic to determine typehash.
typeHash :=
ternary(
eq(treeHeight, 13), BulkOrder_Typehash_Height_Thirteen, BulkOrder_Typehash_Height_Fourteen
)

// Exit the function once typehash has been located.
leave
}
// Handle height fifteen and sixteen via branchless logic.
typeHash :=
ternary(eq(treeHeight, 15), BulkOrder_Typehash_Height_Fifteen, BulkOrder_Typehash_Height_Sixteen)

// Exit the function once typehash has been located.
leave
}

// Handle tree height seventeen through twenty.
if lt(treeHeight, 21) {
// Handle tree height seventeen and eighteen.
if lt(treeHeight, 19) {
// Utilize branchless logic to determine typehash.
typeHash :=
ternary(
eq(treeHeight, 17), BulkOrder_Typehash_Height_Seventeen, BulkOrder_Typehash_Height_Eighteen
)

// Exit the function once typehash has been located.
leave
}

// Handle height nineteen and twenty via branchless logic.
typeHash :=
ternary(eq(treeHeight, 19), BulkOrder_Typehash_Height_Nineteen, BulkOrder_Typehash_Height_Twenty)

// Exit the function once typehash has been located.
leave
}

// Handle tree height twenty-one and twenty-two.
if lt(treeHeight, 23) {
// Utilize branchless logic to determine typehash.
typeHash :=
ternary(
eq(treeHeight, 21), BulkOrder_Typehash_Height_TwentyOne, BulkOrder_Typehash_Height_TwentyTwo
)

// Exit the function once typehash has been located.
leave
}

// Handle height twenty-three & twenty-four w/ branchless logic.
typeHash :=
ternary(eq(treeHeight, 23), BulkOrder_Typehash_Height_TwentyThree, BulkOrder_Typehash_Height_TwentyFour)

// Exit the function once typehash has been located.
leave
}

Check warning

Code scanning / Slither

Assembly usage

SeaportEIP1271._lookupBulkOrderTypehash.asm_0.lookupTypeHash() (contracts/extension/SeaportOrderParser.sol#359-481) uses assembly - INLINE ASM (contracts/extension/SeaportOrderParser.sol#359-481)
Comment on lines +484 to +486
function ternary(cond, ifTrue, ifFalse) -> c {
c := xor(ifFalse, mul(cond, xor(ifFalse, ifTrue)))
}

Check warning

Code scanning / Slither

Assembly usage

AccountSeaportBulkSigSupport._lookupBulkOrderTypehash.asm_0.ternary() (contracts/extension/SeaportOrderParser.sol#484-486) uses assembly - INLINE ASM (contracts/extension/SeaportOrderParser.sol#484-486)
Comment on lines 359 to 481
function lookupTypeHash(treeHeight) -> typeHash {
// Handle tree heights one through eight.
if lt(treeHeight, 9) {
// Handle tree heights one through four.
if lt(treeHeight, 5) {
// Handle tree heights one and two.
if lt(treeHeight, 3) {
// Utilize branchless logic to determine typehash.
typeHash :=
ternary(eq(treeHeight, 1), BulkOrder_Typehash_Height_One, BulkOrder_Typehash_Height_Two)

// Exit the function once typehash has been located.
leave
}

// Handle height three and four via branchless logic.
typeHash :=
ternary(eq(treeHeight, 3), BulkOrder_Typehash_Height_Three, BulkOrder_Typehash_Height_Four)

// Exit the function once typehash has been located.
leave
}

// Handle tree height five and six.
if lt(treeHeight, 7) {
// Utilize branchless logic to determine typehash.
typeHash :=
ternary(eq(treeHeight, 5), BulkOrder_Typehash_Height_Five, BulkOrder_Typehash_Height_Six)

// Exit the function once typehash has been located.
leave
}

// Handle height seven and eight via branchless logic.
typeHash :=
ternary(eq(treeHeight, 7), BulkOrder_Typehash_Height_Seven, BulkOrder_Typehash_Height_Eight)

// Exit the function once typehash has been located.
leave
}

// Handle tree height nine through sixteen.
if lt(treeHeight, 17) {
// Handle tree height nine through twelve.
if lt(treeHeight, 13) {
// Handle tree height nine and ten.
if lt(treeHeight, 11) {
// Utilize branchless logic to determine typehash.
typeHash :=
ternary(eq(treeHeight, 9), BulkOrder_Typehash_Height_Nine, BulkOrder_Typehash_Height_Ten)

// Exit the function once typehash has been located.
leave
}

// Handle height eleven and twelve via branchless logic.
typeHash :=
ternary(eq(treeHeight, 11), BulkOrder_Typehash_Height_Eleven, BulkOrder_Typehash_Height_Twelve)

// Exit the function once typehash has been located.
leave
}

// Handle tree height thirteen and fourteen.
if lt(treeHeight, 15) {
// Utilize branchless logic to determine typehash.
typeHash :=
ternary(
eq(treeHeight, 13), BulkOrder_Typehash_Height_Thirteen, BulkOrder_Typehash_Height_Fourteen
)

// Exit the function once typehash has been located.
leave
}
// Handle height fifteen and sixteen via branchless logic.
typeHash :=
ternary(eq(treeHeight, 15), BulkOrder_Typehash_Height_Fifteen, BulkOrder_Typehash_Height_Sixteen)

// Exit the function once typehash has been located.
leave
}

// Handle tree height seventeen through twenty.
if lt(treeHeight, 21) {
// Handle tree height seventeen and eighteen.
if lt(treeHeight, 19) {
// Utilize branchless logic to determine typehash.
typeHash :=
ternary(
eq(treeHeight, 17), BulkOrder_Typehash_Height_Seventeen, BulkOrder_Typehash_Height_Eighteen
)

// Exit the function once typehash has been located.
leave
}

// Handle height nineteen and twenty via branchless logic.
typeHash :=
ternary(eq(treeHeight, 19), BulkOrder_Typehash_Height_Nineteen, BulkOrder_Typehash_Height_Twenty)

// Exit the function once typehash has been located.
leave
}

// Handle tree height twenty-one and twenty-two.
if lt(treeHeight, 23) {
// Utilize branchless logic to determine typehash.
typeHash :=
ternary(
eq(treeHeight, 21), BulkOrder_Typehash_Height_TwentyOne, BulkOrder_Typehash_Height_TwentyTwo
)

// Exit the function once typehash has been located.
leave
}

// Handle height twenty-three & twenty-four w/ branchless logic.
typeHash :=
ternary(eq(treeHeight, 23), BulkOrder_Typehash_Height_TwentyThree, BulkOrder_Typehash_Height_TwentyFour)

// Exit the function once typehash has been located.
leave
}

Check warning

Code scanning / Slither

Cyclomatic complexity

AccountSeaportBulkSigSupport._lookupBulkOrderTypehash.asm_0.lookupTypeHash() (contracts/extension/SeaportOrderParser.sol#359-481) has a high cyclomatic complexity (12).
Comment on lines +38 to +204
function _deriveOrderHash(
OrderParameters memory orderParameters,
uint256 counter
) internal view returns (bytes32 orderHash) {
// Get length of original consideration array and place it on the stack.
uint256 originalConsiderationLength = (orderParameters.totalOriginalConsiderationItems);

/*
* Memory layout for an array of structs (dynamic or not) is similar
* to ABI encoding of dynamic types, with a head segment followed by
* a data segment. The main difference is that the head of an element
* is a memory pointer rather than an offset.
*/

// Declare a variable for the derived hash of the offer array.
bytes32 offerHash;

// Read offer item EIP-712 typehash from runtime code & place on stack.
bytes32 typeHash = _OFFER_ITEM_TYPEHASH;

// Utilize assembly so that memory regions can be reused across hashes.
assembly {
// Retrieve the free memory pointer and place on the stack.
let hashArrPtr := mload(FreeMemoryPointerSlot)

// Get the pointer to the offers array.
let offerArrPtr := mload(add(orderParameters, OrderParameters_offer_head_offset))

// Load the length.
let offerLength := mload(offerArrPtr)

// Set the pointer to the first offer's head.
offerArrPtr := add(offerArrPtr, OneWord)

// Iterate over the offer items.
for {
let i := 0
} lt(i, offerLength) {
i := add(i, 1)
} {
// Read the pointer to the offer data and subtract one word
// to get typeHash pointer.
let ptr := sub(mload(offerArrPtr), OneWord)

// Read the current value before the offer data.
let value := mload(ptr)

// Write the type hash to the previous word.
mstore(ptr, typeHash)

// Take the EIP712 hash and store it in the hash array.
mstore(hashArrPtr, keccak256(ptr, EIP712_OfferItem_size))

// Restore the previous word.
mstore(ptr, value)

// Increment the array pointers by one word.
offerArrPtr := add(offerArrPtr, OneWord)
hashArrPtr := add(hashArrPtr, OneWord)
}

// Derive the offer hash using the hashes of each item.
offerHash := keccak256(mload(FreeMemoryPointerSlot), shl(OneWordShift, offerLength))
}

// Declare a variable for the derived hash of the consideration array.
bytes32 considerationHash;

// Read consideration item typehash from runtime code & place on stack.
typeHash = _CONSIDERATION_ITEM_TYPEHASH;

// Utilize assembly so that memory regions can be reused across hashes.
assembly {
// Retrieve the free memory pointer and place on the stack.
let hashArrPtr := mload(FreeMemoryPointerSlot)

// Get the pointer to the consideration array.
let considerationArrPtr := add(
mload(add(orderParameters, OrderParameters_consideration_head_offset)),
OneWord
)

// Iterate over the consideration items (not including tips).
for {
let i := 0
} lt(i, originalConsiderationLength) {
i := add(i, 1)
} {
// Read the pointer to the consideration data and subtract one
// word to get typeHash pointer.
let ptr := sub(mload(considerationArrPtr), OneWord)

// Read the current value before the consideration data.
let value := mload(ptr)

// Write the type hash to the previous word.
mstore(ptr, typeHash)

// Take the EIP712 hash and store it in the hash array.
mstore(hashArrPtr, keccak256(ptr, EIP712_ConsiderationItem_size))

// Restore the previous word.
mstore(ptr, value)

// Increment the array pointers by one word.
considerationArrPtr := add(considerationArrPtr, OneWord)
hashArrPtr := add(hashArrPtr, OneWord)
}

// Derive the consideration hash using the hashes of each item.
considerationHash := keccak256(mload(FreeMemoryPointerSlot), shl(OneWordShift, originalConsiderationLength))
}

// Read order item EIP-712 typehash from runtime code & place on stack.
typeHash = _ORDER_TYPEHASH;

// Utilize assembly to access derived hashes & other arguments directly.
assembly {
// Retrieve pointer to the region located just behind parameters.
let typeHashPtr := sub(orderParameters, OneWord)

// Store the value at that pointer location to restore later.
let previousValue := mload(typeHashPtr)

// Store the order item EIP-712 typehash at the typehash location.
mstore(typeHashPtr, typeHash)

// Retrieve the pointer for the offer array head.
let offerHeadPtr := add(orderParameters, OrderParameters_offer_head_offset)

// Retrieve the data pointer referenced by the offer head.
let offerDataPtr := mload(offerHeadPtr)

// Store the offer hash at the retrieved memory location.
mstore(offerHeadPtr, offerHash)

// Retrieve the pointer for the consideration array head.
let considerationHeadPtr := add(orderParameters, OrderParameters_consideration_head_offset)

// Retrieve the data pointer referenced by the consideration head.
let considerationDataPtr := mload(considerationHeadPtr)

// Store the consideration hash at the retrieved memory location.
mstore(considerationHeadPtr, considerationHash)

// Retrieve the pointer for the counter.
let counterPtr := add(orderParameters, OrderParameters_counter_offset)

// Store the counter at the retrieved memory location.
mstore(counterPtr, counter)

// Derive the order hash using the full range of order parameters.
orderHash := keccak256(typeHashPtr, EIP712_Order_size)

// Restore the value previously held at typehash pointer location.
mstore(typeHashPtr, previousValue)

// Restore offer data pointer at the offer head pointer location.
mstore(offerHeadPtr, offerDataPtr)

// Restore consideration data pointer at the consideration head ptr.
mstore(considerationHeadPtr, considerationDataPtr)

// Restore consideration item length at the counter pointer.
mstore(counterPtr, originalConsiderationLength)
}
}

Check warning

Code scanning / Slither

Assembly usage

SeaportOrderParser._deriveOrderHash(OrderParameters,uint256) (contracts/extension/SeaportOrderParser.sol#38-204) uses assembly - INLINE ASM (contracts/extension/SeaportOrderParser.sol#59-101) - INLINE ASM (contracts/extension/SeaportOrderParser.sol#110-149) - INLINE ASM (contracts/extension/SeaportOrderParser.sol#155-203)
Comment on lines 292 to 355
function _computeBulkOrderProof(
bytes memory proofAndSignature,
bytes32 leaf
) internal pure returns (bytes32 bulkOrderHash) {
// Declare arguments for the root hash and the height of the proof.
bytes32 root;
uint256 height;

// Utilize assembly to efficiently derive the root hash using the proof.
assembly {
// Retrieve the length of the proof, key, and signature combined.
let fullLength := mload(proofAndSignature)

// If proofAndSignature has odd length, it is a compact signature
// with 64 bytes.
let signatureLength := sub(ECDSA_MaxLength, and(fullLength, 1))

// Derive height (or depth of tree) with signature and proof length.
height := shr(OneWordShift, sub(fullLength, signatureLength))

// Update the length in memory to only include the signature.
mstore(proofAndSignature, signatureLength)

// Derive the pointer for the key using the signature length.
let keyPtr := add(proofAndSignature, add(OneWord, signatureLength))

// Retrieve the three-byte key using the derived pointer.
let key := shr(BulkOrderProof_keyShift, mload(keyPtr))

/// Retrieve pointer to first proof element by applying a constant
// for the key size to the derived key pointer.
let proof := add(keyPtr, BulkOrderProof_keySize)

// Compute level 1.
let scratchPtr1 := shl(OneWordShift, and(key, 1))
mstore(scratchPtr1, leaf)
mstore(xor(scratchPtr1, OneWord), mload(proof))

// Compute remaining proofs.
for {
let i := 1
} lt(i, height) {
i := add(i, 1)
} {
proof := add(proof, OneWord)
let scratchPtr := shl(OneWordShift, and(shr(i, key), 1))
mstore(scratchPtr, keccak256(0, TwoWords))
mstore(xor(scratchPtr, OneWord), mload(proof))
}

// Compute root hash.
root := keccak256(0, TwoWords)
}

// Retrieve appropriate typehash constant based on height.
bytes32 rootTypeHash = _lookupBulkOrderTypehash(height);

// Use the typehash and the root hash to derive final bulk order hash.
assembly {
mstore(0, rootTypeHash)
mstore(OneWord, root)
bulkOrderHash := keccak256(0, TwoWords)
}
}

Check warning

Code scanning / Slither

Assembly usage

SeaportOrderParser._computeBulkOrderProof(bytes,bytes32) (contracts/extension/SeaportOrderParser.sol#292-355) uses assembly - INLINE ASM (contracts/extension/SeaportOrderParser.sol#301-344) - INLINE ASM (contracts/extension/SeaportOrderParser.sol#350-354)
@nkrishang nkrishang enabled auto-merge (squash) March 26, 2024 09:41
@codecov
Copy link

codecov bot commented Mar 26, 2024

Codecov Report

Attention: Patch coverage is 0% with 61 lines in your changes are missing coverage. Please review.

Project coverage is 64.69%. Comparing base (b44b563) to head (85b889b).

❗ Current head 85b889b differs from pull request most recent head 03f77c1. Consider uploading reports for the commit 03f77c1 to get more accurate results

Files Patch % Lines
contracts/extension/SeaportOrderParser.sol 0.00% 31 Missing ⚠️
contracts/extension/SeaportEIP1271.sol 0.00% 20 Missing ⚠️
...lts/account/utils/AccountSeaportBulkSigSupport.sol 0.00% 10 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #633      +/-   ##
==========================================
- Coverage   65.26%   64.69%   -0.58%     
==========================================
  Files         217      220       +3     
  Lines        6847     6908      +61     
==========================================
  Hits         4469     4469              
- Misses       2378     2439      +61     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@nkrishang nkrishang merged commit a9e6477 into main Mar 26, 2024
@nkrishang nkrishang deleted the nk/seaport-bulk-sig-support branch March 26, 2024 11:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants