Reuse efficient hash function from GettersAndDerivers#_deriveConduit in ConduitController
ConduitController#createConduit and ConduitController#getConduit both calculate the deterministic conduit address using abi.encodePacked, keccak256, and type conversions:
function createConduit(bytes32 conduitKey, address initialOwner)
external
override
returns (address conduit)
{
// If the first 20 bytes of the conduit key do not match the caller...
if (address(uint160(bytes20(conduitKey))) != msg.sender) {
// Revert with an error indicating that the creator is invalid.
revert InvalidCreator();
}
// Derive address from deployer, conduit key and creation code hash.
conduit = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
bytes1(0xff),
address(this),
conduitKey,
_CONDUIT_CREATION_CODE_HASH
)
)
)
)
);
...
}
// Leverage scratch space to perform an efficient hash.
assembly {
// Retrieve the free memory pointer; it will be replaced afterwards.
let freeMemoryPointer := mload(FreeMemoryPointerSlot)
// Place the control character and the conduit controller in scratch
// space; note that eleven bytes at the beginning are left unused.
mstore(0, or(MaskOverByteTwelve, conduitController))
// Place the conduit key in the next region of scratch space.
mstore(OneWord, conduitKey)
// Place conduit creation code hash in free memory pointer location.
mstore(TwoWords, conduitCreationCodeHash)
// Derive conduit by hashing and applying a mask over last 20 bytes.
conduit := and(
// Hash the relevant region.
keccak256(
// The region starts at memory pointer 11.
Create2AddressDerivation_ptr,
// The region is 85 bytes long (1 + 20 + 32 + 32).
Create2AddressDerivation_length
),
// The address equals the last twenty bytes of the hash.
MaskOverLastTwentyBytes
)
// Restore the free memory pointer.
mstore(FreeMemoryPointerSlot, freeMemoryPointer)
}
You'll need to make one small modification, and use address() directly to access the current address in the first mstore:
// Read conduit creation code hash from runtime and place on the stack.
bytes32 conduitCreationCodeHash = _CONDUIT_CREATION_CODE_HASH;
// Derive address from deployer, conduit key and creation code hash.
assembly {
// Retrieve the free memory pointer; it will be replaced afterwards.
let freeMemoryPointer := mload(FreeMemoryPointerSlot)
// Place the control character and the deployer address in scratch
// space; note that eleven bytes at the beginning are left unused.
mstore(0, or(MaskOverByteTwelve, address()))
// Place the conduit key in the next region of scratch space.
mstore(OneWord, conduitKey)
// Place conduit creation code hash in free memory pointer location.
mstore(TwoWords, conduitCreationCodeHash)
// Derive conduit by hashing and applying a mask over last 20 bytes.
conduit := and(
// Hash the relevant region.
keccak256(
// The region starts at memory pointer 11.
Create2AddressDerivation_ptr,
// The region is 85 bytes long (1 + 20 + 32 + 32).
Create2AddressDerivation_length
),
// The address equals the last twenty bytes of the hash.
MaskOverLastTwentyBytes
)
// Restore the free memory pointer.
mstore(FreeMemoryPointerSlot, freeMemoryPointer)
}
Reuse efficient hash function from
GettersAndDerivers#_deriveConduit
inConduitController
ConduitController#createConduit
andConduitController#getConduit
both calculate the deterministic conduit address usingabi.encodePacked
,keccak256
, and type conversions:ConduitController#createConduit
ConduitController#getConduit
Reusing the same efficient hash implementation using scratch space from
GettersAndDerivers#_deriveConduit
can save gas in these calculations.GettersAndDerivers#_deriveConduit
You'll need to make one small modification, and use
address()
directly to access the current address in the firstmstore
:Status quo gas report:
Using efficient hash: