From 90491d217f50d43dfcbac081af35cb72538d3b69 Mon Sep 17 00:00:00 2001 From: Krishang Date: Wed, 21 Feb 2024 14:16:04 +0530 Subject: [PATCH 01/12] POC: Seaport bulk signatures not supported by Account.isValidSignature --- .gitmodules | 12 ++ foundry.toml | 4 + lib/murky | 1 + lib/seaport-core | 1 + lib/seaport-sol | 1 + lib/seaport-types | 1 + src/test/seaport/AccountBulkOrderSig.t.sol | 213 +++++++++++++++++++ src/test/seaport/EIP712MerkleTree.sol | 226 +++++++++++++++++++++ src/test/seaport/Seaport.sol | 121 +++++++++++ 9 files changed, 580 insertions(+) create mode 160000 lib/murky create mode 160000 lib/seaport-core create mode 160000 lib/seaport-sol create mode 160000 lib/seaport-types create mode 100644 src/test/seaport/AccountBulkOrderSig.t.sol create mode 100644 src/test/seaport/EIP712MerkleTree.sol create mode 100644 src/test/seaport/Seaport.sol diff --git a/.gitmodules b/.gitmodules index 7872f5e50..36d13a4de 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,15 @@ [submodule "lib/dynamic-contracts"] path = lib/dynamic-contracts url = https://github.com/thirdweb-dev/dynamic-contracts +[submodule "lib/seaport-sol"] + path = lib/seaport-sol + url = https://github.com/ProjectOpenSea/seaport-sol +[submodule "lib/murky"] + path = lib/murky + url = https://github.com/dmfxyz/murky +[submodule "lib/seaport-types"] + path = lib/seaport-types + url = https://github.com/ProjectOpenSea/seaport-types +[submodule "lib/seaport-core"] + path = lib/seaport-core + url = https://github.com/ProjectOpenSea/seaport-core diff --git a/foundry.toml b/foundry.toml index a86fc9b13..d2cf92874 100644 --- a/foundry.toml +++ b/foundry.toml @@ -39,6 +39,10 @@ remappings = [ 'erc721a/=lib/ERC721A/', '@thirdweb-dev/dynamic-contracts/=lib/dynamic-contracts/', 'lib/sstore2=lib/dynamic-contracts/lib/sstore2/', + 'murky/=lib/murky/src/', + 'seaport-sol/=lib/seaport-sol/', + 'seaport-types/=lib/seaport-types/', + 'seaport-core/=lib/seaport-core/' ] fs_permissions = [{ access = "read-write", path = "./src/test/smart-wallet/utils"}] src = 'contracts' diff --git a/lib/murky b/lib/murky new file mode 160000 index 000000000..40de6e801 --- /dev/null +++ b/lib/murky @@ -0,0 +1 @@ +Subproject commit 40de6e80117f39cda69d71b07b7c824adac91b29 diff --git a/lib/seaport-core b/lib/seaport-core new file mode 160000 index 000000000..d4e8c74ad --- /dev/null +++ b/lib/seaport-core @@ -0,0 +1 @@ +Subproject commit d4e8c74adc472b311ab64b5c9f9757b5bba57a15 diff --git a/lib/seaport-sol b/lib/seaport-sol new file mode 160000 index 000000000..040d00576 --- /dev/null +++ b/lib/seaport-sol @@ -0,0 +1 @@ +Subproject commit 040d005768abafe3308b5f996aca3fd843d9c20e diff --git a/lib/seaport-types b/lib/seaport-types new file mode 160000 index 000000000..25bae8ddf --- /dev/null +++ b/lib/seaport-types @@ -0,0 +1 @@ +Subproject commit 25bae8ddfa8709e5c51ab429fe06024e46a18f15 diff --git a/src/test/seaport/AccountBulkOrderSig.t.sol b/src/test/seaport/AccountBulkOrderSig.t.sol new file mode 100644 index 000000000..184e0765e --- /dev/null +++ b/src/test/seaport/AccountBulkOrderSig.t.sol @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.0; + +// Test utils +import "../utils/BaseTest.sol"; + +// Account Abstraction setup for smart wallets. +import { EntryPoint, IEntryPoint } from "contracts/prebuilts/account/utils/Entrypoint.sol"; +import { UserOperation } from "contracts/prebuilts/account/utils/UserOperation.sol"; + +// Target +import { AccountFactory, Account as SimpleAccount } from "contracts/prebuilts/account/non-upgradeable/AccountFactory.sol"; +import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; + +import { Seaport } from "./Seaport.sol"; +import { EIP712MerkleTree } from "./EIP712MerkleTree.sol"; + +import { ConduitController } from "seaport-core/src/conduit/ConduitController.sol"; +import { ConsiderationItem, OfferItem, ItemType, SpentItem, OrderComponents, Order, OrderParameters } from "seaport-types/src/lib/ConsiderationStructs.sol"; +import { ConsiderationInterface } from "seaport-types/src/interfaces/ConsiderationInterface.sol"; +import { OrderType, BasicOrderType } from "seaport-types/src/lib/ConsiderationEnums.sol"; + +library GPv2EIP1271 { + bytes4 internal constant MAGICVALUE = 0x1626ba7e; +} + +interface EIP1271Verifier { + function isValidSignature(bytes32 _hash, bytes memory _signature) external view returns (bytes4 magicValue); +} + +contract AccountBulkOrderSigTest is BaseTest { + // Target contracts + EntryPoint private entrypoint; + AccountFactory private accountFactory; + Seaport private seaport; + + // Signer + uint256 private accountAdminPKey = 1; + address private accountAdmin; + + // Test params + OfferItem offerItem; + OfferItem[] offerItems; + ConsiderationItem considerationItem; + ConsiderationItem[] considerationItems; + OrderComponents baseOrderComponents; + OrderParameters baseOrderParameters; + + // UserOp terminology: `sender` is the smart wallet. + address private sender = 0xAcF86fd6BA3b8A4CBDbc1F0A605e1667a8879640; + address payable private beneficiary = payable(address(0x45654)); + + function _configureOrderParameters(address offerer) internal { + bytes32 conduitKey = bytes32(0); + baseOrderParameters.offerer = offerer; + baseOrderParameters.zone = address(0); + baseOrderParameters.offer = offerItems; + baseOrderParameters.consideration = considerationItems; + baseOrderParameters.orderType = OrderType.FULL_OPEN; + baseOrderParameters.startTime = block.timestamp; + baseOrderParameters.endTime = block.timestamp + 1; + baseOrderParameters.zoneHash = bytes32(0); + baseOrderParameters.salt = 0; + baseOrderParameters.conduitKey = conduitKey; + baseOrderParameters.totalOriginalConsiderationItems = considerationItems.length; + } + + function _configureConsiderationItems() internal { + considerationItem.itemType = ItemType.NATIVE; + considerationItem.token = address(0); + considerationItem.identifierOrCriteria = 0; + considerationItem.startAmount = 1; + considerationItem.endAmount = 1; + considerationItem.recipient = payable(address(0x123)); + considerationItems.push(considerationItem); + } + + function configureOrderComponents(uint256 counter) internal { + baseOrderComponents.offerer = baseOrderParameters.offerer; + baseOrderComponents.zone = baseOrderParameters.zone; + baseOrderComponents.offer = baseOrderParameters.offer; + baseOrderComponents.consideration = baseOrderParameters.consideration; + baseOrderComponents.orderType = baseOrderParameters.orderType; + baseOrderComponents.startTime = baseOrderParameters.startTime; + baseOrderComponents.endTime = baseOrderParameters.endTime; + baseOrderComponents.zoneHash = baseOrderParameters.zoneHash; + baseOrderComponents.salt = baseOrderParameters.salt; + baseOrderComponents.conduitKey = baseOrderParameters.conduitKey; + baseOrderComponents.counter = counter; + } + + function _setupUserOp( + uint256 _signerPKey, + bytes memory _initCode, + bytes memory _callDataForEntrypoint + ) internal returns (UserOperation[] memory ops) { + uint256 nonce = entrypoint.getNonce(sender, 0); + + // Get user op fields + UserOperation memory op = UserOperation({ + sender: sender, + nonce: nonce, + initCode: _initCode, + callData: _callDataForEntrypoint, + callGasLimit: 500_000, + verificationGasLimit: 500_000, + preVerificationGas: 500_000, + maxFeePerGas: 0, + maxPriorityFeePerGas: 0, + paymasterAndData: bytes(""), + signature: bytes("") + }); + + // Sign UserOp + bytes32 opHash = EntryPoint(entrypoint).getUserOpHash(op); + bytes32 msgHash = ECDSA.toEthSignedMessageHash(opHash); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_signerPKey, msgHash); + bytes memory userOpSignature = abi.encodePacked(r, s, v); + + address recoveredSigner = ECDSA.recover(msgHash, v, r, s); + address expectedSigner = vm.addr(_signerPKey); + assertEq(recoveredSigner, expectedSigner); + + op.signature = userOpSignature; + + // Store UserOp + ops = new UserOperation[](1); + ops[0] = op; + } + + function _setupUserOpExecute( + uint256 _signerPKey, + bytes memory _initCode, + address _target, + uint256 _value, + bytes memory _callData + ) internal returns (UserOperation[] memory) { + bytes memory callDataForEntrypoint = abi.encodeWithSignature( + "execute(address,uint256,bytes)", + _target, + _value, + _callData + ); + + return _setupUserOp(_signerPKey, _initCode, callDataForEntrypoint); + } + + function setUp() public override { + super.setUp(); + + // Setup signers. + string memory offerer = "offerer"; + (address addr, uint256 key) = makeAddrAndKey(offerer); + + accountAdmin = addr; + accountAdminPKey = key; + vm.deal(accountAdmin, 100 ether); + + // Setup contracts + entrypoint = new EntryPoint(); + // deploy account factory + accountFactory = new AccountFactory(deployer, IEntryPoint(payable(address(entrypoint)))); + // deploy seaport contract + seaport = new Seaport(address(new ConduitController())); + + bytes memory initCallData = abi.encodeWithSignature("createAccount(address,bytes)", accountAdmin, bytes("")); + bytes memory initCode = abi.encodePacked(abi.encodePacked(address(accountFactory)), initCallData); + + UserOperation[] memory userOpCreateAccount = _setupUserOpExecute( + accountAdminPKey, + initCode, + address(0), + 0, + bytes("") + ); + + EntryPoint(entrypoint).handleOps(userOpCreateAccount, beneficiary); + } + + /*////////////////////////////////////////////////////////// + Test: performing a contract call + //////////////////////////////////////////////////////////////*/ + + function test_POC() public { + erc721.mint(address(accountAdmin), 1); + vm.prank(accountAdmin); + erc721.setApprovalForAll(address(seaport), true); + + _configureConsiderationItems(); + _configureOrderParameters(sender); + // _configureOrderParameters(accountAdmin); + configureOrderComponents(seaport.getCounter(accountAdmin)); + OrderComponents[] memory orderComponents = new OrderComponents[](3); + orderComponents[0] = baseOrderComponents; + // The other order components can remain empty. + + EIP712MerkleTree merkleTree = new EIP712MerkleTree(); + bytes memory bulkSignature = merkleTree.signBulkOrder( + ConsiderationInterface(address(seaport)), + accountAdminPKey, + orderComponents, + uint24(0), + false + ); + + Order memory order = Order({ parameters: baseOrderParameters, signature: bulkSignature }); + + assertEq(bulkSignature.length, 132); + vm.expectRevert("ECDSA: invalid signature length"); + seaport.fulfillOrder{ value: 1 }(order, bytes32(0)); + } +} diff --git a/src/test/seaport/EIP712MerkleTree.sol b/src/test/seaport/EIP712MerkleTree.sol new file mode 100644 index 000000000..d697196fa --- /dev/null +++ b/src/test/seaport/EIP712MerkleTree.sol @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import { MurkyBase } from "murky/common/MurkyBase.sol"; + +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; + +import { Test } from "forge-std/Test.sol"; + +import { OrderComponents } from "seaport-sol/src/SeaportStructs.sol"; + +import { SeaportInterface } from "seaport-sol/src/SeaportInterface.sol"; + +import { TypehashDirectory } from "./TypehashDirectory.sol"; + +/** + * @dev Seaport doesn't sort leaves when hashing for bulk orders, but Murky + * does, so implement a custom hashLeafPairs function + */ +contract MerkleUnsorted is MurkyBase { + function hashLeafPairs(bytes32 left, bytes32 right) public pure override returns (bytes32 _hash) { + assembly { + mstore(0x0, left) + mstore(0x20, right) + _hash := keccak256(0x0, 0x40) + } + } +} + +contract EIP712MerkleTree is Test { + // data contract to retrieve bulk order typehashes + TypehashDirectory internal immutable _typehashDirectory; + OrderComponents private emptyOrderComponents; + MerkleUnsorted private merkle; + + constructor() { + _typehashDirectory = new TypehashDirectory(); + merkle = new MerkleUnsorted(); + } + + /** + * @dev Creates a single bulk signature: a base signature + a three byte + * index + a series of 32 byte proofs. The height of the tree is determined + * by the length of the orderComponents array and only fills empty orders + * into the tree to make the length a power of 2. + */ + function signBulkOrder( + SeaportInterface consideration, + uint256 privateKey, + OrderComponents[] memory orderComponents, + uint24 orderIndex, + bool useCompact2098 + ) public view returns (bytes memory) { + // cache the hash of an empty order components struct to fill out any + // nodes required to make the length a power of 2 + bytes32 emptyComponentsHash = consideration.getOrderHash(emptyOrderComponents); + // declare vars here to avoid stack too deep errors + bytes32[] memory leaves; + bytes32 bulkOrderTypehash; + // block scope to avoid stacc 2 dank + { + // height of merkle tree is log2(length), rounded up to next power + // of 2 + uint256 height = Math.log2(orderComponents.length); + // Murky won't let you compute a merkle tree with only 1 leaf, so + // if height is 0 (length is 1), set height to 1 + if (2 ** height != orderComponents.length || height == 0) { + height += 1; + } + // get the typehash for a bulk order of this height + bulkOrderTypehash = _lookupBulkOrderTypehash(height); + // allocate array for leaf hashes + leaves = new bytes32[](2 ** height); + // hash each original order component + for (uint256 i = 0; i < orderComponents.length; i++) { + leaves[i] = consideration.getOrderHash(orderComponents[i]); + } + // fill out empty node hashes + for (uint256 i = orderComponents.length; i < 2 ** height; i++) { + leaves[i] = emptyComponentsHash; + } + } + + // get the proof for the order index + bytes32[] memory proof = merkle.getProof(leaves, orderIndex); + bytes32 root = merkle.getRoot(leaves); + + return _getSignature(consideration, privateKey, bulkOrderTypehash, root, proof, orderIndex, useCompact2098); + } + + /** + * @dev Creates a single bulk signature: a base signature + a three byte + * index + a series of 32 byte proofs. The height of the tree is determined + * by the height parameter and this function will fill empty orders into the + * tree until the specified height is reached. + */ + function signSparseBulkOrder( + SeaportInterface consideration, + uint256 privateKey, + OrderComponents memory orderComponents, + uint256 height, + uint24 orderIndex, + bool useCompact2098 + ) public view returns (bytes memory) { + require(orderIndex < 2 ** height, "orderIndex out of bounds"); + // get hash of actual order + bytes32 orderHash = consideration.getOrderHash(orderComponents); + // get initial empty order components hash + bytes32 emptyComponentsHash = consideration.getOrderHash(emptyOrderComponents); + + // calculate intermediate hashes of a sparse order tree + // this will also serve as our proof + bytes32[] memory emptyHashes = new bytes32[]((height)); + // first layer is empty order hash + emptyHashes[0] = emptyComponentsHash; + for (uint256 i = 1; i < height; i++) { + bytes32 nextHash; + bytes32 lastHash = emptyHashes[i - 1]; + // subsequent layers are hash of emptyHeight+emptyHeight + assembly { + mstore(0, lastHash) + mstore(0x20, lastHash) + nextHash := keccak256(0, 0x40) + } + emptyHashes[i] = nextHash; + } + // begin calculating order tree root + bytes32 root = orderHash; + // hashIndex is the index within the layer of the non-sparse hash + uint24 hashIndex = orderIndex; + + for (uint256 i = 0; i < height; i++) { + // get sparse hash at this height + bytes32 heightEmptyHash = emptyHashes[i]; + assembly { + // if the hashIndex is odd, our "root" is second component + if and(hashIndex, 1) { + mstore(0, heightEmptyHash) + mstore(0x20, root) + } + // else it is even and our "root" is first component + // (this can def be done in a branchless way but who has the + // time??) + if iszero(and(hashIndex, 1)) { + mstore(0, root) + mstore(0x20, heightEmptyHash) + } + // compute new intermediate hash (or final root) + root := keccak256(0, 0x40) + } + // divide hashIndex by 2 to get index of next layer + // 0 -> 0 + // 1 -> 0 + // 2 -> 1 + // 3 -> 1 + // etc + hashIndex /= 2; + } + + return + _getSignature( + consideration, + privateKey, + _lookupBulkOrderTypehash(height), + root, + emptyHashes, + orderIndex, + useCompact2098 + ); + } + + /** + * @dev same lookup seaport optimized does + */ + function _lookupBulkOrderTypehash(uint256 treeHeight) internal view returns (bytes32 typeHash) { + TypehashDirectory directory = _typehashDirectory; + assembly { + let typeHashOffset := add(1, shl(0x5, sub(treeHeight, 1))) + extcodecopy(directory, 0, typeHashOffset, 0x20) + typeHash := mload(0) + } + } + + function _getSignature( + SeaportInterface consideration, + uint256 privateKey, + bytes32 bulkOrderTypehash, + bytes32 root, + bytes32[] memory proof, + uint24 orderIndex, + bool useCompact2098 + ) internal view returns (bytes memory) { + // bulkOrder hash is keccak256 of the specific bulk order typehash and + // the merkle root of the order hashes + bytes32 bulkOrderHash = keccak256(abi.encode(bulkOrderTypehash, root)); + + // get domain separator from the particular seaport instance + (, bytes32 domainSeparator, ) = consideration.information(); + + // declare out here to avoid stack too deep errors + bytes memory signature; + // avoid stacc 2 thicc + { + (uint8 v, bytes32 r, bytes32 s) = vm.sign( + privateKey, + keccak256(abi.encodePacked(bytes2(0x1901), domainSeparator, bulkOrderHash)) + ); + // if useCompact2098 is true, encode yParity (v) into s + if (useCompact2098) { + uint256 yParity = (v == 27) ? 0 : 1; + bytes32 yAndS = bytes32(uint256(s) | (yParity << 255)); + signature = abi.encodePacked(r, yAndS); + } else { + signature = abi.encodePacked(r, s, v); + } + } + + // return the packed signature, order index, and proof + // encodePacked will pack everything tightly without lengths + // ie, long-style rsv signatures will have 1 byte for v + // orderIndex will be the next 3 bytes + // then proof will be each element one after another; its offset and + // length will not be encoded + return abi.encodePacked(signature, orderIndex, proof); + } +} diff --git a/src/test/seaport/Seaport.sol b/src/test/seaport/Seaport.sol new file mode 100644 index 000000000..7f5a6f55b --- /dev/null +++ b/src/test/seaport/Seaport.sol @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import { Consideration } from "seaport-core/src/lib/Consideration.sol"; + +/** + * @title Seaport + * @custom:version 1.5 + * @author 0age (0age.eth) + * @custom:coauthor d1ll0n (d1ll0n.eth) + * @custom:coauthor transmissions11 (t11s.eth) + * @custom:coauthor James Wenzel (emo.eth) + * @custom:contributor Kartik (slokh.eth) + * @custom:contributor LeFevre (lefevre.eth) + * @custom:contributor Joseph Schiarizzi (CupOJoseph.eth) + * @custom:contributor Aspyn Palatnick (stuckinaboot.eth) + * @custom:contributor Stephan Min (stephanm.eth) + * @custom:contributor Ryan Ghods (ralxz.eth) + * @custom:contributor Daniel Viau (snotrocket.eth) + * @custom:contributor hack3r-0m (hack3r-0m.eth) + * @custom:contributor Diego Estevez (antidiego.eth) + * @custom:contributor Chomtana (chomtana.eth) + * @custom:contributor Saw-mon and Natalie (sawmonandnatalie.eth) + * @custom:contributor 0xBeans (0xBeans.eth) + * @custom:contributor 0x4non (punkdev.eth) + * @custom:contributor Laurence E. Day (norsefire.eth) + * @custom:contributor vectorized.eth (vectorized.eth) + * @custom:contributor karmacoma (karmacoma.eth) + * @custom:contributor horsefacts (horsefacts.eth) + * @custom:contributor UncarvedBlock (uncarvedblock.eth) + * @custom:contributor Zoraiz Mahmood (zorz.eth) + * @custom:contributor William Poulin (wpoulin.eth) + * @custom:contributor Rajiv Patel-O'Connor (rajivpoc.eth) + * @custom:contributor tserg (tserg.eth) + * @custom:contributor cygaar (cygaar.eth) + * @custom:contributor Meta0xNull (meta0xnull.eth) + * @custom:contributor gpersoon (gpersoon.eth) + * @custom:contributor Matt Solomon (msolomon.eth) + * @custom:contributor Weikang Song (weikangs.eth) + * @custom:contributor zer0dot (zer0dot.eth) + * @custom:contributor Mudit Gupta (mudit.eth) + * @custom:contributor leonardoalt (leoalt.eth) + * @custom:contributor cmichel (cmichel.eth) + * @custom:contributor PraneshASP (pranesh.eth) + * @custom:contributor JasperAlexander (jasperalexander.eth) + * @custom:contributor Ellahi (ellahi.eth) + * @custom:contributor zaz (1zaz1.eth) + * @custom:contributor berndartmueller (berndartmueller.eth) + * @custom:contributor dmfxyz (dmfxyz.eth) + * @custom:contributor daltoncoder (dontkillrobots.eth) + * @custom:contributor 0xf4ce (0xf4ce.eth) + * @custom:contributor phaze (phaze.eth) + * @custom:contributor hrkrshnn (hrkrshnn.eth) + * @custom:contributor axic (axic.eth) + * @custom:contributor leastwood (leastwood.eth) + * @custom:contributor 0xsanson (sanson.eth) + * @custom:contributor blockdev (blockd3v.eth) + * @custom:contributor fiveoutofnine (fiveoutofnine.eth) + * @custom:contributor shuklaayush (shuklaayush.eth) + * @custom:contributor dravee (dravee.eth) + * @custom:contributor 0xPatissier + * @custom:contributor pcaversaccio + * @custom:contributor David Eiber + * @custom:contributor csanuragjain + * @custom:contributor sach1r0 + * @custom:contributor twojoy0 + * @custom:contributor ori_dabush + * @custom:contributor Daniel Gelfand + * @custom:contributor okkothejawa + * @custom:contributor FlameHorizon + * @custom:contributor vdrg + * @custom:contributor dmitriia + * @custom:contributor bokeh-eth + * @custom:contributor asutorufos + * @custom:contributor rfart(rfa) + * @custom:contributor Riley Holterhus + * @custom:contributor big-tech-sux + * @notice Seaport is a generalized native token/ERC20/ERC721/ERC1155 + * marketplace with lightweight methods for common routes as well as + * more flexible methods for composing advanced orders or groups of + * orders. Each order contains an arbitrary number of items that may be + * spent (the "offer") along with an arbitrary number of items that must + * be received back by the indicated recipients (the "consideration"). + */ +contract Seaport is Consideration { + /** + * @notice Derive and set hashes, reference chainId, and associated domain + * separator during deployment. + * + * @param conduitController A contract that deploys conduits, or proxies + * that may optionally be used to transfer approved + * ERC20/721/1155 tokens. + */ + constructor(address conduitController) Consideration(conduitController) {} + + /** + * @dev Internal pure function to retrieve and return the name of this + * contract. + * + * @return The name of this contract. + */ + function _name() internal pure override returns (string memory) { + // Return the name of the contract. + assembly { + mstore(0x20, 0x20) + mstore(0x47, 0x07536561706f7274) + return(0x20, 0x60) + } + } + + /** + * @dev Internal pure function to retrieve the name of this contract as a + * string that will be used to derive the name hash in the constructor. + * + * @return The name of this contract as a string. + */ + function _nameString() internal pure override returns (string memory) { + // Return the name of the contract. + return "Seaport"; + } +} From 13572f38e627044f0082f30e569985fdf7c222cf Mon Sep 17 00:00:00 2001 From: Krishang Date: Wed, 21 Feb 2024 14:23:15 +0530 Subject: [PATCH 02/12] Add missing TypehashDirectory --- src/test/seaport/TypehashDirectory.sol | 163 +++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 src/test/seaport/TypehashDirectory.sol diff --git a/src/test/seaport/TypehashDirectory.sol b/src/test/seaport/TypehashDirectory.sol new file mode 100644 index 000000000..31053aaa7 --- /dev/null +++ b/src/test/seaport/TypehashDirectory.sol @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import { FreeMemoryPointerSlot, OneWord, OneWordShift, ThirtyOneBytes } from "seaport-types/src/lib/ConsiderationConstants.sol"; + +/** + * @title TypehashDirectory + * @notice The typehash directory contains 24 bulk order EIP-712 typehashes, + * depending on the height of the tree in each bulk order payload, as + * its runtime code (with an invalid opcode prefix so that the contract + * cannot be called normally). This runtime code is designed to be read + * from by Seaport using `extcodecopy` while verifying bulk signatures. + */ +contract TypehashDirectory { + // Encodes "[2]" for use in deriving typehashes. + bytes3 internal constant twoSubstring = 0x5B325D; + uint256 internal constant twoSubstringLength = 0x3; + + // Dictates maximum bulk order group size; 24 => 2^24 => 16,777,216 orders. + uint256 internal constant MaxTreeHeight = 0x18; + + uint256 internal constant InvalidOpcode = 0xfe; + + /** + * @dev Derive 24 bulk order EIP-712 typehashes, one for each supported + * tree height from 1 to 24, and write them to runtime code. + */ + constructor() { + // Declare an array where each type hash will be written. + bytes32[] memory typeHashes = new bytes32[](MaxTreeHeight); + + // Derive a string of 24 "[2]" substrings. + bytes memory brackets = getMaxTreeBrackets(MaxTreeHeight); + + // Derive a string of subtypes for the order parameters. + bytes memory subTypes = getTreeSubTypes(); + + // Cache memory pointer before each loop so memory doesn't expand by the + // full string size on each loop. + uint256 freeMemoryPointer; + assembly { + freeMemoryPointer := mload(FreeMemoryPointerSlot) + } + + // Iterate over each tree height. + for (uint256 i = 0; i < MaxTreeHeight; ) { + // The actual height is one greater than its respective index. + uint256 height = i + 1; + + // Slice brackets length to size needed for `height`. + assembly { + mstore(brackets, mul(twoSubstringLength, height)) + } + + // Encode the type string for the BulkOrder struct. + bytes memory bulkOrderTypeString = bytes.concat("BulkOrder(OrderComponents", brackets, " tree)", subTypes); + + // Derive EIP712 type hash. + bytes32 typeHash = keccak256(bulkOrderTypeString); + typeHashes[i] = typeHash; + + // Reset the free memory pointer. + assembly { + mstore(FreeMemoryPointerSlot, freeMemoryPointer) + } + + unchecked { + ++i; + } + } + + assembly { + // Overwrite length with zero to give the contract an INVALID prefix + // and deploy the type hashes array as a contract. + mstore(typeHashes, InvalidOpcode) + + return(add(typeHashes, ThirtyOneBytes), add(shl(OneWordShift, MaxTreeHeight), 1)) + } + } + + /** + * @dev Internal pure function that returns a string of "[2]" substrings, + * with a number of substrings equal to the provided height. + * + * @param maxHeight The number of "[2]" substrings to include. + * + * @return A bytes array representing the string. + */ + function getMaxTreeBrackets(uint256 maxHeight) internal pure returns (bytes memory) { + bytes memory suffixes = new bytes(twoSubstringLength * maxHeight); + assembly { + // Retrieve the pointer to the array head. + let ptr := add(suffixes, OneWord) + + // Derive the terminal pointer. + let endPtr := add(ptr, mul(maxHeight, twoSubstringLength)) + + // Iterate over each pointer until terminal pointer is reached. + for { + + } lt(ptr, endPtr) { + ptr := add(ptr, twoSubstringLength) + } { + // Insert "[2]" substring directly at current pointer location. + mstore(ptr, twoSubstring) + } + } + + // Return the fully populated array of substrings. + return suffixes; + } + + /** + * @dev Internal pure function that returns a string of subtypes used in + * generating bulk order EIP-712 typehashes. + * + * @return A bytes array representing the string. + */ + function getTreeSubTypes() internal pure returns (bytes memory) { + // Construct the OfferItem type string. + bytes memory offerItemTypeString = bytes( + "OfferItem(" + "uint8 itemType," + "address token," + "uint256 identifierOrCriteria," + "uint256 startAmount," + "uint256 endAmount" + ")" + ); + + // Construct the ConsiderationItem type string. + bytes memory considerationItemTypeString = bytes( + "ConsiderationItem(" + "uint8 itemType," + "address token," + "uint256 identifierOrCriteria," + "uint256 startAmount," + "uint256 endAmount," + "address recipient" + ")" + ); + + // Construct the OrderComponents type string, not including the above. + bytes memory orderComponentsPartialTypeString = bytes( + "OrderComponents(" + "address offerer," + "address zone," + "OfferItem[] offer," + "ConsiderationItem[] consideration," + "uint8 orderType," + "uint256 startTime," + "uint256 endTime," + "bytes32 zoneHash," + "uint256 salt," + "bytes32 conduitKey," + "uint256 counter" + ")" + ); + + // Return the combined string. + return bytes.concat(considerationItemTypeString, offerItemTypeString, orderComponentsPartialTypeString); + } +} From 2c389e670769341fef268295fa4974eb8b71e182 Mon Sep 17 00:00:00 2001 From: Krishang Date: Thu, 22 Feb 2024 17:17:02 +0530 Subject: [PATCH 03/12] WORKING SOLUTION: Account.isValidSignature supports Seaport bulk order sigs --- .../account/non-upgradeable/Account.sol | 25 +++- lib/seaport-core | 2 +- src/test/seaport/AccountBulkOrderSig.t.sol | 19 ++- src/test/seaport/EIP712MerkleTree.sol | 114 ++++-------------- 4 files changed, 60 insertions(+), 100 deletions(-) diff --git a/contracts/prebuilts/account/non-upgradeable/Account.sol b/contracts/prebuilts/account/non-upgradeable/Account.sol index adc4bb3e3..0c0ba1582 100644 --- a/contracts/prebuilts/account/non-upgradeable/Account.sol +++ b/contracts/prebuilts/account/non-upgradeable/Account.sol @@ -67,8 +67,29 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115 bytes32 _message, bytes memory _signature ) public view virtual override returns (bytes4 magicValue) { - bytes32 messageHash = getMessageHash(abi.encode(_message)); - address signer = messageHash.recover(_signature); + bytes32 digest; + bytes memory targetSig; + + // Handle OpenSea bulk order signatures that are >65 bytes in length. + if (_signature.length > 65) { + // We decode the received bytes data into: + // 1. abi encode-packed signature + // 2. target digest that was signed to produce the signature + (bytes memory extractedPackedSig, bytes32 bulkOrderDigest) = abi.decode(_signature, (bytes, bytes32)); + + // Use the modified digest built for bulk orders + digest = bulkOrderDigest; + + // Extract the signature, which is the first 65 bytes + targetSig = new bytes(65); + for (uint i = 0; i < 65; i++) { + targetSig[i] = extractedPackedSig[i]; + } + } else { + digest = getMessageHash(abi.encode(_message)); + } + + address signer = digest.recover(targetSig); if (isAdmin(signer)) { return MAGICVALUE; diff --git a/lib/seaport-core b/lib/seaport-core index d4e8c74ad..c17f6a8b2 160000 --- a/lib/seaport-core +++ b/lib/seaport-core @@ -1 +1 @@ -Subproject commit d4e8c74adc472b311ab64b5c9f9757b5bba57a15 +Subproject commit c17f6a8b238fa3b4d23e28a4a72efad4baeafb5d diff --git a/src/test/seaport/AccountBulkOrderSig.t.sol b/src/test/seaport/AccountBulkOrderSig.t.sol index 184e0765e..895dfd531 100644 --- a/src/test/seaport/AccountBulkOrderSig.t.sol +++ b/src/test/seaport/AccountBulkOrderSig.t.sol @@ -196,7 +196,7 @@ contract AccountBulkOrderSigTest is BaseTest { // The other order components can remain empty. EIP712MerkleTree merkleTree = new EIP712MerkleTree(); - bytes memory bulkSignature = merkleTree.signBulkOrder( + (bytes memory packedSignature, bytes32 digest) = merkleTree.signBulkOrder( ConsiderationInterface(address(seaport)), accountAdminPKey, orderComponents, @@ -204,10 +204,21 @@ contract AccountBulkOrderSigTest is BaseTest { false ); - Order memory order = Order({ parameters: baseOrderParameters, signature: bulkSignature }); + Order memory order = Order({ parameters: baseOrderParameters, signature: abi.encode(packedSignature, digest) }); - assertEq(bulkSignature.length, 132); - vm.expectRevert("ECDSA: invalid signature length"); + assertEq(packedSignature.length, 132); + // vm.expectRevert("ECDSA: invalid signature length"); + // 0x882f38f087adb31c0a3f7b96bec402664a3e52b748dbf635ecaa5f719df04ec81fd442cdaae162d152c21f866f5b09e097f561f7db6d1020b0a8c72c3ff36fb41c + // 0x882f38f087adb31c0a3f7b96bec402664a3e52b748dbf635ecaa5f719df04ec81fd442cdaae162d152c21f866f5b09e097f561f7db6d1020b0a8c72c3ff36fb41c + // 0x882f38f087adb31c0a3f7b96bec402664a3e52b748dbf635ecaa5f719df04ec81fd442cdaae162d152c21f866f5b09e097f561f7db6d1020b0a8c72c3ff36fb41c00000006bfdd4fee487c47799fd9aa57225e03268298d2983ff74cbab178665fab33ead34b12e74ee846c338466455cad0c77d7d37d1f8072d72ed279c9c9e7f80a2b5 + + // 0x988496fb495acac726f98c32c7d74b1389f7c8cb18fa0be785e9cc5826d5fe57 + // 0x988496fb495acac726f98c32c7d74b1389f7c8cb18fa0be785e9cc5826d5fe57 -- digest + // 0x26fba4b6e6131cf86f3aa79d8968d0152ee9171a95c60fecd5b5a2aa1158a4ff -- originalDigest + + // 0x376ca148aa5b65f07b5dc48dac6cc1957266d972912bca47163071c7eca58725 -- bulkOrderHash in EIP712MerkleTree.sol + // 0xc2bbd323938bf2d6e379be48b82c7a8fe220c804b7fe1160f5f1621fe3e9eabb -- order hash + // 0x376ca148aa5b65f07b5dc48dac6cc1957266d972912bca47163071c7eca58725 -- order hash modified seaport.fulfillOrder{ value: 1 }(order, bytes32(0)); } } diff --git a/src/test/seaport/EIP712MerkleTree.sol b/src/test/seaport/EIP712MerkleTree.sol index d697196fa..6eb43e6c7 100644 --- a/src/test/seaport/EIP712MerkleTree.sol +++ b/src/test/seaport/EIP712MerkleTree.sol @@ -50,7 +50,7 @@ contract EIP712MerkleTree is Test { OrderComponents[] memory orderComponents, uint24 orderIndex, bool useCompact2098 - ) public view returns (bytes memory) { + ) public view returns (bytes memory packedSignature, bytes32 bulkOrderHash) { // cache the hash of an empty order components struct to fill out any // nodes required to make the length a power of 2 bytes32 emptyComponentsHash = consideration.getOrderHash(emptyOrderComponents); @@ -85,88 +85,15 @@ contract EIP712MerkleTree is Test { bytes32[] memory proof = merkle.getProof(leaves, orderIndex); bytes32 root = merkle.getRoot(leaves); - return _getSignature(consideration, privateKey, bulkOrderTypehash, root, proof, orderIndex, useCompact2098); - } - - /** - * @dev Creates a single bulk signature: a base signature + a three byte - * index + a series of 32 byte proofs. The height of the tree is determined - * by the height parameter and this function will fill empty orders into the - * tree until the specified height is reached. - */ - function signSparseBulkOrder( - SeaportInterface consideration, - uint256 privateKey, - OrderComponents memory orderComponents, - uint256 height, - uint24 orderIndex, - bool useCompact2098 - ) public view returns (bytes memory) { - require(orderIndex < 2 ** height, "orderIndex out of bounds"); - // get hash of actual order - bytes32 orderHash = consideration.getOrderHash(orderComponents); - // get initial empty order components hash - bytes32 emptyComponentsHash = consideration.getOrderHash(emptyOrderComponents); - - // calculate intermediate hashes of a sparse order tree - // this will also serve as our proof - bytes32[] memory emptyHashes = new bytes32[]((height)); - // first layer is empty order hash - emptyHashes[0] = emptyComponentsHash; - for (uint256 i = 1; i < height; i++) { - bytes32 nextHash; - bytes32 lastHash = emptyHashes[i - 1]; - // subsequent layers are hash of emptyHeight+emptyHeight - assembly { - mstore(0, lastHash) - mstore(0x20, lastHash) - nextHash := keccak256(0, 0x40) - } - emptyHashes[i] = nextHash; - } - // begin calculating order tree root - bytes32 root = orderHash; - // hashIndex is the index within the layer of the non-sparse hash - uint24 hashIndex = orderIndex; - - for (uint256 i = 0; i < height; i++) { - // get sparse hash at this height - bytes32 heightEmptyHash = emptyHashes[i]; - assembly { - // if the hashIndex is odd, our "root" is second component - if and(hashIndex, 1) { - mstore(0, heightEmptyHash) - mstore(0x20, root) - } - // else it is even and our "root" is first component - // (this can def be done in a branchless way but who has the - // time??) - if iszero(and(hashIndex, 1)) { - mstore(0, root) - mstore(0x20, heightEmptyHash) - } - // compute new intermediate hash (or final root) - root := keccak256(0, 0x40) - } - // divide hashIndex by 2 to get index of next layer - // 0 -> 0 - // 1 -> 0 - // 2 -> 1 - // 3 -> 1 - // etc - hashIndex /= 2; - } - - return - _getSignature( - consideration, - privateKey, - _lookupBulkOrderTypehash(height), - root, - emptyHashes, - orderIndex, - useCompact2098 - ); + (packedSignature, bulkOrderHash) = _getSignature( + consideration, + privateKey, + bulkOrderTypehash, + root, + proof, + orderIndex, + useCompact2098 + ); } /** @@ -189,22 +116,23 @@ contract EIP712MerkleTree is Test { bytes32[] memory proof, uint24 orderIndex, bool useCompact2098 - ) internal view returns (bytes memory) { - // bulkOrder hash is keccak256 of the specific bulk order typehash and - // the merkle root of the order hashes - bytes32 bulkOrderHash = keccak256(abi.encode(bulkOrderTypehash, root)); - + ) internal view returns (bytes memory, bytes32) { // get domain separator from the particular seaport instance (, bytes32 domainSeparator, ) = consideration.information(); // declare out here to avoid stack too deep errors bytes memory signature; // avoid stacc 2 thicc + + // bulkOrder hash is keccak256 of the specific bulk order typehash and + // the merkle root of the order hashes + // bytes32 bulkOrderHash = keccak256(abi.encode(bulkOrderTypehash, root)); + bytes32 digest = keccak256( + abi.encodePacked(bytes2(0x1901), domainSeparator, keccak256(abi.encode(bulkOrderTypehash, root))) + ); + { - (uint8 v, bytes32 r, bytes32 s) = vm.sign( - privateKey, - keccak256(abi.encodePacked(bytes2(0x1901), domainSeparator, bulkOrderHash)) - ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); // if useCompact2098 is true, encode yParity (v) into s if (useCompact2098) { uint256 yParity = (v == 27) ? 0 : 1; @@ -221,6 +149,6 @@ contract EIP712MerkleTree is Test { // orderIndex will be the next 3 bytes // then proof will be each element one after another; its offset and // length will not be encoded - return abi.encodePacked(signature, orderIndex, proof); + return (abi.encodePacked(signature, orderIndex, proof), digest); } } From 8bde8ab3a9d80ce4a9b27a89b1a235c35d81cf38 Mon Sep 17 00:00:00 2001 From: Krishang Date: Thu, 22 Feb 2024 17:51:44 +0530 Subject: [PATCH 04/12] fix compilation and tests --- contracts/prebuilts/account/non-upgradeable/Account.sol | 1 + lib/seaport-core | 2 +- src/test/smart-wallet/utils/AABenchmarkArtifacts.sol | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/contracts/prebuilts/account/non-upgradeable/Account.sol b/contracts/prebuilts/account/non-upgradeable/Account.sol index 0c0ba1582..b8579bfae 100644 --- a/contracts/prebuilts/account/non-upgradeable/Account.sol +++ b/contracts/prebuilts/account/non-upgradeable/Account.sol @@ -87,6 +87,7 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115 } } else { digest = getMessageHash(abi.encode(_message)); + targetSig = _signature; } address signer = digest.recover(targetSig); diff --git a/lib/seaport-core b/lib/seaport-core index c17f6a8b2..d4e8c74ad 160000 --- a/lib/seaport-core +++ b/lib/seaport-core @@ -1 +1 @@ -Subproject commit c17f6a8b238fa3b4d23e28a4a72efad4baeafb5d +Subproject commit d4e8c74adc472b311ab64b5c9f9757b5bba57a15 diff --git a/src/test/smart-wallet/utils/AABenchmarkArtifacts.sol b/src/test/smart-wallet/utils/AABenchmarkArtifacts.sol index 2897e9129..6fa69d620 100644 --- a/src/test/smart-wallet/utils/AABenchmarkArtifacts.sol +++ b/src/test/smart-wallet/utils/AABenchmarkArtifacts.sol @@ -9,6 +9,6 @@ interface ThirdwebAccount { } address constant THIRDWEB_ACCOUNT_FACTORY_ADDRESS = 0x2e234DAe75C793f67A35089C9d99245E1C58470b; address constant THIRDWEB_ACCOUNT_IMPL_ADDRESS = 0xffD4505B3452Dc22f8473616d50503bA9E1710Ac; -bytes constant THIRDWEB_ACCOUNT_FACTORY_BYTECODE = hex"608060405234801561001057600080fd5b50600436106101285760003560e01c806308e93d0a1461012d5780630b61e12b1461014b5780630e6254fd1461016057806311464fbe14610173578063248a9ca3146101b25780632f2ff15d146101d357806336568abe146101e657806358451f97146101f957806383a03f8c146102015780638878ed33146102145780639010d07c1461022757806391d148541461023a5780639387a3801461025d578063938e3d7b14610270578063a217fddf14610283578063a32fa5b31461028b578063a65d69d41461029e578063ac9650d8146102c5578063c3c5a547146102e5578063ca15c873146102f8578063d547741f1461030b578063d8fd8f441461031e578063e68a7c3b14610331578063e8a3d48514610344575b600080fd5b610135610359565b6040516101429190611945565b60405180910390f35b61015e6101593660046119ae565b61036a565b005b61013561016e3660046119d8565b61040b565b61019a7f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac81565b6040516001600160a01b039091168152602001610142565b6101c56101c03660046119f3565b610435565b604051908152602001610142565b61015e6101e1366004611a0c565b610453565b61015e6101f4366004611a0c565b6104fd565b6101c561055c565b61015e61020f3660046119f3565b610568565b61019a610222366004611a38565b6105b6565b61019a610235366004611aba565b610630565b61024d610248366004611a0c565b61073e565b6040519015158152602001610142565b61015e61026b3660046119ae565b610772565b61015e61027e366004611af2565b610809565b6101c5600081565b61024d610299366004611a0c565b61085a565b61019a7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278981565b6102d86102d3366004611ba2565b6108bd565b6040516101429190611c66565b61024d6102f33660046119d8565b610a19565b6101c56103063660046119f3565b610a25565b61015e610319366004611a0c565b610ac2565b61019a61032c366004611a38565b610acd565b61013561033f366004611aba565b610c18565b61034c610d49565b6040516101429190611cca565b60606103656000610de1565b905090565b336103758183610dee565b61039a5760405162461bcd60e51b815260040161039190611cdd565b60405180910390fd5b6001600160a01b03831660009081526002602052604081206103bc9083610e32565b9050801561040557836001600160a01b0316826001600160a01b03167f12146497b3b826918ec47f0cac7272a09ed06b30c16c030e99ec48ff5dd60b4760405160405180910390a35b50505050565b6001600160a01b038116600090815260026020526040902060609061042f90610de1565b92915050565b600061043f610e47565b600092835260010160205250604090205490565b61047761045e610e47565b6000848152600191909101602052604090205433610e6b565b61047f610e47565b6000838152602091825260408082206001600160a01b0385168352909252205460ff16156104ef5760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610391565b6104f98282610ef0565b5050565b336001600160a01b038216146105525760405162461bcd60e51b815260206004820152601a60248201527921b0b71037b7363c903932b737bab731b2903337b91039b2b63360311b6044820152606401610391565b6104f98282610f04565b60006103656000610f18565b336105738183610dee565b61058f5760405162461bcd60e51b815260040161039190611cdd565b61059a600082610e32565b6104f95760405162461bcd60e51b815260040161039190611d14565b6000806105f98585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f2292505050565b90506106257f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac82610f55565b9150505b9392505050565b60008061063b610fb5565b600085815260209190915260408120549150805b82811015610735576000610661610fb5565b60008881526020918252604080822085835260010190925220546001600160a01b0316146106d9578482036106c757610698610fb5565b600087815260209182526040808220938252600190930190915220546001600160a01b0316925061042f915050565b6106d2600183611d74565b9150610723565b6106e486600061073e565b801561071057506106f3610fb5565b600087815260209182526040808220828052600201909252205481145b1561072357610720600183611d74565b91505b61072e600182611d74565b905061064f565b50505092915050565b6000610748610e47565b6000938452602090815260408085206001600160a01b039490941685529290525090205460ff1690565b3361077d8183610dee565b6107995760405162461bcd60e51b815260040161039190611cdd565b6001600160a01b03831660009081526002602052604081206107bb9083610fbf565b9050801561040557836001600160a01b0316826001600160a01b03167f98d1ebbe00ae92a5de96a0f49742a8afa89f42363592bc2e7cfaaed68b45e7a660405160405180910390a350505050565b610811610fd4565b61084e5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610391565b61085781610fe0565b50565b6000610864610e47565b600084815260209182526040808220828052909252205460ff166108b45761088a610e47565b6000848152602091825260408082206001600160a01b0386168352909252205460ff16905061042f565b50600192915050565b6060816001600160401b038111156108d7576108d7611adc565b60405190808252806020026020018201604052801561090a57816020015b60608152602001906001900390816108f55790505b509050336000805b848110156107355781156109915761096f3087878481811061093657610936611d87565b90506020028101906109489190611d9d565b8660405160200161095b93929190611dea565b6040516020818303038152906040526110c7565b84828151811061098157610981611d87565b6020026020010181905250610a11565b6109f3308787848181106109a7576109a7611d87565b90506020028101906109b99190611d9d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506110c792505050565b848281518110610a0557610a05611d87565b60200260200101819052505b600101610912565b600061042f81836110ec565b600080610a30610fb5565b6000848152602091909152604081205491505b81811015610a9d576000610a55610fb5565b60008681526020918252604080822085835260010190925220546001600160a01b031614610a8b57610a88600184611d74565b92505b610a96600182611d74565b9050610a43565b50610aa983600061073e565b15610abc57610ab9600183611d74565b91505b50919050565b61055261045e610e47565b6000807f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac90506000610b358686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f2292505050565b90506000610b438383610f55565b90506001600160a01b0381163b15610b5f579250610629915050565b610b69838361110e565b9050336001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27891614610bc257610ba6600082610e32565b610bc25760405162461bcd60e51b815260040161039190611d14565b610bce818888886111a5565b866001600160a01b0316816001600160a01b03167fac631f3001b55ea1509cf3d7e74898f85392a61a76e8149181ae1259622dabc860405160405180910390a39695505050505050565b60608183108015610c325750610c2e6000610f18565b8211155b610c8a5760405162461bcd60e51b815260206004820152602360248201527f426173654163636f756e74466163746f72793a20696e76616c696420696e646960448201526263657360e81b6064820152608401610391565b6000610c968484611e0b565b9050610ca28484611e0b565b6001600160401b03811115610cb957610cb9611adc565b604051908082528060200260200182016040528015610ce2578160200160208202803683370190505b50915060005b81811015610d4157610d05610cfd8683611d74565b60009061120d565b838281518110610d1757610d17611d87565b6001600160a01b0390921660209283029190910190910152610d3a600182611d74565b9050610ce8565b505092915050565b6060610d53611219565b8054610d5e90611e1e565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8a90611e1e565b8015610dd75780601f10610dac57610100808354040283529160200191610dd7565b820191906000526020600020905b815481529060010190602001808311610dba57829003601f168201915b5050505050905090565b606060006106298361123d565b600080610e1b7f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac84610f55565b6001600160a01b0385811691161491505092915050565b6000610629836001600160a01b038416611299565b7f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e50090565b610e73610e47565b6000838152602091825260408082206001600160a01b0385168352909252205460ff166104f957610eae816001600160a01b031660146112e8565b610eb98360206112e8565b604051602001610eca929190611e52565b60408051601f198184030181529082905262461bcd60e51b825261039191600401611cca565b610efa8282611483565b6104f982826114ec565b610f0e82826115ab565b6104f98282611614565b600061042f825490565b60008282604051602001610f37929190611ebf565b60405160208183030381529060405280519060200120905092915050565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c82012060788201526055604390910120600090610629565b60006103656116a3565b6000610629836001600160a01b038416611705565b6000610365813361073e565b6000610fea611219565b8054610ff590611e1e565b80601f016020809104026020016040519081016040528092919081815260200182805461102190611e1e565b801561106e5780601f106110435761010080835404028352916020019161106e565b820191906000526020600020905b81548152906001019060200180831161105157829003601f168201915b505050505090508161107e611219565b906110899082611f34565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a1681836040516110bb929190611ff3565b60405180910390a15050565b606061062983836040518060600160405280602781526020016120b9602791396117f8565b6001600160a01b03811660009081526001830160205260408120541515610629565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661042f5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610391565b60405163347d5e2560e21b81526001600160a01b0385169063d1f57894906111d590869086908690600401612018565b600060405180830381600087803b1580156111ef57600080fd5b505af1158015611203573d6000803e3d6000fd5b5050505050505050565b60006106298383611870565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b60608160000180548060200260200160405190810160405280929190818152602001828054801561128d57602002820191906000526020600020905b815481526020019060010190808311611279575b50505050509050919050565b60008181526001830160205260408120546112e05750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561042f565b50600061042f565b606060006112f7836002612058565b611302906002611d74565b6001600160401b0381111561131957611319611adc565b6040519080825280601f01601f191660200182016040528015611343576020820181803683370190505b509050600360fc1b8160008151811061135e5761135e611d87565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061138d5761138d611d87565b60200101906001600160f81b031916908160001a90535060006113b1846002612058565b6113bc906001611d74565b90505b6001811115611434576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106113f0576113f0611d87565b1a60f81b82828151811061140657611406611d87565b60200101906001600160f81b031916908160001a90535060049490941c9361142d8161206f565b90506113bf565b5083156106295760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610391565b600161148d610e47565b6000848152602091825260408082206001600160a01b0386168084529352808220805460ff1916941515949094179093559151339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60006114f6610fb5565b6000848152602091909152604090205490506001611512610fb5565b6000858152602091909152604081208054909190611531908490611d74565b90915550829050611540610fb5565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b039290921691909117905580611580610fb5565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b6115b58282610e6b565b6115bd610e47565b6000838152602091825260408082206001600160a01b0385168084529352808220805460ff191690555133929185917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600061161e610fb5565b6000848152602091825260408082206001600160a01b03861683526002019092522054905061164b610fb5565b6000848152602091825260408082208483526001019092522080546001600160a01b031916905561167a610fb5565b6000938452602090815260408085206001600160a01b0390941685526002909301905250812055565b60008060ff196116d460017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c611e0b565b6040516020016116e691815260200190565b60408051601f1981840301815291905280516020909101201692915050565b600081815260018301602052604081205480156117ee576000611729600183611e0b565b855490915060009061173d90600190611e0b565b90508181146117a257600086600001828154811061175d5761175d611d87565b906000526020600020015490508087600001848154811061178057611780611d87565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117b3576117b3612086565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061042f565b600091505061042f565b6060600080856001600160a01b031685604051611815919061209c565b600060405180830381855af49150503d8060008114611850576040519150601f19603f3d011682016040523d82523d6000602084013e611855565b606091505b50915091506118668683838761189a565b9695505050505050565b600082600001828154811061188757611887611d87565b9060005260206000200154905092915050565b60608315611909578251600003611902576001600160a01b0385163b6119025760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610391565b5081611913565b611913838361191b565b949350505050565b81511561192b5781518083602001fd5b8060405162461bcd60e51b81526004016103919190611cca565b6020808252825182820181905260009190848201906040850190845b818110156119865783516001600160a01b031683529284019291840191600101611961565b50909695505050505050565b80356001600160a01b03811681146119a957600080fd5b919050565b600080604083850312156119c157600080fd5b6119ca83611992565b946020939093013593505050565b6000602082840312156119ea57600080fd5b61062982611992565b600060208284031215611a0557600080fd5b5035919050565b60008060408385031215611a1f57600080fd5b82359150611a2f60208401611992565b90509250929050565b600080600060408486031215611a4d57600080fd5b611a5684611992565b925060208401356001600160401b0380821115611a7257600080fd5b818601915086601f830112611a8657600080fd5b813581811115611a9557600080fd5b876020828501011115611aa757600080fd5b6020830194508093505050509250925092565b60008060408385031215611acd57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b600060208284031215611b0457600080fd5b81356001600160401b0380821115611b1b57600080fd5b818401915084601f830112611b2f57600080fd5b813581811115611b4157611b41611adc565b604051601f8201601f19908116603f01168101908382118183101715611b6957611b69611adc565b81604052828152876020848701011115611b8257600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060208385031215611bb557600080fd5b82356001600160401b0380821115611bcc57600080fd5b818501915085601f830112611be057600080fd5b813581811115611bef57600080fd5b8660208260051b8501011115611c0457600080fd5b60209290920196919550909350505050565b60005b83811015611c31578181015183820152602001611c19565b50506000910152565b60008151808452611c52816020860160208601611c16565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015611cbd57603f19888603018452611cab858351611c3a565b94509285019290850190600101611c8f565b5092979650505050505050565b6020815260006106296020830184611c3a565b6020808252601f908201527f4163636f756e74466163746f72793a206e6f7420616e206163636f756e742e00604082015260600190565b6020808252602a908201527f4163636f756e74466163746f72793a206163636f756e7420616c7265616479206040820152691c9959da5cdd195c995960b21b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561042f5761042f611d5e565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112611db457600080fd5b8301803591506001600160401b03821115611dce57600080fd5b602001915036819003821315611de357600080fd5b9250929050565b8284823760609190911b6001600160601b0319169101908152601401919050565b8181038181111561042f5761042f611d5e565b600181811c90821680611e3257607f821691505b602082108103610abc57634e487b7160e01b600052602260045260246000fd5b7402832b936b4b9b9b4b7b7399d1030b1b1b7bab73a1605d1b815260008351611e82816015850160208801611c16565b7001034b99036b4b9b9b4b733903937b6329607d1b6015918401918201528351611eb3816026840160208801611c16565b01602601949350505050565b6001600160a01b038316815260406020820181905260009061191390830184611c3a565b601f821115611f2f576000816000526020600020601f850160051c81016020861015611f0c5750805b601f850160051c820191505b81811015611f2b57828155600101611f18565b5050505b505050565b81516001600160401b03811115611f4d57611f4d611adc565b611f6181611f5b8454611e1e565b84611ee3565b602080601f831160018114611f965760008415611f7e5750858301515b600019600386901b1c1916600185901b178555611f2b565b600085815260208120601f198616915b82811015611fc557888601518255948401946001909101908401611fa6565b5085821015611fe35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6040815260006120066040830185611c3a565b82810360208401526106258185611c3a565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761042f5761042f611d5e565b60008161207e5761207e611d5e565b506000190190565b634e487b7160e01b600052603160045260246000fd5b600082516120ae818460208701611c16565b919091019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220a61135b53685bb0ed196dd5ad4d75bcd9d18cbd5f1c400b41cef4e22728763e164736f6c63430008170033"; -bytes constant THIRDWEB_ACCOUNT_IMPL_BYTECODE = hex"60806040526004361061014b5760003560e01c806301ffc9a7146101575780630a1028c41461018c578063150b7a02146101ba5780631626ba7e146101f35780631dd756c51461021357806324d7806c146102335780633a871cdd1461025357806347e1da2a146102735780634a58db19146102955780634d44560d1461029d5780635892e236146102bd5780637dff5a79146102dd5780638b52d723146102fd578063938e3d7b1461031f578063a9082d841461033f578063ac9650d81461037e578063b0d691fe146103ab578063b61d27f6146103cd578063b76464d5146103ed578063bc197c811461040d578063c45a015514610439578063d087d2881461046d578063d1f5789414610482578063d42f2f35146104a2578063e8a3d485146104b7578063e9523c97146104d9578063f15d424e146104fb578063f23a6e611461052857600080fd5b3661015257005b600080fd5b34801561016357600080fd5b50610177610172366004612d91565b610554565b60405190151581526020015b60405180910390f35b34801561019857600080fd5b506101ac6101a7366004612e78565b61059a565b604051908152602001610183565b3480156101c657600080fd5b506101da6101d5366004612ed1565b61063e565b6040516001600160e01b03199091168152602001610183565b3480156101ff57600080fd5b506101da61020e366004612f3c565b61064f565b34801561021f57600080fd5b5061017761022e366004612f9b565b61078f565b34801561023f57600080fd5b5061017761024e366004612fe0565b610a53565b34801561025f57600080fd5b506101ac61026e366004612ffd565b610a82565b34801561027f57600080fd5b5061029361028e36600461308e565b610aa8565b005b610293610c0f565b3480156102a957600080fd5b506102936102b8366004613127565b610c77565b3480156102c957600080fd5b506102936102d8366004613194565b610cea565b3480156102e957600080fd5b506101776102f8366004612fe0565b6110a7565b34801561030957600080fd5b50610312611160565b60405161018391906132a7565b34801561032b57600080fd5b5061029361033a36600461330b565b6113a7565b34801561034b57600080fd5b5061035f61035a366004613194565b6113f8565b6040805192151583526001600160a01b03909116602083015201610183565b34801561038a57600080fd5b5061039e610399366004613353565b61144f565b60405161018391906133e4565b3480156103b757600080fd5b506103c06115b4565b604051610183919061343b565b3480156103d957600080fd5b506102936103e836600461344f565b6115fd565b3480156103f957600080fd5b50610293610408366004612fe0565b61168d565b34801561041957600080fd5b506101da61042836600461353c565b63bc197c8160e01b95945050505050565b34801561044557600080fd5b506103c07f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b81565b34801561047957600080fd5b506101ac6116bf565b34801561048e57600080fd5b5061029361049d3660046135e9565b61173f565b3480156104ae57600080fd5b506103126118f7565b3480156104c357600080fd5b506104cc611a68565b6040516101839190613630565b3480156104e557600080fd5b506104ee611b00565b6040516101839190613643565b34801561050757600080fd5b5061051b610516366004612fe0565b611b12565b6040516101839190613690565b34801561053457600080fd5b506101da6105433660046136a3565b63f23a6e6160e01b95945050505050565b60006001600160e01b03198216630271189760e51b148061058557506001600160e01b03198216630a85bd0160e11b145b80610594575061059482611bea565b92915050565b6000807f82cac545155fcbf147f2a9013809613677ac7d65498556e6d19ce43bcbf6c28483805190602001206040516020016105e0929190918252602082015260400190565b604051602081830303815290604052805190602001209050610600611c1f565b60405161190160f01b602082015260228101919091526042810182905260620160405160208183030381529060405280519060200120915050919050565b630a85bd0160e11b5b949350505050565b60008061067c8460405160200161066891815260200190565b60405160208183030381529060405261059a565b9050600061068a8285611d46565b905061069581610a53565b156106ac5750630b135d3f60e11b91506105949050565b3360006106b7611d6a565b6001600160a01b03841660009081526006919091016020526040902090506106df8183611d8e565b8061070f57506106ee81611db0565b600114801561070f575060006107048282611dba565b6001600160a01b0316145b61076c5760405162461bcd60e51b8152602060048201526024808201527f4163636f756e743a2063616c6c6572206e6f7420617070726f7665642074617260448201526333b2ba1760e11b60648201526084015b60405180910390fd5b610775836110a7565b1561078557630b135d3f60e11b94505b5050505092915050565b6000610799611d6a565b6001600160a01b0384166000908152600491909101602052604090205460ff16156107c657506001610594565b60006107d0611d6a565b6001600160a01b0385166000908152600591909101602090815260408083208151606081018352815481526001909101546001600160801b0380821694830194909452600160801b900490921690820152915061082b611d6a565b6006016000866001600160a01b03166001600160a01b0316815260200190815260200160002090504282602001516001600160801b0316118061087b575081604001516001600160801b03164210155b8061088c575061088a81611db0565b155b1561089c57600092505050610594565b60006108b36108ae606087018761370b565b611dc6565b905060006108c083611db0565b60011480156108e1575060006108d68482611dba565b6001600160a01b0316145b90506324f16c0560e11b6001600160e01b03198316016109585760008061091361090e60608a018a61370b565b611e00565b9150915082610939576109268583611d8e565b6109395760009650505050505050610594565b85518111156109515760009650505050505050610594565b5050610a46565b635c0f12eb60e11b6001600160e01b0319831601610a395760008061098861098360608a018a61370b565b611e65565b5091509150826109e85760005b82518110156109e6576109ca8382815181106109b3576109b3613751565b602002602001015187611d8e90919063ffffffff16565b6109de576000975050505050505050610594565b600101610995565b505b60005b8251811015610a3157818181518110610a0657610a06613751565b602002602001015187600001511015610a29576000975050505050505050610594565b6001016109eb565b505050610a46565b6000945050505050610594565b5060019695505050505050565b6000610a5d611d6a565b6001600160a01b03909216600090815260049290920160205250604090205460ff1690565b6000610a8c611eb2565b610a968484611f1b565b9050610aa182612060565b9392505050565b610ab06115b4565b6001600160a01b0316336001600160a01b03161480610ad35750610ad333610a53565b610aef5760405162461bcd60e51b815260040161076390613767565b610af76120ad565b8481148015610b0557508483145b610b515760405162461bcd60e51b815260206004820152601d60248201527f4163636f756e743a2077726f6e67206172726179206c656e677468732e0000006044820152606401610763565b60005b85811015610c0657610bfd878783818110610b7157610b71613751565b9050602002016020810190610b869190612fe0565b868684818110610b9857610b98613751565b90506020020135858585818110610bb157610bb1613751565b9050602002810190610bc3919061370b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061219392505050565b50600101610b54565b50505050505050565b610c176115b4565b6001600160a01b031663b760faf934306040518363ffffffff1660e01b8152600401610c43919061343b565b6000604051808303818588803b158015610c5c57600080fd5b505af1158015610c70573d6000803e3d6000fd5b5050505050565b610c7f612204565b610c876115b4565b6001600160a01b031663205c287883836040518363ffffffff1660e01b8152600401610cb49291906137a8565b600060405180830381600087803b158015610cce57600080fd5b505af1158015610ce2573d6000803e3d6000fd5b505050505050565b6000610cf96020850185612fe0565b905042610d0c60e0860160c087016137d8565b6001600160801b031611158015610d3b5750610d2f610100850160e086016137d8565b6001600160801b031642105b610d715760405162461bcd60e51b8152602060048201526007602482015266085c195c9a5bd960ca1b6044820152606401610763565b600080610d7f8686866113f8565b9150915081610db95760405162461bcd60e51b8152600401610763906020808252600490820152632173696760e01b604082015260600190565b6001610dc3611d6a565b610100880135600090815260079190910160209081526040808320805460ff1916941515949094179093559091610dff91908901908901613804565b60ff161115610e2c576000610e1a6040880160208901613804565b60ff166001149050610c068482612242565b610e3583610a53565b15610e6a5760405162461bcd60e51b815260206004820152600560248201526430b236b4b760d91b6044820152606401610763565b610e7f83610e76611d6a565b60020190612317565b50604051806060016040528087606001358152602001876080016020810190610ea891906137d8565b6001600160801b03168152602001610ec660c0890160a08a016137d8565b6001600160801b03169052610ed9611d6a565b6001600160a01b03851660009081526005919091016020908152604080832084518155918401519301516001600160801b03908116600160801b02931692909217600190920191909155610f4f610f2e611d6a565b6001600160a01b03861660009081526006919091016020526040902061232c565b805190915060005b81811015610fb957610fa6838281518110610f7457610f74613751565b6020026020010151610f84611d6a565b6001600160a01b03891660009081526006919091016020526040902090612339565b50610fb2600182613835565b9050610f57565b50610fc76040890189613848565b9050905060005b8181101561104857611035610fe660408b018b613848565b83818110610ff657610ff6613751565b905060200201602081019061100b9190612fe0565b611013611d6a565b6001600160a01b03891660009081526006919091016020526040902090612317565b50611041600182613835565b9050610fce565b506110528861234e565b846001600160a01b0316836001600160a01b03167ff21d10c26e35863a8df291aca54181ee8c4a3bc8e00246c3f7a5a14b69d826a78a6040516110959190613922565b60405180910390a35050505050505050565b6000806110b2611d6a565b6001600160a01b038416600090815260059190910160209081526040918290208251606081018452815481526001909101546001600160801b03808216938301849052600160801b90910416928101929092529091504210801590611123575080604001516001600160801b031642105b8015610aa157506000611158611137611d6a565b6001600160a01b038616600090815260069190910160205260409020611db0565b119392505050565b6060600061117761116f611d6a565b60020161232c565b80519091506000805b82811015611208576111aa84828151811061119d5761119d613751565b60200260200101516110a7565b156111c157816111b981613a0d565b9250506111f6565b60008482815181106111d5576111d5613751565b60200260200101906001600160a01b031690816001600160a01b0316815250505b611201600182613835565b9050611180565b50806001600160401b0381111561122157611221612dbb565b60405190808252806020026020018201604052801561125a57816020015b611247612d47565b81526020019060019003908161123f5790505b5093506000805b8381101561139f5760006001600160a01b031685828151811061128657611286613751565b60200260200101516001600160a01b03161461138d5760008582815181106112b0576112b0613751565b6020026020010151905060006112c4611d6a565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a08101909452918352909250810161132e610f2e611d6a565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b031681525088858061136d90613a0d565b96508151811061137f5761137f613751565b602002602001018190525050505b611398600182613835565b9050611261565b505050505090565b6113af6123e3565b6113ec5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610763565b6113f5816123fb565b50565b60008061140e611407866124e2565b8585612626565b9050611418611d6a565b6101008601356000908152600791909101602052604090205460ff16158015611445575061144581610a53565b9150935093915050565b6060816001600160401b0381111561146957611469612dbb565b60405190808252806020026020018201604052801561149c57816020015b60608152602001906001900390816114875790505b509050336000805b848110156115ab57811561152357611501308787848181106114c8576114c8613751565b90506020028101906114da919061370b565b866040516020016114ed93929190613a26565b604051602081830303815290604052612678565b84828151811061151357611513613751565b60200260200101819052506115a3565b6115853087878481811061153957611539613751565b905060200281019061154b919061370b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061267892505050565b84828151811061159757611597613751565b60200260200101819052505b6001016114a4565b50505092915050565b6000806115bf61269d565b546001600160a01b0316905080156115d657919050565b7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278991505090565b6116056115b4565b6001600160a01b0316336001600160a01b03161480611628575061162833610a53565b6116445760405162461bcd60e51b815260040161076390613767565b61164c6120ad565b610c70848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061219392505050565b611695612204565b8061169e61269d565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60006116c96115b4565b604051631aab3f0d60e11b8152306004820152600060248201526001600160a01b0391909116906335567e1a90604401602060405180830381865afa158015611716573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061173a9190613a47565b905090565b60006117496126c1565b5460ff16905060006117596126c1565b54610100900460ff1690508015808015611776575060018360ff16105b806117955750611785306126e5565b15801561179557508260ff166001145b6117f85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610763565b60016118026126c1565b805460ff191660ff92909216919091179055801561183b5760016118246126c1565b80549115156101000261ff00199092169190911790555b61187b8686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506126f492505050565b61188361269d565b60010181905550611895866001612242565b8015610ce25760006118a56126c1565b80549115156101000261ff0019909216919091179055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6060600061190661116f611d6a565b8051909150806001600160401b0381111561192357611923612dbb565b60405190808252806020026020018201604052801561195c57816020015b611949612d47565b8152602001906001900390816119415790505b50925060005b81811015611a6257600083828151811061197e5761197e613751565b602002602001015190506000611992611d6a565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a0810190945291835290925081016119fc610f2e611d6a565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250868481518110611a4157611a41613751565b60200260200101819052505050600181611a5b9190613835565b9050611962565b50505090565b6060611a72612727565b8054611a7d90613a60565b80601f0160208091040260200160405190810160405280929190818152602001828054611aa990613a60565b8015611af65780601f10611acb57610100808354040283529160200191611af6565b820191906000526020600020905b815481529060010190602001808311611ad957829003601f168201915b5050505050905090565b606061173a611b0d611d6a565b61232c565b611b1a612d47565b6000611b24611d6a565b6001600160a01b038416600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101611baf611b8e611d6a565b6001600160a01b03871660009081526006919091016020526040902061232c565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250915050919050565b60006001600160e01b03198216630271189760e51b148061059457506301ffc9a760e01b6001600160e01b0319831614610594565b6000306001600160a01b037f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac16148015611c7857507f0000000000000000000000000000000000000000000000000000000000007a6946145b15611ca257507fbcdadf6444930a967ffda04923d78c49b3dd65df3ed39abb04a1e3eb1190553790565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527ff0729608244859f656d32ae4cbc6b0367695d68d8e941a28f5e2d33c6d5182dd828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000806000611d55858561274b565b91509150611d6281612790565b509392505050565b7f3181e78fc1b109bc611fd2406150bf06e33faa75f71cba12c3e1fd670f2def0090565b6001600160a01b03811660009081526001830160205260408120541515610aa1565b6000610594825490565b6000610aa183836128d5565b60006004821015611de95760405162461bcd60e51b815260040161076390613a94565b611df7600460008486613ab3565b610aa191613add565b6000806044831015611e245760405162461bcd60e51b815260040161076390613a94565b611e32602460048587613ab3565b810190611e3f9190612fe0565b9150611e4f604460248587613ab3565b810190611e5c9190613b0d565b90509250929050565b606080806064841015611e8a5760405162461bcd60e51b815260040161076390613a94565b611e978460048188613ab3565b810190611ea49190613ba5565b919790965090945092505050565b611eba6115b4565b6001600160a01b0316336001600160a01b031614611f195760405162461bcd60e51b815260206004820152601c60248201527b1858d8dbdd5b9d0e881b9bdd08199c9bdb48115b9d1c9e541bda5b9d60221b6044820152606401610763565b565b7b0ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d05199960211b6000908152601c829052603c81206000611f99611f5c61014087018761370b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611d469050565b9050611fa5818661078f565b611fb457600192505050610594565b6000611fbe611d6a565b6001600160a01b03929092166000908152600590920160209081526040808420815160608082018452825482526001909201546001600160801b0380821683870152600160801b8204908116928501929092528351928301845295825265ffffffffffff8087169483019490945292831691015260d09290921b6001600160d01b03191660a09290921b65ffffffffffff60a01b169190911795945050505050565b80156113f557604051600090339060001990849084818181858888f193505050503d8060008114610c70576040519150601f19603f3d011682016040523d82523d6000602084013e610c70565b60405163c3c5a54760e01b81527f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b906001600160a01b0382169063c3c5a547906120fb90309060040161343b565b602060405180830381865afa158015612118573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213c9190613c8a565b6113f557806001600160a01b03166383a03f8c61215761269d565b600101546040518263ffffffff1660e01b815260040161217991815260200190565b600060405180830381600087803b158015610c5c57600080fd5b60606000846001600160a01b031684846040516121b09190613cac565b60006040518083038185875af1925050503d80600081146121ed576040519150601f19603f3d011682016040523d82523d6000602084013e6121f2565b606091505b509250905080611d6257815160208301fd5b61220d33610a53565b611f195760405162461bcd60e51b815260206004820152600660248201526510b0b236b4b760d11b6044820152606401610763565b61224c82826128ff565b6001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b163b156123135780156122db577f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b6001600160a01b0316630b61e12b836122ba61269d565b600101546040518363ffffffff1660e01b8152600401610cb49291906137a8565b7f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b6001600160a01b0316639387a380836122ba61269d565b5050565b6000610aa1836001600160a01b0384166129ae565b60606000610aa1836129fd565b6000610aa1836001600160a01b038416612a59565b6001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b163b156113f5576001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b16630b61e12b6123ba6020840184612fe0565b6123c261269d565b600101546040518363ffffffff1660e01b81526004016121799291906137a8565b60006123ee33610a53565b8061173a57505030331490565b6000612405612727565b805461241090613a60565b80601f016020809104026020016040519081016040528092919081815260200182805461243c90613a60565b80156124895780601f1061245e57610100808354040283529160200191612489565b820191906000526020600020905b81548152906001019060200180831161246c57829003601f168201915b5050505050905081612499612727565b906124a49082613d15565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a1681836040516124d6929190613dd4565b60405180910390a15050565b60607f3fd4a1a1a267c84185e3b7eecd57c68783c0581d538b9d6e5f23e4670497c1e96125126020840184612fe0565b6125226040850160208601613804565b61252f6040860186613848565b604051602001612540929190613e02565b60408051601f198184030181529190528051602090910120606086013561256d60a08801608089016137d8565b61257d60c0890160a08a016137d8565b61258d60e08a0160c08b016137d8565b61259e6101008b0160e08c016137d8565b60408051602081019a909a526001600160a01b039098169789019790975260ff9095166060880152608087019390935260a08601919091526001600160801b0390811660c086015290811660e0850152908116610100848101919091529116610120830152830135610140820152610160016040516020818303038152906040529050919050565b600061064783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250508751602089012061267292509050612b4c565b90611d46565b6060610aa18383604051806060016040528060278152602001613ea860279139612b79565b7f036f52c1827dab135f7fd44ca0bddde297e2f659c710e0ec53e975f22b54830090565b7f322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee030090565b6001600160a01b03163b151590565b60008282604051602001612709929190613e44565b60405160208183030381529060405280519060200120905092915050565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b60008082516041036127815760208301516040840151606085015160001a61277587828585612bf1565b94509450505050612789565b506000905060025b9250929050565b60008160048111156127a4576127a4613e68565b036127ac5750565b60018160048111156127c0576127c0613e68565b036128085760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401610763565b600281600481111561281c5761281c613e68565b036128695760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610763565b600381600481111561287d5761287d613e68565b036113f55760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610763565b60008260000182815481106128ec576128ec613751565b9060005260206000200154905092915050565b80612908611d6a565b6001600160a01b038416600090815260049190910160205260409020805460ff191691151591909117905580156129515761294b82612945611d6a565b90612317565b50612965565b6129638261295d611d6a565b90612339565b505b816001600160a01b03167f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a11133826040516129a2911515815260200190565b60405180910390a25050565b60008181526001830160205260408120546129f557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610594565b506000610594565b606081600001805480602002602001604051908101604052809291908181526020018280548015612a4d57602002820191906000526020600020905b815481526020019060010190808311612a39575b50505050509050919050565b60008181526001830160205260408120548015612b42576000612a7d600183613e7e565b8554909150600090612a9190600190613e7e565b9050818114612af6576000866000018281548110612ab157612ab1613751565b9060005260206000200154905080876000018481548110612ad457612ad4613751565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612b0757612b07613e91565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610594565b6000915050610594565b6000610594612b59611c1f565b8360405161190160f01b8152600281019290925260228201526042902090565b6060600080856001600160a01b031685604051612b969190613cac565b600060405180830381855af49150503d8060008114612bd1576040519150601f19603f3d011682016040523d82523d6000602084013e612bd6565b606091505b5091509150612be786838387612cab565b9695505050505050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115612c1e5750600090506003612ca2565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612c72573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612c9b57600060019250925050612ca2565b9150600090505b94509492505050565b60608315612d18578251600003612d1157612cc5856126e5565b612d115760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610763565b5081610647565b6106478383815115612d2d5781518083602001fd5b8060405162461bcd60e51b81526004016107639190613630565b6040518060a0016040528060006001600160a01b03168152602001606081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b600060208284031215612da357600080fd5b81356001600160e01b031981168114610aa157600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612df957612df9612dbb565b604052919050565b60006001600160401b03831115612e1a57612e1a612dbb565b612e2d601f8401601f1916602001612dd1565b9050828152838383011115612e4157600080fd5b828260208301376000602084830101529392505050565b600082601f830112612e6957600080fd5b610aa183833560208501612e01565b600060208284031215612e8a57600080fd5b81356001600160401b03811115612ea057600080fd5b61064784828501612e58565b6001600160a01b03811681146113f557600080fd5b8035612ecc81612eac565b919050565b60008060008060808587031215612ee757600080fd5b8435612ef281612eac565b93506020850135612f0281612eac565b92506040850135915060608501356001600160401b03811115612f2457600080fd5b612f3087828801612e58565b91505092959194509250565b60008060408385031215612f4f57600080fd5b8235915060208301356001600160401b03811115612f6c57600080fd5b612f7885828601612e58565b9150509250929050565b60006101608284031215612f9557600080fd5b50919050565b60008060408385031215612fae57600080fd5b8235612fb981612eac565b915060208301356001600160401b03811115612fd457600080fd5b612f7885828601612f82565b600060208284031215612ff257600080fd5b8135610aa181612eac565b60008060006060848603121561301257600080fd5b83356001600160401b0381111561302857600080fd5b61303486828701612f82565b9660208601359650604090950135949350505050565b60008083601f84011261305c57600080fd5b5081356001600160401b0381111561307357600080fd5b6020830191508360208260051b850101111561278957600080fd5b600080600080600080606087890312156130a757600080fd5b86356001600160401b03808211156130be57600080fd5b6130ca8a838b0161304a565b909850965060208901359150808211156130e357600080fd5b6130ef8a838b0161304a565b9096509450604089013591508082111561310857600080fd5b5061311589828a0161304a565b979a9699509497509295939492505050565b6000806040838503121561313a57600080fd5b823561314581612eac565b946020939093013593505050565b60008083601f84011261316557600080fd5b5081356001600160401b0381111561317c57600080fd5b60208301915083602082850101111561278957600080fd5b6000806000604084860312156131a957600080fd5b83356001600160401b03808211156131c057600080fd5b9085019061012082880312156131d557600080fd5b909350602085013590808211156131eb57600080fd5b506131f886828701613153565b9497909650939450505050565b6001600160801b03169052565b80516001600160a01b03908116835260208083015160a082860181905281519086018190526000939183019290849060c08801905b8083101561326957855185168252948301946001929092019190830190613247565b5060408701516040890152606087015194506132886060890186613205565b6080870151945061329c6080890186613205565b979650505050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156132fe57603f198886030184526132ec858351613212565b945092850192908501906001016132d0565b5092979650505050505050565b60006020828403121561331d57600080fd5b81356001600160401b0381111561333357600080fd5b8201601f8101841361334457600080fd5b61064784823560208401612e01565b6000806020838503121561336657600080fd5b82356001600160401b0381111561337c57600080fd5b6133888582860161304a565b90969095509350505050565b60005b838110156133af578181015183820152602001613397565b50506000910152565b600081518084526133d0816020860160208601613394565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156132fe57603f198886030184526134298583516133b8565b9450928501929085019060010161340d565b6001600160a01b0391909116815260200190565b6000806000806060858703121561346557600080fd5b843561347081612eac565b93506020850135925060408501356001600160401b0381111561349257600080fd5b61349e87828801613153565b95989497509550505050565b60006001600160401b038211156134c3576134c3612dbb565b5060051b60200190565b600082601f8301126134de57600080fd5b813560206134f36134ee836134aa565b612dd1565b8083825260208201915060208460051b87010193508684111561351557600080fd5b602086015b84811015613531578035835291830191830161351a565b509695505050505050565b600080600080600060a0868803121561355457600080fd5b853561355f81612eac565b9450602086013561356f81612eac565b935060408601356001600160401b038082111561358b57600080fd5b61359789838a016134cd565b945060608801359150808211156135ad57600080fd5b6135b989838a016134cd565b935060808801359150808211156135cf57600080fd5b506135dc88828901612e58565b9150509295509295909350565b6000806000604084860312156135fe57600080fd5b833561360981612eac565b925060208401356001600160401b0381111561362457600080fd5b6131f886828701613153565b602081526000610aa160208301846133b8565b6020808252825182820181905260009190848201906040850190845b818110156136845783516001600160a01b03168352928401929184019160010161365f565b50909695505050505050565b602081526000610aa16020830184613212565b600080600080600060a086880312156136bb57600080fd5b85356136c681612eac565b945060208601356136d681612eac565b9350604086013592506060860135915060808601356001600160401b038111156136ff57600080fd5b6135dc88828901612e58565b6000808335601e1984360301811261372257600080fd5b8301803591506001600160401b0382111561373c57600080fd5b60200191503681900382131561278957600080fd5b634e487b7160e01b600052603260045260246000fd5b60208082526021908201527f4163636f756e743a206e6f742061646d696e206f7220456e747279506f696e746040820152601760f91b606082015260800190565b6001600160a01b03929092168252602082015260400190565b80356001600160801b0381168114612ecc57600080fd5b6000602082840312156137ea57600080fd5b610aa1826137c1565b803560ff81168114612ecc57600080fd5b60006020828403121561381657600080fd5b610aa1826137f3565b634e487b7160e01b600052601160045260246000fd5b808201808211156105945761059461381f565b6000808335601e1984360301811261385f57600080fd5b8301803591506001600160401b0382111561387957600080fd5b6020019150600581901b360382131561278957600080fd5b6000808335601e198436030181126138a857600080fd5b83016020810192503590506001600160401b038111156138c757600080fd5b8060051b360382131561278957600080fd5b8183526000602080850194508260005b858110156139175781356138fc81612eac565b6001600160a01b0316875295820195908201906001016138e9565b509495945050505050565b602081526139436020820161393684612ec1565b6001600160a01b03169052565b6000613951602084016137f3565b60ff81166040840152506139686040840184613891565b610120806060860152613980610140860183856138d9565b925060608601356080860152613998608087016137c1565b91506139a760a0860183613205565b6139b360a087016137c1565b91506139c260c0860183613205565b6139ce60c087016137c1565b91506139dd60e0860183613205565b6139e960e087016137c1565b91506101006139fa81870184613205565b9590950135939094019290925250919050565b600060018201613a1f57613a1f61381f565b5060010190565b8284823760609190911b6001600160601b0319169101908152601401919050565b600060208284031215613a5957600080fd5b5051919050565b600181811c90821680613a7457607f821691505b602082108103612f9557634e487b7160e01b600052602260045260246000fd5b602080825260059082015264214461746160d81b604082015260600190565b60008085851115613ac357600080fd5b83861115613ad057600080fd5b5050820193919092039150565b6001600160e01b03198135818116916004851015613b055780818660040360031b1b83161692505b505092915050565b600060208284031215613b1f57600080fd5b5035919050565b600082601f830112613b3757600080fd5b81356020613b476134ee836134aa565b82815260059290921b84018101918181019086841115613b6657600080fd5b8286015b848110156135315780356001600160401b03811115613b895760008081fd5b613b978986838b0101612e58565b845250918301918301613b6a565b600080600060608486031215613bba57600080fd5b83356001600160401b0380821115613bd157600080fd5b818601915086601f830112613be557600080fd5b81356020613bf56134ee836134aa565b82815260059290921b8401810191818101908a841115613c1457600080fd5b948201945b83861015613c3b578535613c2c81612eac565b82529482019490820190613c19565b97505087013592505080821115613c5157600080fd5b613c5d878388016134cd565b93506040860135915080821115613c7357600080fd5b50613c8086828701613b26565b9150509250925092565b600060208284031215613c9c57600080fd5b81518015158114610aa157600080fd5b60008251613cbe818460208701613394565b9190910192915050565b601f821115613d10576000816000526020600020601f850160051c81016020861015613cf15750805b601f850160051c820191505b81811015610ce257828155600101613cfd565b505050565b81516001600160401b03811115613d2e57613d2e612dbb565b613d4281613d3c8454613a60565b84613cc8565b602080601f831160018114613d775760008415613d5f5750858301515b600019600386901b1c1916600185901b178555610ce2565b600085815260208120601f198616915b82811015613da657888601518255948401946001909101908401613d87565b5085821015613dc45787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b604081526000613de760408301856133b8565b8281036020840152613df981856133b8565b95945050505050565b60008184825b85811015613e39578135613e1b81612eac565b6001600160a01b031683526020928301929190910190600101613e08565b509095945050505050565b6001600160a01b0383168152604060208201819052600090610647908301846133b8565b634e487b7160e01b600052602160045260246000fd5b818103818111156105945761059461381f565b634e487b7160e01b600052603160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220a031bcfe5c5246fc2b8326d1783bec18aa37ab91f19b647ed1f1162ac7b3a39f64736f6c63430008170033"; +bytes constant THIRDWEB_ACCOUNT_FACTORY_BYTECODE = hex"608060405234801561001057600080fd5b50600436106101285760003560e01c806308e93d0a1461012d5780630b61e12b1461014b5780630e6254fd1461016057806311464fbe14610173578063248a9ca3146101b25780632f2ff15d146101d357806336568abe146101e657806358451f97146101f957806383a03f8c146102015780638878ed33146102145780639010d07c1461022757806391d148541461023a5780639387a3801461025d578063938e3d7b14610270578063a217fddf14610283578063a32fa5b31461028b578063a65d69d41461029e578063ac9650d8146102c5578063c3c5a547146102e5578063ca15c873146102f8578063d547741f1461030b578063d8fd8f441461031e578063e68a7c3b14610331578063e8a3d48514610344575b600080fd5b610135610359565b6040516101429190611945565b60405180910390f35b61015e6101593660046119ae565b61036a565b005b61013561016e3660046119d8565b61040b565b61019a7f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac81565b6040516001600160a01b039091168152602001610142565b6101c56101c03660046119f3565b610435565b604051908152602001610142565b61015e6101e1366004611a0c565b610453565b61015e6101f4366004611a0c565b6104fd565b6101c561055c565b61015e61020f3660046119f3565b610568565b61019a610222366004611a38565b6105b6565b61019a610235366004611aba565b610630565b61024d610248366004611a0c565b61073e565b6040519015158152602001610142565b61015e61026b3660046119ae565b610772565b61015e61027e366004611af2565b610809565b6101c5600081565b61024d610299366004611a0c565b61085a565b61019a7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278981565b6102d86102d3366004611ba2565b6108bd565b6040516101429190611c66565b61024d6102f33660046119d8565b610a19565b6101c56103063660046119f3565b610a25565b61015e610319366004611a0c565b610ac2565b61019a61032c366004611a38565b610acd565b61013561033f366004611aba565b610c18565b61034c610d49565b6040516101429190611cca565b60606103656000610de1565b905090565b336103758183610dee565b61039a5760405162461bcd60e51b815260040161039190611cdd565b60405180910390fd5b6001600160a01b03831660009081526002602052604081206103bc9083610e32565b9050801561040557836001600160a01b0316826001600160a01b03167f12146497b3b826918ec47f0cac7272a09ed06b30c16c030e99ec48ff5dd60b4760405160405180910390a35b50505050565b6001600160a01b038116600090815260026020526040902060609061042f90610de1565b92915050565b600061043f610e47565b600092835260010160205250604090205490565b61047761045e610e47565b6000848152600191909101602052604090205433610e6b565b61047f610e47565b6000838152602091825260408082206001600160a01b0385168352909252205460ff16156104ef5760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610391565b6104f98282610ef0565b5050565b336001600160a01b038216146105525760405162461bcd60e51b815260206004820152601a60248201527921b0b71037b7363c903932b737bab731b2903337b91039b2b63360311b6044820152606401610391565b6104f98282610f04565b60006103656000610f18565b336105738183610dee565b61058f5760405162461bcd60e51b815260040161039190611cdd565b61059a600082610e32565b6104f95760405162461bcd60e51b815260040161039190611d14565b6000806105f98585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f2292505050565b90506106257f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac82610f55565b9150505b9392505050565b60008061063b610fb5565b600085815260209190915260408120549150805b82811015610735576000610661610fb5565b60008881526020918252604080822085835260010190925220546001600160a01b0316146106d9578482036106c757610698610fb5565b600087815260209182526040808220938252600190930190915220546001600160a01b0316925061042f915050565b6106d2600183611d74565b9150610723565b6106e486600061073e565b801561071057506106f3610fb5565b600087815260209182526040808220828052600201909252205481145b1561072357610720600183611d74565b91505b61072e600182611d74565b905061064f565b50505092915050565b6000610748610e47565b6000938452602090815260408085206001600160a01b039490941685529290525090205460ff1690565b3361077d8183610dee565b6107995760405162461bcd60e51b815260040161039190611cdd565b6001600160a01b03831660009081526002602052604081206107bb9083610fbf565b9050801561040557836001600160a01b0316826001600160a01b03167f98d1ebbe00ae92a5de96a0f49742a8afa89f42363592bc2e7cfaaed68b45e7a660405160405180910390a350505050565b610811610fd4565b61084e5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610391565b61085781610fe0565b50565b6000610864610e47565b600084815260209182526040808220828052909252205460ff166108b45761088a610e47565b6000848152602091825260408082206001600160a01b0386168352909252205460ff16905061042f565b50600192915050565b6060816001600160401b038111156108d7576108d7611adc565b60405190808252806020026020018201604052801561090a57816020015b60608152602001906001900390816108f55790505b509050336000805b848110156107355781156109915761096f3087878481811061093657610936611d87565b90506020028101906109489190611d9d565b8660405160200161095b93929190611dea565b6040516020818303038152906040526110c7565b84828151811061098157610981611d87565b6020026020010181905250610a11565b6109f3308787848181106109a7576109a7611d87565b90506020028101906109b99190611d9d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506110c792505050565b848281518110610a0557610a05611d87565b60200260200101819052505b600101610912565b600061042f81836110ec565b600080610a30610fb5565b6000848152602091909152604081205491505b81811015610a9d576000610a55610fb5565b60008681526020918252604080822085835260010190925220546001600160a01b031614610a8b57610a88600184611d74565b92505b610a96600182611d74565b9050610a43565b50610aa983600061073e565b15610abc57610ab9600183611d74565b91505b50919050565b61055261045e610e47565b6000807f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac90506000610b358686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f2292505050565b90506000610b438383610f55565b90506001600160a01b0381163b15610b5f579250610629915050565b610b69838361110e565b9050336001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27891614610bc257610ba6600082610e32565b610bc25760405162461bcd60e51b815260040161039190611d14565b610bce818888886111a5565b866001600160a01b0316816001600160a01b03167fac631f3001b55ea1509cf3d7e74898f85392a61a76e8149181ae1259622dabc860405160405180910390a39695505050505050565b60608183108015610c325750610c2e6000610f18565b8211155b610c8a5760405162461bcd60e51b815260206004820152602360248201527f426173654163636f756e74466163746f72793a20696e76616c696420696e646960448201526263657360e81b6064820152608401610391565b6000610c968484611e0b565b9050610ca28484611e0b565b6001600160401b03811115610cb957610cb9611adc565b604051908082528060200260200182016040528015610ce2578160200160208202803683370190505b50915060005b81811015610d4157610d05610cfd8683611d74565b60009061120d565b838281518110610d1757610d17611d87565b6001600160a01b0390921660209283029190910190910152610d3a600182611d74565b9050610ce8565b505092915050565b6060610d53611219565b8054610d5e90611e1e565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8a90611e1e565b8015610dd75780601f10610dac57610100808354040283529160200191610dd7565b820191906000526020600020905b815481529060010190602001808311610dba57829003601f168201915b5050505050905090565b606060006106298361123d565b600080610e1b7f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac84610f55565b6001600160a01b0385811691161491505092915050565b6000610629836001600160a01b038416611299565b7f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e50090565b610e73610e47565b6000838152602091825260408082206001600160a01b0385168352909252205460ff166104f957610eae816001600160a01b031660146112e8565b610eb98360206112e8565b604051602001610eca929190611e52565b60408051601f198184030181529082905262461bcd60e51b825261039191600401611cca565b610efa8282611483565b6104f982826114ec565b610f0e82826115ab565b6104f98282611614565b600061042f825490565b60008282604051602001610f37929190611ebf565b60405160208183030381529060405280519060200120905092915050565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c82012060788201526055604390910120600090610629565b60006103656116a3565b6000610629836001600160a01b038416611705565b6000610365813361073e565b6000610fea611219565b8054610ff590611e1e565b80601f016020809104026020016040519081016040528092919081815260200182805461102190611e1e565b801561106e5780601f106110435761010080835404028352916020019161106e565b820191906000526020600020905b81548152906001019060200180831161105157829003601f168201915b505050505090508161107e611219565b906110899082611f34565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a1681836040516110bb929190611ff3565b60405180910390a15050565b606061062983836040518060600160405280602781526020016120b9602791396117f8565b6001600160a01b03811660009081526001830160205260408120541515610629565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661042f5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610391565b60405163347d5e2560e21b81526001600160a01b0385169063d1f57894906111d590869086908690600401612018565b600060405180830381600087803b1580156111ef57600080fd5b505af1158015611203573d6000803e3d6000fd5b5050505050505050565b60006106298383611870565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b60608160000180548060200260200160405190810160405280929190818152602001828054801561128d57602002820191906000526020600020905b815481526020019060010190808311611279575b50505050509050919050565b60008181526001830160205260408120546112e05750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561042f565b50600061042f565b606060006112f7836002612058565b611302906002611d74565b6001600160401b0381111561131957611319611adc565b6040519080825280601f01601f191660200182016040528015611343576020820181803683370190505b509050600360fc1b8160008151811061135e5761135e611d87565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061138d5761138d611d87565b60200101906001600160f81b031916908160001a90535060006113b1846002612058565b6113bc906001611d74565b90505b6001811115611434576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106113f0576113f0611d87565b1a60f81b82828151811061140657611406611d87565b60200101906001600160f81b031916908160001a90535060049490941c9361142d8161206f565b90506113bf565b5083156106295760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610391565b600161148d610e47565b6000848152602091825260408082206001600160a01b0386168084529352808220805460ff1916941515949094179093559151339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60006114f6610fb5565b6000848152602091909152604090205490506001611512610fb5565b6000858152602091909152604081208054909190611531908490611d74565b90915550829050611540610fb5565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b039290921691909117905580611580610fb5565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b6115b58282610e6b565b6115bd610e47565b6000838152602091825260408082206001600160a01b0385168084529352808220805460ff191690555133929185917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600061161e610fb5565b6000848152602091825260408082206001600160a01b03861683526002019092522054905061164b610fb5565b6000848152602091825260408082208483526001019092522080546001600160a01b031916905561167a610fb5565b6000938452602090815260408085206001600160a01b0390941685526002909301905250812055565b60008060ff196116d460017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c611e0b565b6040516020016116e691815260200190565b60408051601f1981840301815291905280516020909101201692915050565b600081815260018301602052604081205480156117ee576000611729600183611e0b565b855490915060009061173d90600190611e0b565b90508181146117a257600086600001828154811061175d5761175d611d87565b906000526020600020015490508087600001848154811061178057611780611d87565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117b3576117b3612086565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061042f565b600091505061042f565b6060600080856001600160a01b031685604051611815919061209c565b600060405180830381855af49150503d8060008114611850576040519150601f19603f3d011682016040523d82523d6000602084013e611855565b606091505b50915091506118668683838761189a565b9695505050505050565b600082600001828154811061188757611887611d87565b9060005260206000200154905092915050565b60608315611909578251600003611902576001600160a01b0385163b6119025760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610391565b5081611913565b611913838361191b565b949350505050565b81511561192b5781518083602001fd5b8060405162461bcd60e51b81526004016103919190611cca565b6020808252825182820181905260009190848201906040850190845b818110156119865783516001600160a01b031683529284019291840191600101611961565b50909695505050505050565b80356001600160a01b03811681146119a957600080fd5b919050565b600080604083850312156119c157600080fd5b6119ca83611992565b946020939093013593505050565b6000602082840312156119ea57600080fd5b61062982611992565b600060208284031215611a0557600080fd5b5035919050565b60008060408385031215611a1f57600080fd5b82359150611a2f60208401611992565b90509250929050565b600080600060408486031215611a4d57600080fd5b611a5684611992565b925060208401356001600160401b0380821115611a7257600080fd5b818601915086601f830112611a8657600080fd5b813581811115611a9557600080fd5b876020828501011115611aa757600080fd5b6020830194508093505050509250925092565b60008060408385031215611acd57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b600060208284031215611b0457600080fd5b81356001600160401b0380821115611b1b57600080fd5b818401915084601f830112611b2f57600080fd5b813581811115611b4157611b41611adc565b604051601f8201601f19908116603f01168101908382118183101715611b6957611b69611adc565b81604052828152876020848701011115611b8257600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060208385031215611bb557600080fd5b82356001600160401b0380821115611bcc57600080fd5b818501915085601f830112611be057600080fd5b813581811115611bef57600080fd5b8660208260051b8501011115611c0457600080fd5b60209290920196919550909350505050565b60005b83811015611c31578181015183820152602001611c19565b50506000910152565b60008151808452611c52816020860160208601611c16565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015611cbd57603f19888603018452611cab858351611c3a565b94509285019290850190600101611c8f565b5092979650505050505050565b6020815260006106296020830184611c3a565b6020808252601f908201527f4163636f756e74466163746f72793a206e6f7420616e206163636f756e742e00604082015260600190565b6020808252602a908201527f4163636f756e74466163746f72793a206163636f756e7420616c7265616479206040820152691c9959da5cdd195c995960b21b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561042f5761042f611d5e565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112611db457600080fd5b8301803591506001600160401b03821115611dce57600080fd5b602001915036819003821315611de357600080fd5b9250929050565b8284823760609190911b6001600160601b0319169101908152601401919050565b8181038181111561042f5761042f611d5e565b600181811c90821680611e3257607f821691505b602082108103610abc57634e487b7160e01b600052602260045260246000fd5b7402832b936b4b9b9b4b7b7399d1030b1b1b7bab73a1605d1b815260008351611e82816015850160208801611c16565b7001034b99036b4b9b9b4b733903937b6329607d1b6015918401918201528351611eb3816026840160208801611c16565b01602601949350505050565b6001600160a01b038316815260406020820181905260009061191390830184611c3a565b601f821115611f2f576000816000526020600020601f850160051c81016020861015611f0c5750805b601f850160051c820191505b81811015611f2b57828155600101611f18565b5050505b505050565b81516001600160401b03811115611f4d57611f4d611adc565b611f6181611f5b8454611e1e565b84611ee3565b602080601f831160018114611f965760008415611f7e5750858301515b600019600386901b1c1916600185901b178555611f2b565b600085815260208120601f198616915b82811015611fc557888601518255948401946001909101908401611fa6565b5085821015611fe35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6040815260006120066040830185611c3a565b82810360208401526106258185611c3a565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761042f5761042f611d5e565b60008161207e5761207e611d5e565b506000190190565b634e487b7160e01b600052603160045260246000fd5b600082516120ae818460208701611c16565b919091019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220dcd476482fb1b0a1a789554876c49403bc9eabddddfead79e8de64f2f34d2ea864736f6c63430008170033"; +bytes constant THIRDWEB_ACCOUNT_IMPL_BYTECODE = hex"60806040526004361061014b5760003560e01c806301ffc9a7146101575780630a1028c41461018c578063150b7a02146101ba5780631626ba7e146101f35780631dd756c51461021357806324d7806c146102335780633a871cdd1461025357806347e1da2a146102735780634a58db19146102955780634d44560d1461029d5780635892e236146102bd5780637dff5a79146102dd5780638b52d723146102fd578063938e3d7b1461031f578063a9082d841461033f578063ac9650d81461037e578063b0d691fe146103ab578063b61d27f6146103cd578063b76464d5146103ed578063bc197c811461040d578063c45a015514610439578063d087d2881461046d578063d1f5789414610482578063d42f2f35146104a2578063e8a3d485146104b7578063e9523c97146104d9578063f15d424e146104fb578063f23a6e611461052857600080fd5b3661015257005b600080fd5b34801561016357600080fd5b50610177610172366004612e42565b610554565b60405190151581526020015b60405180910390f35b34801561019857600080fd5b506101ac6101a7366004612f37565b61059a565b604051908152602001610183565b3480156101c657600080fd5b506101da6101d5366004612f90565b61063e565b6040516001600160e01b03199091168152602001610183565b3480156101ff57600080fd5b506101da61020e366004612ffb565b61064f565b34801561021f57600080fd5b5061017761022e36600461305a565b610840565b34801561023f57600080fd5b5061017761024e36600461309f565b610b04565b34801561025f57600080fd5b506101ac61026e3660046130bc565b610b33565b34801561027f57600080fd5b5061029361028e36600461314d565b610b59565b005b610293610cc0565b3480156102a957600080fd5b506102936102b83660046131e6565b610d28565b3480156102c957600080fd5b506102936102d8366004613253565b610d9b565b3480156102e957600080fd5b506101776102f836600461309f565b611158565b34801561030957600080fd5b50610312611211565b6040516101839190613366565b34801561032b57600080fd5b5061029361033a3660046133ca565b611458565b34801561034b57600080fd5b5061035f61035a366004613253565b6114a9565b6040805192151583526001600160a01b03909116602083015201610183565b34801561038a57600080fd5b5061039e610399366004613412565b611500565b60405161018391906134a3565b3480156103b757600080fd5b506103c0611665565b60405161018391906134fa565b3480156103d957600080fd5b506102936103e836600461350e565b6116ae565b3480156103f957600080fd5b5061029361040836600461309f565b61173e565b34801561041957600080fd5b506101da6104283660046135f6565b63bc197c8160e01b95945050505050565b34801561044557600080fd5b506103c07f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b81565b34801561047957600080fd5b506101ac611770565b34801561048e57600080fd5b5061029361049d3660046136a3565b6117f0565b3480156104ae57600080fd5b506103126119a8565b3480156104c357600080fd5b506104cc611b19565b60405161018391906136ea565b3480156104e557600080fd5b506104ee611bb1565b60405161018391906136fd565b34801561050757600080fd5b5061051b61051636600461309f565b611bc3565b604051610183919061374a565b34801561053457600080fd5b506101da61054336600461375d565b63f23a6e6160e01b95945050505050565b60006001600160e01b03198216630271189760e51b148061058557506001600160e01b03198216630a85bd0160e11b145b80610594575061059482611c9b565b92915050565b6000807f82cac545155fcbf147f2a9013809613677ac7d65498556e6d19ce43bcbf6c28483805190602001206040516020016105e0929190918252602082015260400190565b604051602081830303815290604052805190602001209050610600611cd0565b60405161190160f01b602082015260228101919091526042810182905260620160405160208183030381529060405280519060200120915050919050565b630a85bd0160e11b5b949350505050565b6000806060604184511115610700576000808580602001905181019061067591906137c5565b604080516041808252608082019092529196509193508592509060208201818036833701905050925060005b60418110156106f8578281815181106106bc576106bc613845565b602001015160f81c60f81b8482815181106106d9576106d9613845565b60200101906001600160f81b031916908160001a9053506001016106a1565b50505061072d565b61072a8560405160200161071691815260200190565b60405160208183030381529060405261059a565b91505b60006107398383611df7565b905061074481610b04565b1561075c5750630b135d3f60e11b9250610594915050565b336000610767611e1b565b6001600160a01b038416600090815260069190910160205260409020905061078f8183611e3f565b806107bf575061079e81611e61565b60011480156107bf575060006107b48282611e6b565b6001600160a01b0316145b61081c5760405162461bcd60e51b8152602060048201526024808201527f4163636f756e743a2063616c6c6572206e6f7420617070726f7665642074617260448201526333b2ba1760e11b60648201526084015b60405180910390fd5b61082583611158565b1561083557630b135d3f60e11b95505b505050505092915050565b600061084a611e1b565b6001600160a01b0384166000908152600491909101602052604090205460ff161561087757506001610594565b6000610881611e1b565b6001600160a01b0385166000908152600591909101602090815260408083208151606081018352815481526001909101546001600160801b0380821694830194909452600160801b90049092169082015291506108dc611e1b565b6006016000866001600160a01b03166001600160a01b0316815260200190815260200160002090504282602001516001600160801b0316118061092c575081604001516001600160801b03164210155b8061093d575061093b81611e61565b155b1561094d57600092505050610594565b600061096461095f606087018761385b565b611e77565b9050600061097183611e61565b6001148015610992575060006109878482611e6b565b6001600160a01b0316145b90506324f16c0560e11b6001600160e01b0319831601610a09576000806109c46109bf60608a018a61385b565b611eb1565b91509150826109ea576109d78583611e3f565b6109ea5760009650505050505050610594565b8551811115610a025760009650505050505050610594565b5050610af7565b635c0f12eb60e11b6001600160e01b0319831601610aea57600080610a39610a3460608a018a61385b565b611f16565b509150915082610a995760005b8251811015610a9757610a7b838281518110610a6457610a64613845565b602002602001015187611e3f90919063ffffffff16565b610a8f576000975050505050505050610594565b600101610a46565b505b60005b8251811015610ae257818181518110610ab757610ab7613845565b602002602001015187600001511015610ada576000975050505050505050610594565b600101610a9c565b505050610af7565b6000945050505050610594565b5060019695505050505050565b6000610b0e611e1b565b6001600160a01b03909216600090815260049290920160205250604090205460ff1690565b6000610b3d611f63565b610b478484611fcc565b9050610b5282612111565b9392505050565b610b61611665565b6001600160a01b0316336001600160a01b03161480610b845750610b8433610b04565b610ba05760405162461bcd60e51b8152600401610813906138a1565b610ba861215e565b8481148015610bb657508483145b610c025760405162461bcd60e51b815260206004820152601d60248201527f4163636f756e743a2077726f6e67206172726179206c656e677468732e0000006044820152606401610813565b60005b85811015610cb757610cae878783818110610c2257610c22613845565b9050602002016020810190610c37919061309f565b868684818110610c4957610c49613845565b90506020020135858585818110610c6257610c62613845565b9050602002810190610c74919061385b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061224492505050565b50600101610c05565b50505050505050565b610cc8611665565b6001600160a01b031663b760faf934306040518363ffffffff1660e01b8152600401610cf491906134fa565b6000604051808303818588803b158015610d0d57600080fd5b505af1158015610d21573d6000803e3d6000fd5b5050505050565b610d306122b5565b610d38611665565b6001600160a01b031663205c287883836040518363ffffffff1660e01b8152600401610d659291906138e2565b600060405180830381600087803b158015610d7f57600080fd5b505af1158015610d93573d6000803e3d6000fd5b505050505050565b6000610daa602085018561309f565b905042610dbd60e0860160c08701613912565b6001600160801b031611158015610dec5750610de0610100850160e08601613912565b6001600160801b031642105b610e225760405162461bcd60e51b8152602060048201526007602482015266085c195c9a5bd960ca1b6044820152606401610813565b600080610e308686866114a9565b9150915081610e6a5760405162461bcd60e51b8152600401610813906020808252600490820152632173696760e01b604082015260600190565b6001610e74611e1b565b610100880135600090815260079190910160209081526040808320805460ff1916941515949094179093559091610eb09190890190890161393e565b60ff161115610edd576000610ecb604088016020890161393e565b60ff166001149050610cb784826122f3565b610ee683610b04565b15610f1b5760405162461bcd60e51b815260206004820152600560248201526430b236b4b760d91b6044820152606401610813565b610f3083610f27611e1b565b600201906123c8565b50604051806060016040528087606001358152602001876080016020810190610f599190613912565b6001600160801b03168152602001610f7760c0890160a08a01613912565b6001600160801b03169052610f8a611e1b565b6001600160a01b03851660009081526005919091016020908152604080832084518155918401519301516001600160801b03908116600160801b02931692909217600190920191909155611000610fdf611e1b565b6001600160a01b0386166000908152600691909101602052604090206123dd565b805190915060005b8181101561106a5761105783828151811061102557611025613845565b6020026020010151611035611e1b565b6001600160a01b038916600090815260069190910160205260409020906123ea565b5061106360018261396f565b9050611008565b506110786040890189613982565b9050905060005b818110156110f9576110e661109760408b018b613982565b838181106110a7576110a7613845565b90506020020160208101906110bc919061309f565b6110c4611e1b565b6001600160a01b038916600090815260069190910160205260409020906123c8565b506110f260018261396f565b905061107f565b50611103886123ff565b846001600160a01b0316836001600160a01b03167ff21d10c26e35863a8df291aca54181ee8c4a3bc8e00246c3f7a5a14b69d826a78a6040516111469190613a5c565b60405180910390a35050505050505050565b600080611163611e1b565b6001600160a01b038416600090815260059190910160209081526040918290208251606081018452815481526001909101546001600160801b03808216938301849052600160801b909104169281019290925290915042108015906111d4575080604001516001600160801b031642105b8015610b52575060006112096111e8611e1b565b6001600160a01b038616600090815260069190910160205260409020611e61565b119392505050565b60606000611228611220611e1b565b6002016123dd565b80519091506000805b828110156112b95761125b84828151811061124e5761124e613845565b6020026020010151611158565b15611272578161126a81613b47565b9250506112a7565b600084828151811061128657611286613845565b60200260200101906001600160a01b031690816001600160a01b0316815250505b6112b260018261396f565b9050611231565b50806001600160401b038111156112d2576112d2612e6c565b60405190808252806020026020018201604052801561130b57816020015b6112f8612df8565b8152602001906001900390816112f05790505b5093506000805b838110156114505760006001600160a01b031685828151811061133757611337613845565b60200260200101516001600160a01b03161461143e57600085828151811061136157611361613845565b602002602001015190506000611375611e1b565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a0810190945291835290925081016113df610fdf611e1b565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b031681525088858061141e90613b47565b96508151811061143057611430613845565b602002602001018190525050505b61144960018261396f565b9050611312565b505050505090565b611460612494565b61149d5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610813565b6114a6816124ac565b50565b6000806114bf6114b886612593565b85856126d7565b90506114c9611e1b565b6101008601356000908152600791909101602052604090205460ff161580156114f657506114f681610b04565b9150935093915050565b6060816001600160401b0381111561151a5761151a612e6c565b60405190808252806020026020018201604052801561154d57816020015b60608152602001906001900390816115385790505b509050336000805b8481101561165c5781156115d4576115b23087878481811061157957611579613845565b905060200281019061158b919061385b565b8660405160200161159e93929190613b60565b604051602081830303815290604052612729565b8482815181106115c4576115c4613845565b6020026020010181905250611654565b611636308787848181106115ea576115ea613845565b90506020028101906115fc919061385b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061272992505050565b84828151811061164857611648613845565b60200260200101819052505b600101611555565b50505092915050565b60008061167061274e565b546001600160a01b03169050801561168757919050565b7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278991505090565b6116b6611665565b6001600160a01b0316336001600160a01b031614806116d957506116d933610b04565b6116f55760405162461bcd60e51b8152600401610813906138a1565b6116fd61215e565b610d21848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061224492505050565b6117466122b5565b8061174f61274e565b80546001600160a01b0319166001600160a01b039290921691909117905550565b600061177a611665565b604051631aab3f0d60e11b8152306004820152600060248201526001600160a01b0391909116906335567e1a90604401602060405180830381865afa1580156117c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117eb9190613b81565b905090565b60006117fa612772565b5460ff169050600061180a612772565b54610100900460ff1690508015808015611827575060018360ff16105b80611846575061183630612796565b15801561184657508260ff166001145b6118a95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610813565b60016118b3612772565b805460ff191660ff9290921691909117905580156118ec5760016118d5612772565b80549115156101000261ff00199092169190911790555b61192c8686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506127a592505050565b61193461274e565b600101819055506119468660016122f3565b8015610d93576000611956612772565b80549115156101000261ff0019909216919091179055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b606060006119b7611220611e1b565b8051909150806001600160401b038111156119d4576119d4612e6c565b604051908082528060200260200182016040528015611a0d57816020015b6119fa612df8565b8152602001906001900390816119f25790505b50925060005b81811015611b13576000838281518110611a2f57611a2f613845565b602002602001015190506000611a43611e1b565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101611aad610fdf611e1b565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250868481518110611af257611af2613845565b60200260200101819052505050600181611b0c919061396f565b9050611a13565b50505090565b6060611b236127d8565b8054611b2e90613b9a565b80601f0160208091040260200160405190810160405280929190818152602001828054611b5a90613b9a565b8015611ba75780601f10611b7c57610100808354040283529160200191611ba7565b820191906000526020600020905b815481529060010190602001808311611b8a57829003601f168201915b5050505050905090565b60606117eb611bbe611e1b565b6123dd565b611bcb612df8565b6000611bd5611e1b565b6001600160a01b038416600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101611c60611c3f611e1b565b6001600160a01b0387166000908152600691909101602052604090206123dd565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250915050919050565b60006001600160e01b03198216630271189760e51b148061059457506301ffc9a760e01b6001600160e01b0319831614610594565b6000306001600160a01b037f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac16148015611d2957507f0000000000000000000000000000000000000000000000000000000000007a6946145b15611d5357507fbcdadf6444930a967ffda04923d78c49b3dd65df3ed39abb04a1e3eb1190553790565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527ff0729608244859f656d32ae4cbc6b0367695d68d8e941a28f5e2d33c6d5182dd828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000806000611e0685856127fc565b91509150611e1381612841565b509392505050565b7f3181e78fc1b109bc611fd2406150bf06e33faa75f71cba12c3e1fd670f2def0090565b6001600160a01b03811660009081526001830160205260408120541515610b52565b6000610594825490565b6000610b528383612986565b60006004821015611e9a5760405162461bcd60e51b815260040161081390613bce565b611ea8600460008486613bed565b610b5291613c17565b6000806044831015611ed55760405162461bcd60e51b815260040161081390613bce565b611ee3602460048587613bed565b810190611ef0919061309f565b9150611f00604460248587613bed565b810190611f0d9190613c47565b90509250929050565b606080806064841015611f3b5760405162461bcd60e51b815260040161081390613bce565b611f488460048188613bed565b810190611f559190613cdf565b919790965090945092505050565b611f6b611665565b6001600160a01b0316336001600160a01b031614611fca5760405162461bcd60e51b815260206004820152601c60248201527b1858d8dbdd5b9d0e881b9bdd08199c9bdb48115b9d1c9e541bda5b9d60221b6044820152606401610813565b565b7b0ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d05199960211b6000908152601c829052603c8120600061204a61200d61014087018761385b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611df79050565b90506120568186610840565b61206557600192505050610594565b600061206f611e1b565b6001600160a01b03929092166000908152600590920160209081526040808420815160608082018452825482526001909201546001600160801b0380821683870152600160801b8204908116928501929092528351928301845295825265ffffffffffff8087169483019490945292831691015260d09290921b6001600160d01b03191660a09290921b65ffffffffffff60a01b169190911795945050505050565b80156114a657604051600090339060001990849084818181858888f193505050503d8060008114610d21576040519150601f19603f3d011682016040523d82523d6000602084013e610d21565b60405163c3c5a54760e01b81527f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b906001600160a01b0382169063c3c5a547906121ac9030906004016134fa565b602060405180830381865afa1580156121c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ed9190613dc4565b6114a657806001600160a01b03166383a03f8c61220861274e565b600101546040518263ffffffff1660e01b815260040161222a91815260200190565b600060405180830381600087803b158015610d0d57600080fd5b60606000846001600160a01b031684846040516122619190613de6565b60006040518083038185875af1925050503d806000811461229e576040519150601f19603f3d011682016040523d82523d6000602084013e6122a3565b606091505b509250905080611e1357815160208301fd5b6122be33610b04565b611fca5760405162461bcd60e51b815260206004820152600660248201526510b0b236b4b760d11b6044820152606401610813565b6122fd82826129b0565b6001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b163b156123c457801561238c577f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b6001600160a01b0316630b61e12b8361236b61274e565b600101546040518363ffffffff1660e01b8152600401610d659291906138e2565b7f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b6001600160a01b0316639387a3808361236b61274e565b5050565b6000610b52836001600160a01b038416612a5f565b60606000610b5283612aae565b6000610b52836001600160a01b038416612b0a565b6001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b163b156114a6576001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b16630b61e12b61246b602084018461309f565b61247361274e565b600101546040518363ffffffff1660e01b815260040161222a9291906138e2565b600061249f33610b04565b806117eb57505030331490565b60006124b66127d8565b80546124c190613b9a565b80601f01602080910402602001604051908101604052809291908181526020018280546124ed90613b9a565b801561253a5780601f1061250f5761010080835404028352916020019161253a565b820191906000526020600020905b81548152906001019060200180831161251d57829003601f168201915b505050505090508161254a6127d8565b906125559082613e4f565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a168183604051612587929190613f0e565b60405180910390a15050565b60607f3fd4a1a1a267c84185e3b7eecd57c68783c0581d538b9d6e5f23e4670497c1e96125c3602084018461309f565b6125d3604085016020860161393e565b6125e06040860186613982565b6040516020016125f1929190613f3c565b60408051601f198184030181529190528051602090910120606086013561261e60a0880160808901613912565b61262e60c0890160a08a01613912565b61263e60e08a0160c08b01613912565b61264f6101008b0160e08c01613912565b60408051602081019a909a526001600160a01b039098169789019790975260ff9095166060880152608087019390935260a08601919091526001600160801b0390811660c086015290811660e0850152908116610100848101919091529116610120830152830135610140820152610160016040516020818303038152906040529050919050565b600061064783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250508751602089012061272392509050612bfd565b90611df7565b6060610b528383604051806060016040528060278152602001613fe260279139612c2a565b7f036f52c1827dab135f7fd44ca0bddde297e2f659c710e0ec53e975f22b54830090565b7f322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee030090565b6001600160a01b03163b151590565b600082826040516020016127ba929190613f7e565b60405160208183030381529060405280519060200120905092915050565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b60008082516041036128325760208301516040840151606085015160001a61282687828585612ca2565b9450945050505061283a565b506000905060025b9250929050565b600081600481111561285557612855613fa2565b0361285d5750565b600181600481111561287157612871613fa2565b036128b95760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401610813565b60028160048111156128cd576128cd613fa2565b0361291a5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610813565b600381600481111561292e5761292e613fa2565b036114a65760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610813565b600082600001828154811061299d5761299d613845565b9060005260206000200154905092915050565b806129b9611e1b565b6001600160a01b038416600090815260049190910160205260409020805460ff19169115159190911790558015612a02576129fc826129f6611e1b565b906123c8565b50612a16565b612a1482612a0e611e1b565b906123ea565b505b816001600160a01b03167f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a1113382604051612a53911515815260200190565b60405180910390a25050565b6000818152600183016020526040812054612aa657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610594565b506000610594565b606081600001805480602002602001604051908101604052809291908181526020018280548015612afe57602002820191906000526020600020905b815481526020019060010190808311612aea575b50505050509050919050565b60008181526001830160205260408120548015612bf3576000612b2e600183613fb8565b8554909150600090612b4290600190613fb8565b9050818114612ba7576000866000018281548110612b6257612b62613845565b9060005260206000200154905080876000018481548110612b8557612b85613845565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612bb857612bb8613fcb565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610594565b6000915050610594565b6000610594612c0a611cd0565b8360405161190160f01b8152600281019290925260228201526042902090565b6060600080856001600160a01b031685604051612c479190613de6565b600060405180830381855af49150503d8060008114612c82576040519150601f19603f3d011682016040523d82523d6000602084013e612c87565b606091505b5091509150612c9886838387612d5c565b9695505050505050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115612ccf5750600090506003612d53565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612d23573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612d4c57600060019250925050612d53565b9150600090505b94509492505050565b60608315612dc9578251600003612dc257612d7685612796565b612dc25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610813565b5081610647565b6106478383815115612dde5781518083602001fd5b8060405162461bcd60e51b815260040161081391906136ea565b6040518060a0016040528060006001600160a01b03168152602001606081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b600060208284031215612e5457600080fd5b81356001600160e01b031981168114610b5257600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612eaa57612eaa612e6c565b604052919050565b60006001600160401b03821115612ecb57612ecb612e6c565b50601f01601f191660200190565b6000612eec612ee784612eb2565b612e82565b9050828152838383011115612f0057600080fd5b828260208301376000602084830101529392505050565b600082601f830112612f2857600080fd5b610b5283833560208501612ed9565b600060208284031215612f4957600080fd5b81356001600160401b03811115612f5f57600080fd5b61064784828501612f17565b6001600160a01b03811681146114a657600080fd5b8035612f8b81612f6b565b919050565b60008060008060808587031215612fa657600080fd5b8435612fb181612f6b565b93506020850135612fc181612f6b565b92506040850135915060608501356001600160401b03811115612fe357600080fd5b612fef87828801612f17565b91505092959194509250565b6000806040838503121561300e57600080fd5b8235915060208301356001600160401b0381111561302b57600080fd5b61303785828601612f17565b9150509250929050565b6000610160828403121561305457600080fd5b50919050565b6000806040838503121561306d57600080fd5b823561307881612f6b565b915060208301356001600160401b0381111561309357600080fd5b61303785828601613041565b6000602082840312156130b157600080fd5b8135610b5281612f6b565b6000806000606084860312156130d157600080fd5b83356001600160401b038111156130e757600080fd5b6130f386828701613041565b9660208601359650604090950135949350505050565b60008083601f84011261311b57600080fd5b5081356001600160401b0381111561313257600080fd5b6020830191508360208260051b850101111561283a57600080fd5b6000806000806000806060878903121561316657600080fd5b86356001600160401b038082111561317d57600080fd5b6131898a838b01613109565b909850965060208901359150808211156131a257600080fd5b6131ae8a838b01613109565b909650945060408901359150808211156131c757600080fd5b506131d489828a01613109565b979a9699509497509295939492505050565b600080604083850312156131f957600080fd5b823561320481612f6b565b946020939093013593505050565b60008083601f84011261322457600080fd5b5081356001600160401b0381111561323b57600080fd5b60208301915083602082850101111561283a57600080fd5b60008060006040848603121561326857600080fd5b83356001600160401b038082111561327f57600080fd5b90850190610120828803121561329457600080fd5b909350602085013590808211156132aa57600080fd5b506132b786828701613212565b9497909650939450505050565b6001600160801b03169052565b80516001600160a01b03908116835260208083015160a082860181905281519086018190526000939183019290849060c08801905b8083101561332857855185168252948301946001929092019190830190613306565b50604087015160408901526060870151945061334760608901866132c4565b6080870151945061335b60808901866132c4565b979650505050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156133bd57603f198886030184526133ab8583516132d1565b9450928501929085019060010161338f565b5092979650505050505050565b6000602082840312156133dc57600080fd5b81356001600160401b038111156133f257600080fd5b8201601f8101841361340357600080fd5b61064784823560208401612ed9565b6000806020838503121561342557600080fd5b82356001600160401b0381111561343b57600080fd5b61344785828601613109565b90969095509350505050565b60005b8381101561346e578181015183820152602001613456565b50506000910152565b6000815180845261348f816020860160208601613453565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156133bd57603f198886030184526134e8858351613477565b945092850192908501906001016134cc565b6001600160a01b0391909116815260200190565b6000806000806060858703121561352457600080fd5b843561352f81612f6b565b93506020850135925060408501356001600160401b0381111561355157600080fd5b61355d87828801613212565b95989497509550505050565b60006001600160401b0382111561358257613582612e6c565b5060051b60200190565b600082601f83011261359d57600080fd5b813560206135ad612ee783613569565b8083825260208201915060208460051b8701019350868411156135cf57600080fd5b602086015b848110156135eb57803583529183019183016135d4565b509695505050505050565b600080600080600060a0868803121561360e57600080fd5b853561361981612f6b565b9450602086013561362981612f6b565b935060408601356001600160401b038082111561364557600080fd5b61365189838a0161358c565b9450606088013591508082111561366757600080fd5b61367389838a0161358c565b9350608088013591508082111561368957600080fd5b5061369688828901612f17565b9150509295509295909350565b6000806000604084860312156136b857600080fd5b83356136c381612f6b565b925060208401356001600160401b038111156136de57600080fd5b6132b786828701613212565b602081526000610b526020830184613477565b6020808252825182820181905260009190848201906040850190845b8181101561373e5783516001600160a01b031683529284019291840191600101613719565b50909695505050505050565b602081526000610b5260208301846132d1565b600080600080600060a0868803121561377557600080fd5b853561378081612f6b565b9450602086013561379081612f6b565b9350604086013592506060860135915060808601356001600160401b038111156137b957600080fd5b61369688828901612f17565b600080604083850312156137d857600080fd5b82516001600160401b038111156137ee57600080fd5b8301601f810185136137ff57600080fd5b805161380d612ee782612eb2565b81815286602083850101111561382257600080fd5b613833826020830160208601613453565b60209590950151949694955050505050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261387257600080fd5b8301803591506001600160401b0382111561388c57600080fd5b60200191503681900382131561283a57600080fd5b60208082526021908201527f4163636f756e743a206e6f742061646d696e206f7220456e747279506f696e746040820152601760f91b606082015260800190565b6001600160a01b03929092168252602082015260400190565b80356001600160801b0381168114612f8b57600080fd5b60006020828403121561392457600080fd5b610b52826138fb565b803560ff81168114612f8b57600080fd5b60006020828403121561395057600080fd5b610b528261392d565b634e487b7160e01b600052601160045260246000fd5b8082018082111561059457610594613959565b6000808335601e1984360301811261399957600080fd5b8301803591506001600160401b038211156139b357600080fd5b6020019150600581901b360382131561283a57600080fd5b6000808335601e198436030181126139e257600080fd5b83016020810192503590506001600160401b03811115613a0157600080fd5b8060051b360382131561283a57600080fd5b8183526000602080850194508260005b85811015613a51578135613a3681612f6b565b6001600160a01b031687529582019590820190600101613a23565b509495945050505050565b60208152613a7d60208201613a7084612f80565b6001600160a01b03169052565b6000613a8b6020840161392d565b60ff8116604084015250613aa260408401846139cb565b610120806060860152613aba61014086018385613a13565b925060608601356080860152613ad2608087016138fb565b9150613ae160a08601836132c4565b613aed60a087016138fb565b9150613afc60c08601836132c4565b613b0860c087016138fb565b9150613b1760e08601836132c4565b613b2360e087016138fb565b9150610100613b34818701846132c4565b9590950135939094019290925250919050565b600060018201613b5957613b59613959565b5060010190565b8284823760609190911b6001600160601b0319169101908152601401919050565b600060208284031215613b9357600080fd5b5051919050565b600181811c90821680613bae57607f821691505b60208210810361305457634e487b7160e01b600052602260045260246000fd5b602080825260059082015264214461746160d81b604082015260600190565b60008085851115613bfd57600080fd5b83861115613c0a57600080fd5b5050820193919092039150565b6001600160e01b03198135818116916004851015613c3f5780818660040360031b1b83161692505b505092915050565b600060208284031215613c5957600080fd5b5035919050565b600082601f830112613c7157600080fd5b81356020613c81612ee783613569565b82815260059290921b84018101918181019086841115613ca057600080fd5b8286015b848110156135eb5780356001600160401b03811115613cc35760008081fd5b613cd18986838b0101612f17565b845250918301918301613ca4565b600080600060608486031215613cf457600080fd5b83356001600160401b0380821115613d0b57600080fd5b818601915086601f830112613d1f57600080fd5b81356020613d2f612ee783613569565b82815260059290921b8401810191818101908a841115613d4e57600080fd5b948201945b83861015613d75578535613d6681612f6b565b82529482019490820190613d53565b97505087013592505080821115613d8b57600080fd5b613d978783880161358c565b93506040860135915080821115613dad57600080fd5b50613dba86828701613c60565b9150509250925092565b600060208284031215613dd657600080fd5b81518015158114610b5257600080fd5b60008251613df8818460208701613453565b9190910192915050565b601f821115613e4a576000816000526020600020601f850160051c81016020861015613e2b5750805b601f850160051c820191505b81811015610d9357828155600101613e37565b505050565b81516001600160401b03811115613e6857613e68612e6c565b613e7c81613e768454613b9a565b84613e02565b602080601f831160018114613eb15760008415613e995750858301515b600019600386901b1c1916600185901b178555610d93565b600085815260208120601f198616915b82811015613ee057888601518255948401946001909101908401613ec1565b5085821015613efe5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b604081526000613f216040830185613477565b8281036020840152613f338185613477565b95945050505050565b60008184825b85811015613f73578135613f5581612f6b565b6001600160a01b031683526020928301929190910190600101613f42565b509095945050505050565b6001600160a01b038316815260406020820181905260009061064790830184613477565b634e487b7160e01b600052602160045260246000fd5b8181038181111561059457610594613959565b634e487b7160e01b600052603160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212207dd84271219c3604ac6d88d7bd11606f603938cb8085f1d74eeef41783df3fbe64736f6c63430008170033"; From ba729fdc7836e0be84cb8be08a34e0b9fa411347 Mon Sep 17 00:00:00 2001 From: Krishang Date: Fri, 23 Feb 2024 12:11:28 +0530 Subject: [PATCH 05/12] Pass order params to isValidSignature for tighter verification --- .../account/non-upgradeable/Account.sol | 33 +- .../non-upgradeable/SeaportOrderParser.sol | 548 ++++++++++++++++++ src/test/seaport/AccountBulkOrderSig.t.sol | 28 +- src/test/seaport/EIP712MerkleTree.sol | 45 +- 4 files changed, 602 insertions(+), 52 deletions(-) create mode 100644 contracts/prebuilts/account/non-upgradeable/SeaportOrderParser.sol diff --git a/contracts/prebuilts/account/non-upgradeable/Account.sol b/contracts/prebuilts/account/non-upgradeable/Account.sol index b8579bfae..2234c28d1 100644 --- a/contracts/prebuilts/account/non-upgradeable/Account.sol +++ b/contracts/prebuilts/account/non-upgradeable/Account.sol @@ -20,6 +20,9 @@ import "../utils/Helpers.sol"; import "../../../external-deps/openzeppelin/utils/cryptography/ECDSA.sol"; import "../utils/BaseAccountFactory.sol"; +import { OrderParameters } from "seaport-types/src/lib/ConsiderationStructs.sol"; +import { SeaportOrderParser } from "./SeaportOrderParser.sol"; + // $$\ $$\ $$\ $$\ $$\ // $$ | $$ | \__| $$ | $$ | // $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\ @@ -29,7 +32,7 @@ import "../utils/BaseAccountFactory.sol"; // \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ | // \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/ -contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC1155Holder { +contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC1155Holder, SeaportOrderParser { using ECDSA for bytes32; using EnumerableSet for EnumerableSet.AddressSet; @@ -67,18 +70,28 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115 bytes32 _message, bytes memory _signature ) public view virtual override returns (bytes4 magicValue) { - bytes32 digest; + bytes32 targetDigest; bytes memory targetSig; // Handle OpenSea bulk order signatures that are >65 bytes in length. if (_signature.length > 65) { - // We decode the received bytes data into: - // 1. abi encode-packed signature - // 2. target digest that was signed to produce the signature - (bytes memory extractedPackedSig, bytes32 bulkOrderDigest) = abi.decode(_signature, (bytes, bytes32)); + // Decode packed signature and order parameters. + (bytes memory extractedPackedSig, OrderParameters memory orderParameters, uint256 counter) = abi.decode( + _signature, + (bytes, OrderParameters, uint256) + ); + + // Verify that the original digest matches the digest built with order parameters. + bytes32 domainSeparator = _buildDomainSeparator(msg.sender); + bytes32 orderHash = _deriveOrderHash(orderParameters, counter); + + require( + _deriveEIP712Digest(domainSeparator, orderHash) == _message, + "Seaport: order hash does not match the provided message." + ); - // Use the modified digest built for bulk orders - digest = bulkOrderDigest; + // Build bulk signature digest + targetDigest = _deriveEIP712Digest(domainSeparator, _computeBulkOrderProof(extractedPackedSig, orderHash)); // Extract the signature, which is the first 65 bytes targetSig = new bytes(65); @@ -86,11 +99,11 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115 targetSig[i] = extractedPackedSig[i]; } } else { - digest = getMessageHash(abi.encode(_message)); + targetDigest = getMessageHash(abi.encode(_message)); targetSig = _signature; } - address signer = digest.recover(targetSig); + address signer = targetDigest.recover(targetSig); if (isAdmin(signer)) { return MAGICVALUE; diff --git a/contracts/prebuilts/account/non-upgradeable/SeaportOrderParser.sol b/contracts/prebuilts/account/non-upgradeable/SeaportOrderParser.sol new file mode 100644 index 000000000..6aa8865a0 --- /dev/null +++ b/contracts/prebuilts/account/non-upgradeable/SeaportOrderParser.sol @@ -0,0 +1,548 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.11; + +import { OrderParameters } from "seaport-types/src/lib/ConsiderationStructs.sol"; +import { EIP_712_PREFIX, EIP712_ConsiderationItem_size, EIP712_DigestPayload_size, EIP712_DomainSeparator_offset, EIP712_OfferItem_size, EIP712_Order_size, EIP712_OrderHash_offset, OneWord, OneWordShift, OrderParameters_consideration_head_offset, OrderParameters_counter_offset, OrderParameters_offer_head_offset, TwoWords, BulkOrderProof_keyShift, BulkOrderProof_keySize, BulkOrder_Typehash_Height_One, BulkOrder_Typehash_Height_Two, BulkOrder_Typehash_Height_Three, BulkOrder_Typehash_Height_Four, BulkOrder_Typehash_Height_Five, BulkOrder_Typehash_Height_Six, BulkOrder_Typehash_Height_Seven, BulkOrder_Typehash_Height_Eight, BulkOrder_Typehash_Height_Nine, BulkOrder_Typehash_Height_Ten, BulkOrder_Typehash_Height_Eleven, BulkOrder_Typehash_Height_Twelve, BulkOrder_Typehash_Height_Thirteen, BulkOrder_Typehash_Height_Fourteen, BulkOrder_Typehash_Height_Fifteen, BulkOrder_Typehash_Height_Sixteen, BulkOrder_Typehash_Height_Seventeen, BulkOrder_Typehash_Height_Eighteen, BulkOrder_Typehash_Height_Nineteen, BulkOrder_Typehash_Height_Twenty, BulkOrder_Typehash_Height_TwentyOne, BulkOrder_Typehash_Height_TwentyTwo, BulkOrder_Typehash_Height_TwentyThree, BulkOrder_Typehash_Height_TwentyFour, FreeMemoryPointerSlot } from "seaport-types/src/lib/ConsiderationConstants.sol"; + +contract SeaportOrderParser { + uint256 constant ECDSA_MaxLength = 65; + + bytes32 internal immutable _NAME_HASH; + bytes32 internal immutable _VERSION_HASH; + bytes32 internal immutable _EIP_712_DOMAIN_TYPEHASH; + bytes32 internal immutable _OFFER_ITEM_TYPEHASH; + bytes32 internal immutable _CONSIDERATION_ITEM_TYPEHASH; + bytes32 internal immutable _ORDER_TYPEHASH; + + constructor() { + ( + _NAME_HASH, + _VERSION_HASH, + _EIP_712_DOMAIN_TYPEHASH, + _OFFER_ITEM_TYPEHASH, + _CONSIDERATION_ITEM_TYPEHASH, + _ORDER_TYPEHASH + ) = _deriveTypehashes(); + } + + function _nameString() internal pure virtual returns (string memory) { + // Return the name of the contract. + return "Seaport"; + } + + function _buildDomainSeparator(address _domainAddress) internal view returns (bytes32) { + return + keccak256(abi.encode(_EIP_712_DOMAIN_TYPEHASH, _NAME_HASH, _VERSION_HASH, block.chainid, _domainAddress)); + } + + 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) + } + } + + function _deriveTypehashes() + internal + pure + returns ( + bytes32 nameHash, + bytes32 versionHash, + bytes32 eip712DomainTypehash, + bytes32 offerItemTypehash, + bytes32 considerationItemTypehash, + bytes32 orderTypehash + ) + { + // Derive hash of the name of the contract. + nameHash = keccak256(bytes(_nameString())); + + // Derive hash of the version string of the contract. + versionHash = keccak256(bytes("1.5")); + + // Construct the OfferItem type string. + bytes memory offerItemTypeString = bytes( + "OfferItem(" + "uint8 itemType," + "address token," + "uint256 identifierOrCriteria," + "uint256 startAmount," + "uint256 endAmount" + ")" + ); + + // Construct the ConsiderationItem type string. + bytes memory considerationItemTypeString = bytes( + "ConsiderationItem(" + "uint8 itemType," + "address token," + "uint256 identifierOrCriteria," + "uint256 startAmount," + "uint256 endAmount," + "address recipient" + ")" + ); + + // Construct the OrderComponents type string, not including the above. + bytes memory orderComponentsPartialTypeString = bytes( + "OrderComponents(" + "address offerer," + "address zone," + "OfferItem[] offer," + "ConsiderationItem[] consideration," + "uint8 orderType," + "uint256 startTime," + "uint256 endTime," + "bytes32 zoneHash," + "uint256 salt," + "bytes32 conduitKey," + "uint256 counter" + ")" + ); + + // Construct the primary EIP-712 domain type string. + eip712DomainTypehash = keccak256( + bytes( + "EIP712Domain(" + "string name," + "string version," + "uint256 chainId," + "address verifyingContract" + ")" + ) + ); + + // Derive the OfferItem type hash using the corresponding type string. + offerItemTypehash = keccak256(offerItemTypeString); + + // Derive ConsiderationItem type hash using corresponding type string. + considerationItemTypehash = keccak256(considerationItemTypeString); + + bytes memory orderTypeString = bytes.concat( + orderComponentsPartialTypeString, + considerationItemTypeString, + offerItemTypeString + ); + + // Derive OrderItem type hash via combination of relevant type strings. + orderTypehash = keccak256(orderTypeString); + } + + 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) + } + } + + function _lookupBulkOrderTypehash(uint256 _treeHeight) internal pure returns (bytes32 _typeHash) { + // Utilize assembly to efficiently retrieve correct bulk order typehash. + 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 { + // 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 + } + + // Implement ternary conditional using branchless logic. + function ternary(cond, ifTrue, ifFalse) -> c { + c := xor(ifFalse, mul(cond, xor(ifFalse, ifTrue))) + } + + // Look up the typehash using the supplied tree height. + _typeHash := lookupTypeHash(_treeHeight) + } + } + + function _deriveEIP712Digest(bytes32 domainSeparator, bytes32 orderHash) internal pure returns (bytes32 value) { + // Leverage scratch space to perform an efficient hash. + assembly { + // Place the EIP-712 prefix at the start of scratch space. + mstore(0, EIP_712_PREFIX) + + // Place the domain separator in the next region of scratch space. + mstore(EIP712_DomainSeparator_offset, domainSeparator) + + // Place the order hash in scratch space, spilling into the first + // two bytes of the free memory pointer — this should never be set + // as memory cannot be expanded to that size, and will be zeroed out + // after the hash is performed. + mstore(EIP712_OrderHash_offset, orderHash) + + // Hash the relevant region (65 bytes). + value := keccak256(0, EIP712_DigestPayload_size) + + // Clear out the dirtied bits in the memory pointer. + mstore(EIP712_OrderHash_offset, 0) + } + } +} diff --git a/src/test/seaport/AccountBulkOrderSig.t.sol b/src/test/seaport/AccountBulkOrderSig.t.sol index 895dfd531..825ba6f9b 100644 --- a/src/test/seaport/AccountBulkOrderSig.t.sol +++ b/src/test/seaport/AccountBulkOrderSig.t.sol @@ -19,6 +19,11 @@ import { ConduitController } from "seaport-core/src/conduit/ConduitController.so import { ConsiderationItem, OfferItem, ItemType, SpentItem, OrderComponents, Order, OrderParameters } from "seaport-types/src/lib/ConsiderationStructs.sol"; import { ConsiderationInterface } from "seaport-types/src/interfaces/ConsiderationInterface.sol"; import { OrderType, BasicOrderType } from "seaport-types/src/lib/ConsiderationEnums.sol"; +import { OrderParameters } from "seaport-types/src/lib/ConsiderationStructs.sol"; + +import { Create2AddressDerivation_length, Create2AddressDerivation_ptr, EIP_712_PREFIX, EIP712_ConsiderationItem_size, EIP712_DigestPayload_size, EIP712_DomainSeparator_offset, EIP712_OfferItem_size, EIP712_Order_size, EIP712_OrderHash_offset, FreeMemoryPointerSlot, information_conduitController_offset, information_domainSeparator_offset, information_length, information_version_cd_offset, information_version_offset, information_versionLengthPtr, information_versionWithLength, MaskOverByteTwelve, MaskOverLastTwentyBytes, OneWord, OneWordShift, OrderParameters_consideration_head_offset, OrderParameters_counter_offset, OrderParameters_offer_head_offset, TwoWords } from "seaport-types/src/lib/ConsiderationConstants.sol"; + +import { BulkOrderProof_keyShift, BulkOrderProof_keySize, BulkOrder_Typehash_Height_One, BulkOrder_Typehash_Height_Two, BulkOrder_Typehash_Height_Three, BulkOrder_Typehash_Height_Four, BulkOrder_Typehash_Height_Five, BulkOrder_Typehash_Height_Six, BulkOrder_Typehash_Height_Seven, BulkOrder_Typehash_Height_Eight, BulkOrder_Typehash_Height_Nine, BulkOrder_Typehash_Height_Ten, BulkOrder_Typehash_Height_Eleven, BulkOrder_Typehash_Height_Twelve, BulkOrder_Typehash_Height_Thirteen, BulkOrder_Typehash_Height_Fourteen, BulkOrder_Typehash_Height_Fifteen, BulkOrder_Typehash_Height_Sixteen, BulkOrder_Typehash_Height_Seventeen, BulkOrder_Typehash_Height_Eighteen, BulkOrder_Typehash_Height_Nineteen, BulkOrder_Typehash_Height_Twenty, BulkOrder_Typehash_Height_TwentyOne, BulkOrder_Typehash_Height_TwentyTwo, BulkOrder_Typehash_Height_TwentyThree, BulkOrder_Typehash_Height_TwentyFour, EIP712_domainData_chainId_offset, EIP712_domainData_nameHash_offset, EIP712_domainData_size, EIP712_domainData_verifyingContract_offset, EIP712_domainData_versionHash_offset, FreeMemoryPointerSlot, NameLengthPtr, NameWithLength, OneWord, Slot0x80, ThreeWords, ZeroSlot } from "seaport-types/src/lib/ConsiderationConstants.sol"; library GPv2EIP1271 { bytes4 internal constant MAGICVALUE = 0x1626ba7e; @@ -32,6 +37,7 @@ contract AccountBulkOrderSigTest is BaseTest { // Target contracts EntryPoint private entrypoint; AccountFactory private accountFactory; + ConduitController private conduitController; Seaport private seaport; // Signer @@ -162,7 +168,8 @@ contract AccountBulkOrderSigTest is BaseTest { // deploy account factory accountFactory = new AccountFactory(deployer, IEntryPoint(payable(address(entrypoint)))); // deploy seaport contract - seaport = new Seaport(address(new ConduitController())); + conduitController = new ConduitController(); + seaport = new Seaport(address(conduitController)); bytes memory initCallData = abi.encodeWithSignature("createAccount(address,bytes)", accountAdmin, bytes("")); bytes memory initCode = abi.encodePacked(abi.encodePacked(address(accountFactory)), initCallData); @@ -196,7 +203,7 @@ contract AccountBulkOrderSigTest is BaseTest { // The other order components can remain empty. EIP712MerkleTree merkleTree = new EIP712MerkleTree(); - (bytes memory packedSignature, bytes32 digest) = merkleTree.signBulkOrder( + bytes memory packedSignature = merkleTree.signBulkOrder( ConsiderationInterface(address(seaport)), accountAdminPKey, orderComponents, @@ -204,21 +211,12 @@ contract AccountBulkOrderSigTest is BaseTest { false ); - Order memory order = Order({ parameters: baseOrderParameters, signature: abi.encode(packedSignature, digest) }); + Order memory order = Order({ + parameters: baseOrderParameters, + signature: abi.encode(packedSignature, baseOrderParameters, seaport.getCounter(accountAdmin)) + }); assertEq(packedSignature.length, 132); - // vm.expectRevert("ECDSA: invalid signature length"); - // 0x882f38f087adb31c0a3f7b96bec402664a3e52b748dbf635ecaa5f719df04ec81fd442cdaae162d152c21f866f5b09e097f561f7db6d1020b0a8c72c3ff36fb41c - // 0x882f38f087adb31c0a3f7b96bec402664a3e52b748dbf635ecaa5f719df04ec81fd442cdaae162d152c21f866f5b09e097f561f7db6d1020b0a8c72c3ff36fb41c - // 0x882f38f087adb31c0a3f7b96bec402664a3e52b748dbf635ecaa5f719df04ec81fd442cdaae162d152c21f866f5b09e097f561f7db6d1020b0a8c72c3ff36fb41c00000006bfdd4fee487c47799fd9aa57225e03268298d2983ff74cbab178665fab33ead34b12e74ee846c338466455cad0c77d7d37d1f8072d72ed279c9c9e7f80a2b5 - - // 0x988496fb495acac726f98c32c7d74b1389f7c8cb18fa0be785e9cc5826d5fe57 - // 0x988496fb495acac726f98c32c7d74b1389f7c8cb18fa0be785e9cc5826d5fe57 -- digest - // 0x26fba4b6e6131cf86f3aa79d8968d0152ee9171a95c60fecd5b5a2aa1158a4ff -- originalDigest - - // 0x376ca148aa5b65f07b5dc48dac6cc1957266d972912bca47163071c7eca58725 -- bulkOrderHash in EIP712MerkleTree.sol - // 0xc2bbd323938bf2d6e379be48b82c7a8fe220c804b7fe1160f5f1621fe3e9eabb -- order hash - // 0x376ca148aa5b65f07b5dc48dac6cc1957266d972912bca47163071c7eca58725 -- order hash modified seaport.fulfillOrder{ value: 1 }(order, bytes32(0)); } } diff --git a/src/test/seaport/EIP712MerkleTree.sol b/src/test/seaport/EIP712MerkleTree.sol index 6eb43e6c7..6c7b1fc84 100644 --- a/src/test/seaport/EIP712MerkleTree.sol +++ b/src/test/seaport/EIP712MerkleTree.sol @@ -3,15 +3,15 @@ pragma solidity ^0.8.17; import { MurkyBase } from "murky/common/MurkyBase.sol"; -import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; +import { TypehashDirectory } from "./TypehashDirectory.sol"; import { Test } from "forge-std/Test.sol"; -import { OrderComponents } from "seaport-sol/src/SeaportStructs.sol"; +import { ConsiderationInterface } from "seaport-types/src/interfaces/ConsiderationInterface.sol"; -import { SeaportInterface } from "seaport-sol/src/SeaportInterface.sol"; +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; -import { TypehashDirectory } from "./TypehashDirectory.sol"; +import { OrderComponents } from "seaport-types/src/lib/ConsiderationStructs.sol"; /** * @dev Seaport doesn't sort leaves when hashing for bulk orders, but Murky @@ -45,12 +45,12 @@ contract EIP712MerkleTree is Test { * into the tree to make the length a power of 2. */ function signBulkOrder( - SeaportInterface consideration, + ConsiderationInterface consideration, uint256 privateKey, OrderComponents[] memory orderComponents, uint24 orderIndex, bool useCompact2098 - ) public view returns (bytes memory packedSignature, bytes32 bulkOrderHash) { + ) public view returns (bytes memory) { // cache the hash of an empty order components struct to fill out any // nodes required to make the length a power of 2 bytes32 emptyComponentsHash = consideration.getOrderHash(emptyOrderComponents); @@ -85,15 +85,7 @@ contract EIP712MerkleTree is Test { bytes32[] memory proof = merkle.getProof(leaves, orderIndex); bytes32 root = merkle.getRoot(leaves); - (packedSignature, bulkOrderHash) = _getSignature( - consideration, - privateKey, - bulkOrderTypehash, - root, - proof, - orderIndex, - useCompact2098 - ); + return _getSignature(consideration, privateKey, bulkOrderTypehash, root, proof, orderIndex, useCompact2098); } /** @@ -109,30 +101,29 @@ contract EIP712MerkleTree is Test { } function _getSignature( - SeaportInterface consideration, + ConsiderationInterface consideration, uint256 privateKey, bytes32 bulkOrderTypehash, bytes32 root, bytes32[] memory proof, uint24 orderIndex, bool useCompact2098 - ) internal view returns (bytes memory, bytes32) { + ) internal view returns (bytes memory) { + // bulkOrder hash is keccak256 of the specific bulk order typehash and + // the merkle root of the order hashes + bytes32 bulkOrderHash = keccak256(abi.encode(bulkOrderTypehash, root)); + // get domain separator from the particular seaport instance (, bytes32 domainSeparator, ) = consideration.information(); // declare out here to avoid stack too deep errors bytes memory signature; // avoid stacc 2 thicc - - // bulkOrder hash is keccak256 of the specific bulk order typehash and - // the merkle root of the order hashes - // bytes32 bulkOrderHash = keccak256(abi.encode(bulkOrderTypehash, root)); - bytes32 digest = keccak256( - abi.encodePacked(bytes2(0x1901), domainSeparator, keccak256(abi.encode(bulkOrderTypehash, root))) - ); - { - (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign( + privateKey, + keccak256(abi.encodePacked(bytes2(0x1901), domainSeparator, bulkOrderHash)) + ); // if useCompact2098 is true, encode yParity (v) into s if (useCompact2098) { uint256 yParity = (v == 27) ? 0 : 1; @@ -149,6 +140,6 @@ contract EIP712MerkleTree is Test { // orderIndex will be the next 3 bytes // then proof will be each element one after another; its offset and // length will not be encoded - return (abi.encodePacked(signature, orderIndex, proof), digest); + return abi.encodePacked(signature, orderIndex, proof); } } From bd11c73fca8ea04ef1c70b977849f67f42bcba68 Mon Sep 17 00:00:00 2001 From: Krishang Date: Fri, 23 Feb 2024 21:24:46 +0530 Subject: [PATCH 06/12] Create SeaportOrderEIP1271 implementation and revert Account.sol changes --- contracts/extension/SeaportOrderEIP1271.sol | 102 ++++++++++++++++++ .../SeaportOrderParser.sol | 0 .../account/non-upgradeable/Account.sol | 41 +------ .../utils/AABenchmarkArtifacts.sol | 4 +- 4 files changed, 107 insertions(+), 40 deletions(-) create mode 100644 contracts/extension/SeaportOrderEIP1271.sol rename contracts/{prebuilts/account/non-upgradeable => extension}/SeaportOrderParser.sol (100%) diff --git a/contracts/extension/SeaportOrderEIP1271.sol b/contracts/extension/SeaportOrderEIP1271.sol new file mode 100644 index 000000000..6b1ba8fb1 --- /dev/null +++ b/contracts/extension/SeaportOrderEIP1271.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.11; + +import { ERC1271 } from "../eip/ERC1271.sol"; +import { SeaportOrderParser } from "./SeaportOrderParser.sol"; +import { OrderParameters } from "seaport-types/src/lib/ConsiderationStructs.sol"; +import { IAccountPermissions, AccountPermissionsStorage, EnumerableSet, ECDSA } from "./upgradeable/AccountPermissions.sol"; + +contract SeaportOrderEIP1271 is SeaportOrderParser, ERC1271 { + using ECDSA for bytes32; + using EnumerableSet for EnumerableSet.AddressSet; + + bytes32 private constant MSG_TYPEHASH = keccak256("AccountMessage(bytes message)"); + bytes32 private constant TYPEHASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + bytes32 private immutable HASHED_NAME = keccak256("Account"); + bytes32 private immutable HASHED_VERSION = keccak256("1"); + + /// @notice See EIP-1271 + function isValidSignature( + bytes32 _message, + bytes memory _signature + ) public view virtual override returns (bytes4 magicValue) { + bytes32 targetDigest; + bytes memory targetSig; + + // Handle OpenSea bulk order signatures that are >65 bytes in length. + if (_signature.length > 65) { + // Decode packed signature and order parameters. + (bytes memory extractedPackedSig, OrderParameters memory orderParameters, uint256 counter) = abi.decode( + _signature, + (bytes, OrderParameters, uint256) + ); + + // Verify that the original digest matches the digest built with order parameters. + bytes32 domainSeparator = _buildDomainSeparator(msg.sender); + bytes32 orderHash = _deriveOrderHash(orderParameters, counter); + + require( + _deriveEIP712Digest(domainSeparator, orderHash) == _message, + "Seaport: order hash does not match the provided message." + ); + + // Build bulk signature digest + targetDigest = _deriveEIP712Digest(domainSeparator, _computeBulkOrderProof(extractedPackedSig, orderHash)); + + // Extract the signature, which is the first 65 bytes + targetSig = new bytes(65); + for (uint i = 0; i < 65; i++) { + targetSig[i] = extractedPackedSig[i]; + } + } else { + targetDigest = getMessageHash(abi.encode(_message)); + targetSig = _signature; + } + + address signer = targetDigest.recover(targetSig); + AccountPermissionsStorage.Data storage data = AccountPermissionsStorage.data(); + + if (data.isAdmin[signer]) { + return MAGICVALUE; + } + + address caller = msg.sender; + EnumerableSet.AddressSet storage approvedTargets = data.approvedTargets[signer]; + + require( + approvedTargets.contains(caller) || (approvedTargets.length() == 1 && approvedTargets.at(0) == address(0)), + "Account: caller not approved target." + ); + + if (isActiveSigner(signer)) { + magicValue = MAGICVALUE; + } + } + + /** + * @notice Returns the hash of message that should be signed for EIP1271 verification. + * @param message Message to be hashed i.e. `keccak256(abi.encode(data))` + * @return Hashed message + */ + function getMessageHash(bytes memory message) public view returns (bytes32) { + bytes32 messageHash = keccak256(abi.encode(MSG_TYPEHASH, keccak256(message))); + return keccak256(abi.encodePacked("\x19\x01", _buildDomainSeparator(), messageHash)); + } + + /// @notice Returns whether the given account is an active signer on the account. + function isActiveSigner(address signer) public view returns (bool) { + IAccountPermissions.SignerPermissionsStatic memory permissions = AccountPermissionsStorage + .data() + .signerPermissions[signer]; + + return + permissions.startTimestamp <= block.timestamp && + block.timestamp < permissions.endTimestamp && + AccountPermissionsStorage.data().approvedTargets[signer].length() > 0; + } + + function _buildDomainSeparator() private view returns (bytes32) { + return keccak256(abi.encode(TYPEHASH, HASHED_NAME, HASHED_VERSION, block.chainid, address(this))); + } +} diff --git a/contracts/prebuilts/account/non-upgradeable/SeaportOrderParser.sol b/contracts/extension/SeaportOrderParser.sol similarity index 100% rename from contracts/prebuilts/account/non-upgradeable/SeaportOrderParser.sol rename to contracts/extension/SeaportOrderParser.sol diff --git a/contracts/prebuilts/account/non-upgradeable/Account.sol b/contracts/prebuilts/account/non-upgradeable/Account.sol index 2234c28d1..adc4bb3e3 100644 --- a/contracts/prebuilts/account/non-upgradeable/Account.sol +++ b/contracts/prebuilts/account/non-upgradeable/Account.sol @@ -20,9 +20,6 @@ import "../utils/Helpers.sol"; import "../../../external-deps/openzeppelin/utils/cryptography/ECDSA.sol"; import "../utils/BaseAccountFactory.sol"; -import { OrderParameters } from "seaport-types/src/lib/ConsiderationStructs.sol"; -import { SeaportOrderParser } from "./SeaportOrderParser.sol"; - // $$\ $$\ $$\ $$\ $$\ // $$ | $$ | \__| $$ | $$ | // $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\ @@ -32,7 +29,7 @@ import { SeaportOrderParser } from "./SeaportOrderParser.sol"; // \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ | // \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/ -contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC1155Holder, SeaportOrderParser { +contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC1155Holder { using ECDSA for bytes32; using EnumerableSet for EnumerableSet.AddressSet; @@ -70,40 +67,8 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115 bytes32 _message, bytes memory _signature ) public view virtual override returns (bytes4 magicValue) { - bytes32 targetDigest; - bytes memory targetSig; - - // Handle OpenSea bulk order signatures that are >65 bytes in length. - if (_signature.length > 65) { - // Decode packed signature and order parameters. - (bytes memory extractedPackedSig, OrderParameters memory orderParameters, uint256 counter) = abi.decode( - _signature, - (bytes, OrderParameters, uint256) - ); - - // Verify that the original digest matches the digest built with order parameters. - bytes32 domainSeparator = _buildDomainSeparator(msg.sender); - bytes32 orderHash = _deriveOrderHash(orderParameters, counter); - - require( - _deriveEIP712Digest(domainSeparator, orderHash) == _message, - "Seaport: order hash does not match the provided message." - ); - - // Build bulk signature digest - targetDigest = _deriveEIP712Digest(domainSeparator, _computeBulkOrderProof(extractedPackedSig, orderHash)); - - // Extract the signature, which is the first 65 bytes - targetSig = new bytes(65); - for (uint i = 0; i < 65; i++) { - targetSig[i] = extractedPackedSig[i]; - } - } else { - targetDigest = getMessageHash(abi.encode(_message)); - targetSig = _signature; - } - - address signer = targetDigest.recover(targetSig); + bytes32 messageHash = getMessageHash(abi.encode(_message)); + address signer = messageHash.recover(_signature); if (isAdmin(signer)) { return MAGICVALUE; diff --git a/src/test/smart-wallet/utils/AABenchmarkArtifacts.sol b/src/test/smart-wallet/utils/AABenchmarkArtifacts.sol index 6fa69d620..f77fcb5ec 100644 --- a/src/test/smart-wallet/utils/AABenchmarkArtifacts.sol +++ b/src/test/smart-wallet/utils/AABenchmarkArtifacts.sol @@ -9,6 +9,6 @@ interface ThirdwebAccount { } address constant THIRDWEB_ACCOUNT_FACTORY_ADDRESS = 0x2e234DAe75C793f67A35089C9d99245E1C58470b; address constant THIRDWEB_ACCOUNT_IMPL_ADDRESS = 0xffD4505B3452Dc22f8473616d50503bA9E1710Ac; -bytes constant THIRDWEB_ACCOUNT_FACTORY_BYTECODE = hex"608060405234801561001057600080fd5b50600436106101285760003560e01c806308e93d0a1461012d5780630b61e12b1461014b5780630e6254fd1461016057806311464fbe14610173578063248a9ca3146101b25780632f2ff15d146101d357806336568abe146101e657806358451f97146101f957806383a03f8c146102015780638878ed33146102145780639010d07c1461022757806391d148541461023a5780639387a3801461025d578063938e3d7b14610270578063a217fddf14610283578063a32fa5b31461028b578063a65d69d41461029e578063ac9650d8146102c5578063c3c5a547146102e5578063ca15c873146102f8578063d547741f1461030b578063d8fd8f441461031e578063e68a7c3b14610331578063e8a3d48514610344575b600080fd5b610135610359565b6040516101429190611945565b60405180910390f35b61015e6101593660046119ae565b61036a565b005b61013561016e3660046119d8565b61040b565b61019a7f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac81565b6040516001600160a01b039091168152602001610142565b6101c56101c03660046119f3565b610435565b604051908152602001610142565b61015e6101e1366004611a0c565b610453565b61015e6101f4366004611a0c565b6104fd565b6101c561055c565b61015e61020f3660046119f3565b610568565b61019a610222366004611a38565b6105b6565b61019a610235366004611aba565b610630565b61024d610248366004611a0c565b61073e565b6040519015158152602001610142565b61015e61026b3660046119ae565b610772565b61015e61027e366004611af2565b610809565b6101c5600081565b61024d610299366004611a0c565b61085a565b61019a7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278981565b6102d86102d3366004611ba2565b6108bd565b6040516101429190611c66565b61024d6102f33660046119d8565b610a19565b6101c56103063660046119f3565b610a25565b61015e610319366004611a0c565b610ac2565b61019a61032c366004611a38565b610acd565b61013561033f366004611aba565b610c18565b61034c610d49565b6040516101429190611cca565b60606103656000610de1565b905090565b336103758183610dee565b61039a5760405162461bcd60e51b815260040161039190611cdd565b60405180910390fd5b6001600160a01b03831660009081526002602052604081206103bc9083610e32565b9050801561040557836001600160a01b0316826001600160a01b03167f12146497b3b826918ec47f0cac7272a09ed06b30c16c030e99ec48ff5dd60b4760405160405180910390a35b50505050565b6001600160a01b038116600090815260026020526040902060609061042f90610de1565b92915050565b600061043f610e47565b600092835260010160205250604090205490565b61047761045e610e47565b6000848152600191909101602052604090205433610e6b565b61047f610e47565b6000838152602091825260408082206001600160a01b0385168352909252205460ff16156104ef5760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610391565b6104f98282610ef0565b5050565b336001600160a01b038216146105525760405162461bcd60e51b815260206004820152601a60248201527921b0b71037b7363c903932b737bab731b2903337b91039b2b63360311b6044820152606401610391565b6104f98282610f04565b60006103656000610f18565b336105738183610dee565b61058f5760405162461bcd60e51b815260040161039190611cdd565b61059a600082610e32565b6104f95760405162461bcd60e51b815260040161039190611d14565b6000806105f98585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f2292505050565b90506106257f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac82610f55565b9150505b9392505050565b60008061063b610fb5565b600085815260209190915260408120549150805b82811015610735576000610661610fb5565b60008881526020918252604080822085835260010190925220546001600160a01b0316146106d9578482036106c757610698610fb5565b600087815260209182526040808220938252600190930190915220546001600160a01b0316925061042f915050565b6106d2600183611d74565b9150610723565b6106e486600061073e565b801561071057506106f3610fb5565b600087815260209182526040808220828052600201909252205481145b1561072357610720600183611d74565b91505b61072e600182611d74565b905061064f565b50505092915050565b6000610748610e47565b6000938452602090815260408085206001600160a01b039490941685529290525090205460ff1690565b3361077d8183610dee565b6107995760405162461bcd60e51b815260040161039190611cdd565b6001600160a01b03831660009081526002602052604081206107bb9083610fbf565b9050801561040557836001600160a01b0316826001600160a01b03167f98d1ebbe00ae92a5de96a0f49742a8afa89f42363592bc2e7cfaaed68b45e7a660405160405180910390a350505050565b610811610fd4565b61084e5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610391565b61085781610fe0565b50565b6000610864610e47565b600084815260209182526040808220828052909252205460ff166108b45761088a610e47565b6000848152602091825260408082206001600160a01b0386168352909252205460ff16905061042f565b50600192915050565b6060816001600160401b038111156108d7576108d7611adc565b60405190808252806020026020018201604052801561090a57816020015b60608152602001906001900390816108f55790505b509050336000805b848110156107355781156109915761096f3087878481811061093657610936611d87565b90506020028101906109489190611d9d565b8660405160200161095b93929190611dea565b6040516020818303038152906040526110c7565b84828151811061098157610981611d87565b6020026020010181905250610a11565b6109f3308787848181106109a7576109a7611d87565b90506020028101906109b99190611d9d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506110c792505050565b848281518110610a0557610a05611d87565b60200260200101819052505b600101610912565b600061042f81836110ec565b600080610a30610fb5565b6000848152602091909152604081205491505b81811015610a9d576000610a55610fb5565b60008681526020918252604080822085835260010190925220546001600160a01b031614610a8b57610a88600184611d74565b92505b610a96600182611d74565b9050610a43565b50610aa983600061073e565b15610abc57610ab9600183611d74565b91505b50919050565b61055261045e610e47565b6000807f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac90506000610b358686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f2292505050565b90506000610b438383610f55565b90506001600160a01b0381163b15610b5f579250610629915050565b610b69838361110e565b9050336001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27891614610bc257610ba6600082610e32565b610bc25760405162461bcd60e51b815260040161039190611d14565b610bce818888886111a5565b866001600160a01b0316816001600160a01b03167fac631f3001b55ea1509cf3d7e74898f85392a61a76e8149181ae1259622dabc860405160405180910390a39695505050505050565b60608183108015610c325750610c2e6000610f18565b8211155b610c8a5760405162461bcd60e51b815260206004820152602360248201527f426173654163636f756e74466163746f72793a20696e76616c696420696e646960448201526263657360e81b6064820152608401610391565b6000610c968484611e0b565b9050610ca28484611e0b565b6001600160401b03811115610cb957610cb9611adc565b604051908082528060200260200182016040528015610ce2578160200160208202803683370190505b50915060005b81811015610d4157610d05610cfd8683611d74565b60009061120d565b838281518110610d1757610d17611d87565b6001600160a01b0390921660209283029190910190910152610d3a600182611d74565b9050610ce8565b505092915050565b6060610d53611219565b8054610d5e90611e1e565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8a90611e1e565b8015610dd75780601f10610dac57610100808354040283529160200191610dd7565b820191906000526020600020905b815481529060010190602001808311610dba57829003601f168201915b5050505050905090565b606060006106298361123d565b600080610e1b7f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac84610f55565b6001600160a01b0385811691161491505092915050565b6000610629836001600160a01b038416611299565b7f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e50090565b610e73610e47565b6000838152602091825260408082206001600160a01b0385168352909252205460ff166104f957610eae816001600160a01b031660146112e8565b610eb98360206112e8565b604051602001610eca929190611e52565b60408051601f198184030181529082905262461bcd60e51b825261039191600401611cca565b610efa8282611483565b6104f982826114ec565b610f0e82826115ab565b6104f98282611614565b600061042f825490565b60008282604051602001610f37929190611ebf565b60405160208183030381529060405280519060200120905092915050565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c82012060788201526055604390910120600090610629565b60006103656116a3565b6000610629836001600160a01b038416611705565b6000610365813361073e565b6000610fea611219565b8054610ff590611e1e565b80601f016020809104026020016040519081016040528092919081815260200182805461102190611e1e565b801561106e5780601f106110435761010080835404028352916020019161106e565b820191906000526020600020905b81548152906001019060200180831161105157829003601f168201915b505050505090508161107e611219565b906110899082611f34565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a1681836040516110bb929190611ff3565b60405180910390a15050565b606061062983836040518060600160405280602781526020016120b9602791396117f8565b6001600160a01b03811660009081526001830160205260408120541515610629565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661042f5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610391565b60405163347d5e2560e21b81526001600160a01b0385169063d1f57894906111d590869086908690600401612018565b600060405180830381600087803b1580156111ef57600080fd5b505af1158015611203573d6000803e3d6000fd5b5050505050505050565b60006106298383611870565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b60608160000180548060200260200160405190810160405280929190818152602001828054801561128d57602002820191906000526020600020905b815481526020019060010190808311611279575b50505050509050919050565b60008181526001830160205260408120546112e05750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561042f565b50600061042f565b606060006112f7836002612058565b611302906002611d74565b6001600160401b0381111561131957611319611adc565b6040519080825280601f01601f191660200182016040528015611343576020820181803683370190505b509050600360fc1b8160008151811061135e5761135e611d87565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061138d5761138d611d87565b60200101906001600160f81b031916908160001a90535060006113b1846002612058565b6113bc906001611d74565b90505b6001811115611434576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106113f0576113f0611d87565b1a60f81b82828151811061140657611406611d87565b60200101906001600160f81b031916908160001a90535060049490941c9361142d8161206f565b90506113bf565b5083156106295760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610391565b600161148d610e47565b6000848152602091825260408082206001600160a01b0386168084529352808220805460ff1916941515949094179093559151339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60006114f6610fb5565b6000848152602091909152604090205490506001611512610fb5565b6000858152602091909152604081208054909190611531908490611d74565b90915550829050611540610fb5565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b039290921691909117905580611580610fb5565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b6115b58282610e6b565b6115bd610e47565b6000838152602091825260408082206001600160a01b0385168084529352808220805460ff191690555133929185917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600061161e610fb5565b6000848152602091825260408082206001600160a01b03861683526002019092522054905061164b610fb5565b6000848152602091825260408082208483526001019092522080546001600160a01b031916905561167a610fb5565b6000938452602090815260408085206001600160a01b0390941685526002909301905250812055565b60008060ff196116d460017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c611e0b565b6040516020016116e691815260200190565b60408051601f1981840301815291905280516020909101201692915050565b600081815260018301602052604081205480156117ee576000611729600183611e0b565b855490915060009061173d90600190611e0b565b90508181146117a257600086600001828154811061175d5761175d611d87565b906000526020600020015490508087600001848154811061178057611780611d87565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117b3576117b3612086565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061042f565b600091505061042f565b6060600080856001600160a01b031685604051611815919061209c565b600060405180830381855af49150503d8060008114611850576040519150601f19603f3d011682016040523d82523d6000602084013e611855565b606091505b50915091506118668683838761189a565b9695505050505050565b600082600001828154811061188757611887611d87565b9060005260206000200154905092915050565b60608315611909578251600003611902576001600160a01b0385163b6119025760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610391565b5081611913565b611913838361191b565b949350505050565b81511561192b5781518083602001fd5b8060405162461bcd60e51b81526004016103919190611cca565b6020808252825182820181905260009190848201906040850190845b818110156119865783516001600160a01b031683529284019291840191600101611961565b50909695505050505050565b80356001600160a01b03811681146119a957600080fd5b919050565b600080604083850312156119c157600080fd5b6119ca83611992565b946020939093013593505050565b6000602082840312156119ea57600080fd5b61062982611992565b600060208284031215611a0557600080fd5b5035919050565b60008060408385031215611a1f57600080fd5b82359150611a2f60208401611992565b90509250929050565b600080600060408486031215611a4d57600080fd5b611a5684611992565b925060208401356001600160401b0380821115611a7257600080fd5b818601915086601f830112611a8657600080fd5b813581811115611a9557600080fd5b876020828501011115611aa757600080fd5b6020830194508093505050509250925092565b60008060408385031215611acd57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b600060208284031215611b0457600080fd5b81356001600160401b0380821115611b1b57600080fd5b818401915084601f830112611b2f57600080fd5b813581811115611b4157611b41611adc565b604051601f8201601f19908116603f01168101908382118183101715611b6957611b69611adc565b81604052828152876020848701011115611b8257600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060208385031215611bb557600080fd5b82356001600160401b0380821115611bcc57600080fd5b818501915085601f830112611be057600080fd5b813581811115611bef57600080fd5b8660208260051b8501011115611c0457600080fd5b60209290920196919550909350505050565b60005b83811015611c31578181015183820152602001611c19565b50506000910152565b60008151808452611c52816020860160208601611c16565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015611cbd57603f19888603018452611cab858351611c3a565b94509285019290850190600101611c8f565b5092979650505050505050565b6020815260006106296020830184611c3a565b6020808252601f908201527f4163636f756e74466163746f72793a206e6f7420616e206163636f756e742e00604082015260600190565b6020808252602a908201527f4163636f756e74466163746f72793a206163636f756e7420616c7265616479206040820152691c9959da5cdd195c995960b21b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561042f5761042f611d5e565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112611db457600080fd5b8301803591506001600160401b03821115611dce57600080fd5b602001915036819003821315611de357600080fd5b9250929050565b8284823760609190911b6001600160601b0319169101908152601401919050565b8181038181111561042f5761042f611d5e565b600181811c90821680611e3257607f821691505b602082108103610abc57634e487b7160e01b600052602260045260246000fd5b7402832b936b4b9b9b4b7b7399d1030b1b1b7bab73a1605d1b815260008351611e82816015850160208801611c16565b7001034b99036b4b9b9b4b733903937b6329607d1b6015918401918201528351611eb3816026840160208801611c16565b01602601949350505050565b6001600160a01b038316815260406020820181905260009061191390830184611c3a565b601f821115611f2f576000816000526020600020601f850160051c81016020861015611f0c5750805b601f850160051c820191505b81811015611f2b57828155600101611f18565b5050505b505050565b81516001600160401b03811115611f4d57611f4d611adc565b611f6181611f5b8454611e1e565b84611ee3565b602080601f831160018114611f965760008415611f7e5750858301515b600019600386901b1c1916600185901b178555611f2b565b600085815260208120601f198616915b82811015611fc557888601518255948401946001909101908401611fa6565b5085821015611fe35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6040815260006120066040830185611c3a565b82810360208401526106258185611c3a565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761042f5761042f611d5e565b60008161207e5761207e611d5e565b506000190190565b634e487b7160e01b600052603160045260246000fd5b600082516120ae818460208701611c16565b919091019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220dcd476482fb1b0a1a789554876c49403bc9eabddddfead79e8de64f2f34d2ea864736f6c63430008170033"; -bytes constant THIRDWEB_ACCOUNT_IMPL_BYTECODE = hex"60806040526004361061014b5760003560e01c806301ffc9a7146101575780630a1028c41461018c578063150b7a02146101ba5780631626ba7e146101f35780631dd756c51461021357806324d7806c146102335780633a871cdd1461025357806347e1da2a146102735780634a58db19146102955780634d44560d1461029d5780635892e236146102bd5780637dff5a79146102dd5780638b52d723146102fd578063938e3d7b1461031f578063a9082d841461033f578063ac9650d81461037e578063b0d691fe146103ab578063b61d27f6146103cd578063b76464d5146103ed578063bc197c811461040d578063c45a015514610439578063d087d2881461046d578063d1f5789414610482578063d42f2f35146104a2578063e8a3d485146104b7578063e9523c97146104d9578063f15d424e146104fb578063f23a6e611461052857600080fd5b3661015257005b600080fd5b34801561016357600080fd5b50610177610172366004612e42565b610554565b60405190151581526020015b60405180910390f35b34801561019857600080fd5b506101ac6101a7366004612f37565b61059a565b604051908152602001610183565b3480156101c657600080fd5b506101da6101d5366004612f90565b61063e565b6040516001600160e01b03199091168152602001610183565b3480156101ff57600080fd5b506101da61020e366004612ffb565b61064f565b34801561021f57600080fd5b5061017761022e36600461305a565b610840565b34801561023f57600080fd5b5061017761024e36600461309f565b610b04565b34801561025f57600080fd5b506101ac61026e3660046130bc565b610b33565b34801561027f57600080fd5b5061029361028e36600461314d565b610b59565b005b610293610cc0565b3480156102a957600080fd5b506102936102b83660046131e6565b610d28565b3480156102c957600080fd5b506102936102d8366004613253565b610d9b565b3480156102e957600080fd5b506101776102f836600461309f565b611158565b34801561030957600080fd5b50610312611211565b6040516101839190613366565b34801561032b57600080fd5b5061029361033a3660046133ca565b611458565b34801561034b57600080fd5b5061035f61035a366004613253565b6114a9565b6040805192151583526001600160a01b03909116602083015201610183565b34801561038a57600080fd5b5061039e610399366004613412565b611500565b60405161018391906134a3565b3480156103b757600080fd5b506103c0611665565b60405161018391906134fa565b3480156103d957600080fd5b506102936103e836600461350e565b6116ae565b3480156103f957600080fd5b5061029361040836600461309f565b61173e565b34801561041957600080fd5b506101da6104283660046135f6565b63bc197c8160e01b95945050505050565b34801561044557600080fd5b506103c07f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b81565b34801561047957600080fd5b506101ac611770565b34801561048e57600080fd5b5061029361049d3660046136a3565b6117f0565b3480156104ae57600080fd5b506103126119a8565b3480156104c357600080fd5b506104cc611b19565b60405161018391906136ea565b3480156104e557600080fd5b506104ee611bb1565b60405161018391906136fd565b34801561050757600080fd5b5061051b61051636600461309f565b611bc3565b604051610183919061374a565b34801561053457600080fd5b506101da61054336600461375d565b63f23a6e6160e01b95945050505050565b60006001600160e01b03198216630271189760e51b148061058557506001600160e01b03198216630a85bd0160e11b145b80610594575061059482611c9b565b92915050565b6000807f82cac545155fcbf147f2a9013809613677ac7d65498556e6d19ce43bcbf6c28483805190602001206040516020016105e0929190918252602082015260400190565b604051602081830303815290604052805190602001209050610600611cd0565b60405161190160f01b602082015260228101919091526042810182905260620160405160208183030381529060405280519060200120915050919050565b630a85bd0160e11b5b949350505050565b6000806060604184511115610700576000808580602001905181019061067591906137c5565b604080516041808252608082019092529196509193508592509060208201818036833701905050925060005b60418110156106f8578281815181106106bc576106bc613845565b602001015160f81c60f81b8482815181106106d9576106d9613845565b60200101906001600160f81b031916908160001a9053506001016106a1565b50505061072d565b61072a8560405160200161071691815260200190565b60405160208183030381529060405261059a565b91505b60006107398383611df7565b905061074481610b04565b1561075c5750630b135d3f60e11b9250610594915050565b336000610767611e1b565b6001600160a01b038416600090815260069190910160205260409020905061078f8183611e3f565b806107bf575061079e81611e61565b60011480156107bf575060006107b48282611e6b565b6001600160a01b0316145b61081c5760405162461bcd60e51b8152602060048201526024808201527f4163636f756e743a2063616c6c6572206e6f7420617070726f7665642074617260448201526333b2ba1760e11b60648201526084015b60405180910390fd5b61082583611158565b1561083557630b135d3f60e11b95505b505050505092915050565b600061084a611e1b565b6001600160a01b0384166000908152600491909101602052604090205460ff161561087757506001610594565b6000610881611e1b565b6001600160a01b0385166000908152600591909101602090815260408083208151606081018352815481526001909101546001600160801b0380821694830194909452600160801b90049092169082015291506108dc611e1b565b6006016000866001600160a01b03166001600160a01b0316815260200190815260200160002090504282602001516001600160801b0316118061092c575081604001516001600160801b03164210155b8061093d575061093b81611e61565b155b1561094d57600092505050610594565b600061096461095f606087018761385b565b611e77565b9050600061097183611e61565b6001148015610992575060006109878482611e6b565b6001600160a01b0316145b90506324f16c0560e11b6001600160e01b0319831601610a09576000806109c46109bf60608a018a61385b565b611eb1565b91509150826109ea576109d78583611e3f565b6109ea5760009650505050505050610594565b8551811115610a025760009650505050505050610594565b5050610af7565b635c0f12eb60e11b6001600160e01b0319831601610aea57600080610a39610a3460608a018a61385b565b611f16565b509150915082610a995760005b8251811015610a9757610a7b838281518110610a6457610a64613845565b602002602001015187611e3f90919063ffffffff16565b610a8f576000975050505050505050610594565b600101610a46565b505b60005b8251811015610ae257818181518110610ab757610ab7613845565b602002602001015187600001511015610ada576000975050505050505050610594565b600101610a9c565b505050610af7565b6000945050505050610594565b5060019695505050505050565b6000610b0e611e1b565b6001600160a01b03909216600090815260049290920160205250604090205460ff1690565b6000610b3d611f63565b610b478484611fcc565b9050610b5282612111565b9392505050565b610b61611665565b6001600160a01b0316336001600160a01b03161480610b845750610b8433610b04565b610ba05760405162461bcd60e51b8152600401610813906138a1565b610ba861215e565b8481148015610bb657508483145b610c025760405162461bcd60e51b815260206004820152601d60248201527f4163636f756e743a2077726f6e67206172726179206c656e677468732e0000006044820152606401610813565b60005b85811015610cb757610cae878783818110610c2257610c22613845565b9050602002016020810190610c37919061309f565b868684818110610c4957610c49613845565b90506020020135858585818110610c6257610c62613845565b9050602002810190610c74919061385b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061224492505050565b50600101610c05565b50505050505050565b610cc8611665565b6001600160a01b031663b760faf934306040518363ffffffff1660e01b8152600401610cf491906134fa565b6000604051808303818588803b158015610d0d57600080fd5b505af1158015610d21573d6000803e3d6000fd5b5050505050565b610d306122b5565b610d38611665565b6001600160a01b031663205c287883836040518363ffffffff1660e01b8152600401610d659291906138e2565b600060405180830381600087803b158015610d7f57600080fd5b505af1158015610d93573d6000803e3d6000fd5b505050505050565b6000610daa602085018561309f565b905042610dbd60e0860160c08701613912565b6001600160801b031611158015610dec5750610de0610100850160e08601613912565b6001600160801b031642105b610e225760405162461bcd60e51b8152602060048201526007602482015266085c195c9a5bd960ca1b6044820152606401610813565b600080610e308686866114a9565b9150915081610e6a5760405162461bcd60e51b8152600401610813906020808252600490820152632173696760e01b604082015260600190565b6001610e74611e1b565b610100880135600090815260079190910160209081526040808320805460ff1916941515949094179093559091610eb09190890190890161393e565b60ff161115610edd576000610ecb604088016020890161393e565b60ff166001149050610cb784826122f3565b610ee683610b04565b15610f1b5760405162461bcd60e51b815260206004820152600560248201526430b236b4b760d91b6044820152606401610813565b610f3083610f27611e1b565b600201906123c8565b50604051806060016040528087606001358152602001876080016020810190610f599190613912565b6001600160801b03168152602001610f7760c0890160a08a01613912565b6001600160801b03169052610f8a611e1b565b6001600160a01b03851660009081526005919091016020908152604080832084518155918401519301516001600160801b03908116600160801b02931692909217600190920191909155611000610fdf611e1b565b6001600160a01b0386166000908152600691909101602052604090206123dd565b805190915060005b8181101561106a5761105783828151811061102557611025613845565b6020026020010151611035611e1b565b6001600160a01b038916600090815260069190910160205260409020906123ea565b5061106360018261396f565b9050611008565b506110786040890189613982565b9050905060005b818110156110f9576110e661109760408b018b613982565b838181106110a7576110a7613845565b90506020020160208101906110bc919061309f565b6110c4611e1b565b6001600160a01b038916600090815260069190910160205260409020906123c8565b506110f260018261396f565b905061107f565b50611103886123ff565b846001600160a01b0316836001600160a01b03167ff21d10c26e35863a8df291aca54181ee8c4a3bc8e00246c3f7a5a14b69d826a78a6040516111469190613a5c565b60405180910390a35050505050505050565b600080611163611e1b565b6001600160a01b038416600090815260059190910160209081526040918290208251606081018452815481526001909101546001600160801b03808216938301849052600160801b909104169281019290925290915042108015906111d4575080604001516001600160801b031642105b8015610b52575060006112096111e8611e1b565b6001600160a01b038616600090815260069190910160205260409020611e61565b119392505050565b60606000611228611220611e1b565b6002016123dd565b80519091506000805b828110156112b95761125b84828151811061124e5761124e613845565b6020026020010151611158565b15611272578161126a81613b47565b9250506112a7565b600084828151811061128657611286613845565b60200260200101906001600160a01b031690816001600160a01b0316815250505b6112b260018261396f565b9050611231565b50806001600160401b038111156112d2576112d2612e6c565b60405190808252806020026020018201604052801561130b57816020015b6112f8612df8565b8152602001906001900390816112f05790505b5093506000805b838110156114505760006001600160a01b031685828151811061133757611337613845565b60200260200101516001600160a01b03161461143e57600085828151811061136157611361613845565b602002602001015190506000611375611e1b565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a0810190945291835290925081016113df610fdf611e1b565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b031681525088858061141e90613b47565b96508151811061143057611430613845565b602002602001018190525050505b61144960018261396f565b9050611312565b505050505090565b611460612494565b61149d5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610813565b6114a6816124ac565b50565b6000806114bf6114b886612593565b85856126d7565b90506114c9611e1b565b6101008601356000908152600791909101602052604090205460ff161580156114f657506114f681610b04565b9150935093915050565b6060816001600160401b0381111561151a5761151a612e6c565b60405190808252806020026020018201604052801561154d57816020015b60608152602001906001900390816115385790505b509050336000805b8481101561165c5781156115d4576115b23087878481811061157957611579613845565b905060200281019061158b919061385b565b8660405160200161159e93929190613b60565b604051602081830303815290604052612729565b8482815181106115c4576115c4613845565b6020026020010181905250611654565b611636308787848181106115ea576115ea613845565b90506020028101906115fc919061385b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061272992505050565b84828151811061164857611648613845565b60200260200101819052505b600101611555565b50505092915050565b60008061167061274e565b546001600160a01b03169050801561168757919050565b7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278991505090565b6116b6611665565b6001600160a01b0316336001600160a01b031614806116d957506116d933610b04565b6116f55760405162461bcd60e51b8152600401610813906138a1565b6116fd61215e565b610d21848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061224492505050565b6117466122b5565b8061174f61274e565b80546001600160a01b0319166001600160a01b039290921691909117905550565b600061177a611665565b604051631aab3f0d60e11b8152306004820152600060248201526001600160a01b0391909116906335567e1a90604401602060405180830381865afa1580156117c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117eb9190613b81565b905090565b60006117fa612772565b5460ff169050600061180a612772565b54610100900460ff1690508015808015611827575060018360ff16105b80611846575061183630612796565b15801561184657508260ff166001145b6118a95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610813565b60016118b3612772565b805460ff191660ff9290921691909117905580156118ec5760016118d5612772565b80549115156101000261ff00199092169190911790555b61192c8686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506127a592505050565b61193461274e565b600101819055506119468660016122f3565b8015610d93576000611956612772565b80549115156101000261ff0019909216919091179055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b606060006119b7611220611e1b565b8051909150806001600160401b038111156119d4576119d4612e6c565b604051908082528060200260200182016040528015611a0d57816020015b6119fa612df8565b8152602001906001900390816119f25790505b50925060005b81811015611b13576000838281518110611a2f57611a2f613845565b602002602001015190506000611a43611e1b565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101611aad610fdf611e1b565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250868481518110611af257611af2613845565b60200260200101819052505050600181611b0c919061396f565b9050611a13565b50505090565b6060611b236127d8565b8054611b2e90613b9a565b80601f0160208091040260200160405190810160405280929190818152602001828054611b5a90613b9a565b8015611ba75780601f10611b7c57610100808354040283529160200191611ba7565b820191906000526020600020905b815481529060010190602001808311611b8a57829003601f168201915b5050505050905090565b60606117eb611bbe611e1b565b6123dd565b611bcb612df8565b6000611bd5611e1b565b6001600160a01b038416600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101611c60611c3f611e1b565b6001600160a01b0387166000908152600691909101602052604090206123dd565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250915050919050565b60006001600160e01b03198216630271189760e51b148061059457506301ffc9a760e01b6001600160e01b0319831614610594565b6000306001600160a01b037f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac16148015611d2957507f0000000000000000000000000000000000000000000000000000000000007a6946145b15611d5357507fbcdadf6444930a967ffda04923d78c49b3dd65df3ed39abb04a1e3eb1190553790565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527ff0729608244859f656d32ae4cbc6b0367695d68d8e941a28f5e2d33c6d5182dd828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000806000611e0685856127fc565b91509150611e1381612841565b509392505050565b7f3181e78fc1b109bc611fd2406150bf06e33faa75f71cba12c3e1fd670f2def0090565b6001600160a01b03811660009081526001830160205260408120541515610b52565b6000610594825490565b6000610b528383612986565b60006004821015611e9a5760405162461bcd60e51b815260040161081390613bce565b611ea8600460008486613bed565b610b5291613c17565b6000806044831015611ed55760405162461bcd60e51b815260040161081390613bce565b611ee3602460048587613bed565b810190611ef0919061309f565b9150611f00604460248587613bed565b810190611f0d9190613c47565b90509250929050565b606080806064841015611f3b5760405162461bcd60e51b815260040161081390613bce565b611f488460048188613bed565b810190611f559190613cdf565b919790965090945092505050565b611f6b611665565b6001600160a01b0316336001600160a01b031614611fca5760405162461bcd60e51b815260206004820152601c60248201527b1858d8dbdd5b9d0e881b9bdd08199c9bdb48115b9d1c9e541bda5b9d60221b6044820152606401610813565b565b7b0ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d05199960211b6000908152601c829052603c8120600061204a61200d61014087018761385b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611df79050565b90506120568186610840565b61206557600192505050610594565b600061206f611e1b565b6001600160a01b03929092166000908152600590920160209081526040808420815160608082018452825482526001909201546001600160801b0380821683870152600160801b8204908116928501929092528351928301845295825265ffffffffffff8087169483019490945292831691015260d09290921b6001600160d01b03191660a09290921b65ffffffffffff60a01b169190911795945050505050565b80156114a657604051600090339060001990849084818181858888f193505050503d8060008114610d21576040519150601f19603f3d011682016040523d82523d6000602084013e610d21565b60405163c3c5a54760e01b81527f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b906001600160a01b0382169063c3c5a547906121ac9030906004016134fa565b602060405180830381865afa1580156121c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ed9190613dc4565b6114a657806001600160a01b03166383a03f8c61220861274e565b600101546040518263ffffffff1660e01b815260040161222a91815260200190565b600060405180830381600087803b158015610d0d57600080fd5b60606000846001600160a01b031684846040516122619190613de6565b60006040518083038185875af1925050503d806000811461229e576040519150601f19603f3d011682016040523d82523d6000602084013e6122a3565b606091505b509250905080611e1357815160208301fd5b6122be33610b04565b611fca5760405162461bcd60e51b815260206004820152600660248201526510b0b236b4b760d11b6044820152606401610813565b6122fd82826129b0565b6001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b163b156123c457801561238c577f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b6001600160a01b0316630b61e12b8361236b61274e565b600101546040518363ffffffff1660e01b8152600401610d659291906138e2565b7f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b6001600160a01b0316639387a3808361236b61274e565b5050565b6000610b52836001600160a01b038416612a5f565b60606000610b5283612aae565b6000610b52836001600160a01b038416612b0a565b6001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b163b156114a6576001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b16630b61e12b61246b602084018461309f565b61247361274e565b600101546040518363ffffffff1660e01b815260040161222a9291906138e2565b600061249f33610b04565b806117eb57505030331490565b60006124b66127d8565b80546124c190613b9a565b80601f01602080910402602001604051908101604052809291908181526020018280546124ed90613b9a565b801561253a5780601f1061250f5761010080835404028352916020019161253a565b820191906000526020600020905b81548152906001019060200180831161251d57829003601f168201915b505050505090508161254a6127d8565b906125559082613e4f565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a168183604051612587929190613f0e565b60405180910390a15050565b60607f3fd4a1a1a267c84185e3b7eecd57c68783c0581d538b9d6e5f23e4670497c1e96125c3602084018461309f565b6125d3604085016020860161393e565b6125e06040860186613982565b6040516020016125f1929190613f3c565b60408051601f198184030181529190528051602090910120606086013561261e60a0880160808901613912565b61262e60c0890160a08a01613912565b61263e60e08a0160c08b01613912565b61264f6101008b0160e08c01613912565b60408051602081019a909a526001600160a01b039098169789019790975260ff9095166060880152608087019390935260a08601919091526001600160801b0390811660c086015290811660e0850152908116610100848101919091529116610120830152830135610140820152610160016040516020818303038152906040529050919050565b600061064783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250508751602089012061272392509050612bfd565b90611df7565b6060610b528383604051806060016040528060278152602001613fe260279139612c2a565b7f036f52c1827dab135f7fd44ca0bddde297e2f659c710e0ec53e975f22b54830090565b7f322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee030090565b6001600160a01b03163b151590565b600082826040516020016127ba929190613f7e565b60405160208183030381529060405280519060200120905092915050565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b60008082516041036128325760208301516040840151606085015160001a61282687828585612ca2565b9450945050505061283a565b506000905060025b9250929050565b600081600481111561285557612855613fa2565b0361285d5750565b600181600481111561287157612871613fa2565b036128b95760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401610813565b60028160048111156128cd576128cd613fa2565b0361291a5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610813565b600381600481111561292e5761292e613fa2565b036114a65760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610813565b600082600001828154811061299d5761299d613845565b9060005260206000200154905092915050565b806129b9611e1b565b6001600160a01b038416600090815260049190910160205260409020805460ff19169115159190911790558015612a02576129fc826129f6611e1b565b906123c8565b50612a16565b612a1482612a0e611e1b565b906123ea565b505b816001600160a01b03167f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a1113382604051612a53911515815260200190565b60405180910390a25050565b6000818152600183016020526040812054612aa657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610594565b506000610594565b606081600001805480602002602001604051908101604052809291908181526020018280548015612afe57602002820191906000526020600020905b815481526020019060010190808311612aea575b50505050509050919050565b60008181526001830160205260408120548015612bf3576000612b2e600183613fb8565b8554909150600090612b4290600190613fb8565b9050818114612ba7576000866000018281548110612b6257612b62613845565b9060005260206000200154905080876000018481548110612b8557612b85613845565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612bb857612bb8613fcb565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610594565b6000915050610594565b6000610594612c0a611cd0565b8360405161190160f01b8152600281019290925260228201526042902090565b6060600080856001600160a01b031685604051612c479190613de6565b600060405180830381855af49150503d8060008114612c82576040519150601f19603f3d011682016040523d82523d6000602084013e612c87565b606091505b5091509150612c9886838387612d5c565b9695505050505050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115612ccf5750600090506003612d53565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612d23573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612d4c57600060019250925050612d53565b9150600090505b94509492505050565b60608315612dc9578251600003612dc257612d7685612796565b612dc25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610813565b5081610647565b6106478383815115612dde5781518083602001fd5b8060405162461bcd60e51b815260040161081391906136ea565b6040518060a0016040528060006001600160a01b03168152602001606081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b600060208284031215612e5457600080fd5b81356001600160e01b031981168114610b5257600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612eaa57612eaa612e6c565b604052919050565b60006001600160401b03821115612ecb57612ecb612e6c565b50601f01601f191660200190565b6000612eec612ee784612eb2565b612e82565b9050828152838383011115612f0057600080fd5b828260208301376000602084830101529392505050565b600082601f830112612f2857600080fd5b610b5283833560208501612ed9565b600060208284031215612f4957600080fd5b81356001600160401b03811115612f5f57600080fd5b61064784828501612f17565b6001600160a01b03811681146114a657600080fd5b8035612f8b81612f6b565b919050565b60008060008060808587031215612fa657600080fd5b8435612fb181612f6b565b93506020850135612fc181612f6b565b92506040850135915060608501356001600160401b03811115612fe357600080fd5b612fef87828801612f17565b91505092959194509250565b6000806040838503121561300e57600080fd5b8235915060208301356001600160401b0381111561302b57600080fd5b61303785828601612f17565b9150509250929050565b6000610160828403121561305457600080fd5b50919050565b6000806040838503121561306d57600080fd5b823561307881612f6b565b915060208301356001600160401b0381111561309357600080fd5b61303785828601613041565b6000602082840312156130b157600080fd5b8135610b5281612f6b565b6000806000606084860312156130d157600080fd5b83356001600160401b038111156130e757600080fd5b6130f386828701613041565b9660208601359650604090950135949350505050565b60008083601f84011261311b57600080fd5b5081356001600160401b0381111561313257600080fd5b6020830191508360208260051b850101111561283a57600080fd5b6000806000806000806060878903121561316657600080fd5b86356001600160401b038082111561317d57600080fd5b6131898a838b01613109565b909850965060208901359150808211156131a257600080fd5b6131ae8a838b01613109565b909650945060408901359150808211156131c757600080fd5b506131d489828a01613109565b979a9699509497509295939492505050565b600080604083850312156131f957600080fd5b823561320481612f6b565b946020939093013593505050565b60008083601f84011261322457600080fd5b5081356001600160401b0381111561323b57600080fd5b60208301915083602082850101111561283a57600080fd5b60008060006040848603121561326857600080fd5b83356001600160401b038082111561327f57600080fd5b90850190610120828803121561329457600080fd5b909350602085013590808211156132aa57600080fd5b506132b786828701613212565b9497909650939450505050565b6001600160801b03169052565b80516001600160a01b03908116835260208083015160a082860181905281519086018190526000939183019290849060c08801905b8083101561332857855185168252948301946001929092019190830190613306565b50604087015160408901526060870151945061334760608901866132c4565b6080870151945061335b60808901866132c4565b979650505050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156133bd57603f198886030184526133ab8583516132d1565b9450928501929085019060010161338f565b5092979650505050505050565b6000602082840312156133dc57600080fd5b81356001600160401b038111156133f257600080fd5b8201601f8101841361340357600080fd5b61064784823560208401612ed9565b6000806020838503121561342557600080fd5b82356001600160401b0381111561343b57600080fd5b61344785828601613109565b90969095509350505050565b60005b8381101561346e578181015183820152602001613456565b50506000910152565b6000815180845261348f816020860160208601613453565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156133bd57603f198886030184526134e8858351613477565b945092850192908501906001016134cc565b6001600160a01b0391909116815260200190565b6000806000806060858703121561352457600080fd5b843561352f81612f6b565b93506020850135925060408501356001600160401b0381111561355157600080fd5b61355d87828801613212565b95989497509550505050565b60006001600160401b0382111561358257613582612e6c565b5060051b60200190565b600082601f83011261359d57600080fd5b813560206135ad612ee783613569565b8083825260208201915060208460051b8701019350868411156135cf57600080fd5b602086015b848110156135eb57803583529183019183016135d4565b509695505050505050565b600080600080600060a0868803121561360e57600080fd5b853561361981612f6b565b9450602086013561362981612f6b565b935060408601356001600160401b038082111561364557600080fd5b61365189838a0161358c565b9450606088013591508082111561366757600080fd5b61367389838a0161358c565b9350608088013591508082111561368957600080fd5b5061369688828901612f17565b9150509295509295909350565b6000806000604084860312156136b857600080fd5b83356136c381612f6b565b925060208401356001600160401b038111156136de57600080fd5b6132b786828701613212565b602081526000610b526020830184613477565b6020808252825182820181905260009190848201906040850190845b8181101561373e5783516001600160a01b031683529284019291840191600101613719565b50909695505050505050565b602081526000610b5260208301846132d1565b600080600080600060a0868803121561377557600080fd5b853561378081612f6b565b9450602086013561379081612f6b565b9350604086013592506060860135915060808601356001600160401b038111156137b957600080fd5b61369688828901612f17565b600080604083850312156137d857600080fd5b82516001600160401b038111156137ee57600080fd5b8301601f810185136137ff57600080fd5b805161380d612ee782612eb2565b81815286602083850101111561382257600080fd5b613833826020830160208601613453565b60209590950151949694955050505050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261387257600080fd5b8301803591506001600160401b0382111561388c57600080fd5b60200191503681900382131561283a57600080fd5b60208082526021908201527f4163636f756e743a206e6f742061646d696e206f7220456e747279506f696e746040820152601760f91b606082015260800190565b6001600160a01b03929092168252602082015260400190565b80356001600160801b0381168114612f8b57600080fd5b60006020828403121561392457600080fd5b610b52826138fb565b803560ff81168114612f8b57600080fd5b60006020828403121561395057600080fd5b610b528261392d565b634e487b7160e01b600052601160045260246000fd5b8082018082111561059457610594613959565b6000808335601e1984360301811261399957600080fd5b8301803591506001600160401b038211156139b357600080fd5b6020019150600581901b360382131561283a57600080fd5b6000808335601e198436030181126139e257600080fd5b83016020810192503590506001600160401b03811115613a0157600080fd5b8060051b360382131561283a57600080fd5b8183526000602080850194508260005b85811015613a51578135613a3681612f6b565b6001600160a01b031687529582019590820190600101613a23565b509495945050505050565b60208152613a7d60208201613a7084612f80565b6001600160a01b03169052565b6000613a8b6020840161392d565b60ff8116604084015250613aa260408401846139cb565b610120806060860152613aba61014086018385613a13565b925060608601356080860152613ad2608087016138fb565b9150613ae160a08601836132c4565b613aed60a087016138fb565b9150613afc60c08601836132c4565b613b0860c087016138fb565b9150613b1760e08601836132c4565b613b2360e087016138fb565b9150610100613b34818701846132c4565b9590950135939094019290925250919050565b600060018201613b5957613b59613959565b5060010190565b8284823760609190911b6001600160601b0319169101908152601401919050565b600060208284031215613b9357600080fd5b5051919050565b600181811c90821680613bae57607f821691505b60208210810361305457634e487b7160e01b600052602260045260246000fd5b602080825260059082015264214461746160d81b604082015260600190565b60008085851115613bfd57600080fd5b83861115613c0a57600080fd5b5050820193919092039150565b6001600160e01b03198135818116916004851015613c3f5780818660040360031b1b83161692505b505092915050565b600060208284031215613c5957600080fd5b5035919050565b600082601f830112613c7157600080fd5b81356020613c81612ee783613569565b82815260059290921b84018101918181019086841115613ca057600080fd5b8286015b848110156135eb5780356001600160401b03811115613cc35760008081fd5b613cd18986838b0101612f17565b845250918301918301613ca4565b600080600060608486031215613cf457600080fd5b83356001600160401b0380821115613d0b57600080fd5b818601915086601f830112613d1f57600080fd5b81356020613d2f612ee783613569565b82815260059290921b8401810191818101908a841115613d4e57600080fd5b948201945b83861015613d75578535613d6681612f6b565b82529482019490820190613d53565b97505087013592505080821115613d8b57600080fd5b613d978783880161358c565b93506040860135915080821115613dad57600080fd5b50613dba86828701613c60565b9150509250925092565b600060208284031215613dd657600080fd5b81518015158114610b5257600080fd5b60008251613df8818460208701613453565b9190910192915050565b601f821115613e4a576000816000526020600020601f850160051c81016020861015613e2b5750805b601f850160051c820191505b81811015610d9357828155600101613e37565b505050565b81516001600160401b03811115613e6857613e68612e6c565b613e7c81613e768454613b9a565b84613e02565b602080601f831160018114613eb15760008415613e995750858301515b600019600386901b1c1916600185901b178555610d93565b600085815260208120601f198616915b82811015613ee057888601518255948401946001909101908401613ec1565b5085821015613efe5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b604081526000613f216040830185613477565b8281036020840152613f338185613477565b95945050505050565b60008184825b85811015613f73578135613f5581612f6b565b6001600160a01b031683526020928301929190910190600101613f42565b509095945050505050565b6001600160a01b038316815260406020820181905260009061064790830184613477565b634e487b7160e01b600052602160045260246000fd5b8181038181111561059457610594613959565b634e487b7160e01b600052603160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212207dd84271219c3604ac6d88d7bd11606f603938cb8085f1d74eeef41783df3fbe64736f6c63430008170033"; +bytes constant THIRDWEB_ACCOUNT_FACTORY_BYTECODE = hex"608060405234801561001057600080fd5b50600436106101285760003560e01c806308e93d0a1461012d5780630b61e12b1461014b5780630e6254fd1461016057806311464fbe14610173578063248a9ca3146101b25780632f2ff15d146101d357806336568abe146101e657806358451f97146101f957806383a03f8c146102015780638878ed33146102145780639010d07c1461022757806391d148541461023a5780639387a3801461025d578063938e3d7b14610270578063a217fddf14610283578063a32fa5b31461028b578063a65d69d41461029e578063ac9650d8146102c5578063c3c5a547146102e5578063ca15c873146102f8578063d547741f1461030b578063d8fd8f441461031e578063e68a7c3b14610331578063e8a3d48514610344575b600080fd5b610135610359565b6040516101429190611945565b60405180910390f35b61015e6101593660046119ae565b61036a565b005b61013561016e3660046119d8565b61040b565b61019a7f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac81565b6040516001600160a01b039091168152602001610142565b6101c56101c03660046119f3565b610435565b604051908152602001610142565b61015e6101e1366004611a0c565b610453565b61015e6101f4366004611a0c565b6104fd565b6101c561055c565b61015e61020f3660046119f3565b610568565b61019a610222366004611a38565b6105b6565b61019a610235366004611aba565b610630565b61024d610248366004611a0c565b61073e565b6040519015158152602001610142565b61015e61026b3660046119ae565b610772565b61015e61027e366004611af2565b610809565b6101c5600081565b61024d610299366004611a0c565b61085a565b61019a7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278981565b6102d86102d3366004611ba2565b6108bd565b6040516101429190611c66565b61024d6102f33660046119d8565b610a19565b6101c56103063660046119f3565b610a25565b61015e610319366004611a0c565b610ac2565b61019a61032c366004611a38565b610acd565b61013561033f366004611aba565b610c18565b61034c610d49565b6040516101429190611cca565b60606103656000610de1565b905090565b336103758183610dee565b61039a5760405162461bcd60e51b815260040161039190611cdd565b60405180910390fd5b6001600160a01b03831660009081526002602052604081206103bc9083610e32565b9050801561040557836001600160a01b0316826001600160a01b03167f12146497b3b826918ec47f0cac7272a09ed06b30c16c030e99ec48ff5dd60b4760405160405180910390a35b50505050565b6001600160a01b038116600090815260026020526040902060609061042f90610de1565b92915050565b600061043f610e47565b600092835260010160205250604090205490565b61047761045e610e47565b6000848152600191909101602052604090205433610e6b565b61047f610e47565b6000838152602091825260408082206001600160a01b0385168352909252205460ff16156104ef5760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610391565b6104f98282610ef0565b5050565b336001600160a01b038216146105525760405162461bcd60e51b815260206004820152601a60248201527921b0b71037b7363c903932b737bab731b2903337b91039b2b63360311b6044820152606401610391565b6104f98282610f04565b60006103656000610f18565b336105738183610dee565b61058f5760405162461bcd60e51b815260040161039190611cdd565b61059a600082610e32565b6104f95760405162461bcd60e51b815260040161039190611d14565b6000806105f98585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f2292505050565b90506106257f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac82610f55565b9150505b9392505050565b60008061063b610fb5565b600085815260209190915260408120549150805b82811015610735576000610661610fb5565b60008881526020918252604080822085835260010190925220546001600160a01b0316146106d9578482036106c757610698610fb5565b600087815260209182526040808220938252600190930190915220546001600160a01b0316925061042f915050565b6106d2600183611d74565b9150610723565b6106e486600061073e565b801561071057506106f3610fb5565b600087815260209182526040808220828052600201909252205481145b1561072357610720600183611d74565b91505b61072e600182611d74565b905061064f565b50505092915050565b6000610748610e47565b6000938452602090815260408085206001600160a01b039490941685529290525090205460ff1690565b3361077d8183610dee565b6107995760405162461bcd60e51b815260040161039190611cdd565b6001600160a01b03831660009081526002602052604081206107bb9083610fbf565b9050801561040557836001600160a01b0316826001600160a01b03167f98d1ebbe00ae92a5de96a0f49742a8afa89f42363592bc2e7cfaaed68b45e7a660405160405180910390a350505050565b610811610fd4565b61084e5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610391565b61085781610fe0565b50565b6000610864610e47565b600084815260209182526040808220828052909252205460ff166108b45761088a610e47565b6000848152602091825260408082206001600160a01b0386168352909252205460ff16905061042f565b50600192915050565b6060816001600160401b038111156108d7576108d7611adc565b60405190808252806020026020018201604052801561090a57816020015b60608152602001906001900390816108f55790505b509050336000805b848110156107355781156109915761096f3087878481811061093657610936611d87565b90506020028101906109489190611d9d565b8660405160200161095b93929190611dea565b6040516020818303038152906040526110c7565b84828151811061098157610981611d87565b6020026020010181905250610a11565b6109f3308787848181106109a7576109a7611d87565b90506020028101906109b99190611d9d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506110c792505050565b848281518110610a0557610a05611d87565b60200260200101819052505b600101610912565b600061042f81836110ec565b600080610a30610fb5565b6000848152602091909152604081205491505b81811015610a9d576000610a55610fb5565b60008681526020918252604080822085835260010190925220546001600160a01b031614610a8b57610a88600184611d74565b92505b610a96600182611d74565b9050610a43565b50610aa983600061073e565b15610abc57610ab9600183611d74565b91505b50919050565b61055261045e610e47565b6000807f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac90506000610b358686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f2292505050565b90506000610b438383610f55565b90506001600160a01b0381163b15610b5f579250610629915050565b610b69838361110e565b9050336001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27891614610bc257610ba6600082610e32565b610bc25760405162461bcd60e51b815260040161039190611d14565b610bce818888886111a5565b866001600160a01b0316816001600160a01b03167fac631f3001b55ea1509cf3d7e74898f85392a61a76e8149181ae1259622dabc860405160405180910390a39695505050505050565b60608183108015610c325750610c2e6000610f18565b8211155b610c8a5760405162461bcd60e51b815260206004820152602360248201527f426173654163636f756e74466163746f72793a20696e76616c696420696e646960448201526263657360e81b6064820152608401610391565b6000610c968484611e0b565b9050610ca28484611e0b565b6001600160401b03811115610cb957610cb9611adc565b604051908082528060200260200182016040528015610ce2578160200160208202803683370190505b50915060005b81811015610d4157610d05610cfd8683611d74565b60009061120d565b838281518110610d1757610d17611d87565b6001600160a01b0390921660209283029190910190910152610d3a600182611d74565b9050610ce8565b505092915050565b6060610d53611219565b8054610d5e90611e1e565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8a90611e1e565b8015610dd75780601f10610dac57610100808354040283529160200191610dd7565b820191906000526020600020905b815481529060010190602001808311610dba57829003601f168201915b5050505050905090565b606060006106298361123d565b600080610e1b7f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac84610f55565b6001600160a01b0385811691161491505092915050565b6000610629836001600160a01b038416611299565b7f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e50090565b610e73610e47565b6000838152602091825260408082206001600160a01b0385168352909252205460ff166104f957610eae816001600160a01b031660146112e8565b610eb98360206112e8565b604051602001610eca929190611e52565b60408051601f198184030181529082905262461bcd60e51b825261039191600401611cca565b610efa8282611483565b6104f982826114ec565b610f0e82826115ab565b6104f98282611614565b600061042f825490565b60008282604051602001610f37929190611ebf565b60405160208183030381529060405280519060200120905092915050565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c82012060788201526055604390910120600090610629565b60006103656116a3565b6000610629836001600160a01b038416611705565b6000610365813361073e565b6000610fea611219565b8054610ff590611e1e565b80601f016020809104026020016040519081016040528092919081815260200182805461102190611e1e565b801561106e5780601f106110435761010080835404028352916020019161106e565b820191906000526020600020905b81548152906001019060200180831161105157829003601f168201915b505050505090508161107e611219565b906110899082611f34565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a1681836040516110bb929190611ff3565b60405180910390a15050565b606061062983836040518060600160405280602781526020016120b9602791396117f8565b6001600160a01b03811660009081526001830160205260408120541515610629565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661042f5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610391565b60405163347d5e2560e21b81526001600160a01b0385169063d1f57894906111d590869086908690600401612018565b600060405180830381600087803b1580156111ef57600080fd5b505af1158015611203573d6000803e3d6000fd5b5050505050505050565b60006106298383611870565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b60608160000180548060200260200160405190810160405280929190818152602001828054801561128d57602002820191906000526020600020905b815481526020019060010190808311611279575b50505050509050919050565b60008181526001830160205260408120546112e05750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561042f565b50600061042f565b606060006112f7836002612058565b611302906002611d74565b6001600160401b0381111561131957611319611adc565b6040519080825280601f01601f191660200182016040528015611343576020820181803683370190505b509050600360fc1b8160008151811061135e5761135e611d87565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061138d5761138d611d87565b60200101906001600160f81b031916908160001a90535060006113b1846002612058565b6113bc906001611d74565b90505b6001811115611434576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106113f0576113f0611d87565b1a60f81b82828151811061140657611406611d87565b60200101906001600160f81b031916908160001a90535060049490941c9361142d8161206f565b90506113bf565b5083156106295760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610391565b600161148d610e47565b6000848152602091825260408082206001600160a01b0386168084529352808220805460ff1916941515949094179093559151339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60006114f6610fb5565b6000848152602091909152604090205490506001611512610fb5565b6000858152602091909152604081208054909190611531908490611d74565b90915550829050611540610fb5565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b039290921691909117905580611580610fb5565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b6115b58282610e6b565b6115bd610e47565b6000838152602091825260408082206001600160a01b0385168084529352808220805460ff191690555133929185917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600061161e610fb5565b6000848152602091825260408082206001600160a01b03861683526002019092522054905061164b610fb5565b6000848152602091825260408082208483526001019092522080546001600160a01b031916905561167a610fb5565b6000938452602090815260408085206001600160a01b0390941685526002909301905250812055565b60008060ff196116d460017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c611e0b565b6040516020016116e691815260200190565b60408051601f1981840301815291905280516020909101201692915050565b600081815260018301602052604081205480156117ee576000611729600183611e0b565b855490915060009061173d90600190611e0b565b90508181146117a257600086600001828154811061175d5761175d611d87565b906000526020600020015490508087600001848154811061178057611780611d87565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117b3576117b3612086565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061042f565b600091505061042f565b6060600080856001600160a01b031685604051611815919061209c565b600060405180830381855af49150503d8060008114611850576040519150601f19603f3d011682016040523d82523d6000602084013e611855565b606091505b50915091506118668683838761189a565b9695505050505050565b600082600001828154811061188757611887611d87565b9060005260206000200154905092915050565b60608315611909578251600003611902576001600160a01b0385163b6119025760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610391565b5081611913565b611913838361191b565b949350505050565b81511561192b5781518083602001fd5b8060405162461bcd60e51b81526004016103919190611cca565b6020808252825182820181905260009190848201906040850190845b818110156119865783516001600160a01b031683529284019291840191600101611961565b50909695505050505050565b80356001600160a01b03811681146119a957600080fd5b919050565b600080604083850312156119c157600080fd5b6119ca83611992565b946020939093013593505050565b6000602082840312156119ea57600080fd5b61062982611992565b600060208284031215611a0557600080fd5b5035919050565b60008060408385031215611a1f57600080fd5b82359150611a2f60208401611992565b90509250929050565b600080600060408486031215611a4d57600080fd5b611a5684611992565b925060208401356001600160401b0380821115611a7257600080fd5b818601915086601f830112611a8657600080fd5b813581811115611a9557600080fd5b876020828501011115611aa757600080fd5b6020830194508093505050509250925092565b60008060408385031215611acd57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b600060208284031215611b0457600080fd5b81356001600160401b0380821115611b1b57600080fd5b818401915084601f830112611b2f57600080fd5b813581811115611b4157611b41611adc565b604051601f8201601f19908116603f01168101908382118183101715611b6957611b69611adc565b81604052828152876020848701011115611b8257600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060208385031215611bb557600080fd5b82356001600160401b0380821115611bcc57600080fd5b818501915085601f830112611be057600080fd5b813581811115611bef57600080fd5b8660208260051b8501011115611c0457600080fd5b60209290920196919550909350505050565b60005b83811015611c31578181015183820152602001611c19565b50506000910152565b60008151808452611c52816020860160208601611c16565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015611cbd57603f19888603018452611cab858351611c3a565b94509285019290850190600101611c8f565b5092979650505050505050565b6020815260006106296020830184611c3a565b6020808252601f908201527f4163636f756e74466163746f72793a206e6f7420616e206163636f756e742e00604082015260600190565b6020808252602a908201527f4163636f756e74466163746f72793a206163636f756e7420616c7265616479206040820152691c9959da5cdd195c995960b21b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561042f5761042f611d5e565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112611db457600080fd5b8301803591506001600160401b03821115611dce57600080fd5b602001915036819003821315611de357600080fd5b9250929050565b8284823760609190911b6001600160601b0319169101908152601401919050565b8181038181111561042f5761042f611d5e565b600181811c90821680611e3257607f821691505b602082108103610abc57634e487b7160e01b600052602260045260246000fd5b7402832b936b4b9b9b4b7b7399d1030b1b1b7bab73a1605d1b815260008351611e82816015850160208801611c16565b7001034b99036b4b9b9b4b733903937b6329607d1b6015918401918201528351611eb3816026840160208801611c16565b01602601949350505050565b6001600160a01b038316815260406020820181905260009061191390830184611c3a565b601f821115611f2f576000816000526020600020601f850160051c81016020861015611f0c5750805b601f850160051c820191505b81811015611f2b57828155600101611f18565b5050505b505050565b81516001600160401b03811115611f4d57611f4d611adc565b611f6181611f5b8454611e1e565b84611ee3565b602080601f831160018114611f965760008415611f7e5750858301515b600019600386901b1c1916600185901b178555611f2b565b600085815260208120601f198616915b82811015611fc557888601518255948401946001909101908401611fa6565b5085821015611fe35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6040815260006120066040830185611c3a565b82810360208401526106258185611c3a565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761042f5761042f611d5e565b60008161207e5761207e611d5e565b506000190190565b634e487b7160e01b600052603160045260246000fd5b600082516120ae818460208701611c16565b919091019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c287c94ab5092733927e43f330516517c7bbf06a412cf3b2ebc55b9b2967ea5864736f6c63430008170033"; +bytes constant THIRDWEB_ACCOUNT_IMPL_BYTECODE = hex"60806040526004361061014b5760003560e01c806301ffc9a7146101575780630a1028c41461018c578063150b7a02146101ba5780631626ba7e146101f35780631dd756c51461021357806324d7806c146102335780633a871cdd1461025357806347e1da2a146102735780634a58db19146102955780634d44560d1461029d5780635892e236146102bd5780637dff5a79146102dd5780638b52d723146102fd578063938e3d7b1461031f578063a9082d841461033f578063ac9650d81461037e578063b0d691fe146103ab578063b61d27f6146103cd578063b76464d5146103ed578063bc197c811461040d578063c45a015514610439578063d087d2881461046d578063d1f5789414610482578063d42f2f35146104a2578063e8a3d485146104b7578063e9523c97146104d9578063f15d424e146104fb578063f23a6e611461052857600080fd5b3661015257005b600080fd5b34801561016357600080fd5b50610177610172366004612d91565b610554565b60405190151581526020015b60405180910390f35b34801561019857600080fd5b506101ac6101a7366004612e78565b61059a565b604051908152602001610183565b3480156101c657600080fd5b506101da6101d5366004612ed1565b61063e565b6040516001600160e01b03199091168152602001610183565b3480156101ff57600080fd5b506101da61020e366004612f3c565b61064f565b34801561021f57600080fd5b5061017761022e366004612f9b565b61078f565b34801561023f57600080fd5b5061017761024e366004612fe0565b610a53565b34801561025f57600080fd5b506101ac61026e366004612ffd565b610a82565b34801561027f57600080fd5b5061029361028e36600461308e565b610aa8565b005b610293610c0f565b3480156102a957600080fd5b506102936102b8366004613127565b610c77565b3480156102c957600080fd5b506102936102d8366004613194565b610cea565b3480156102e957600080fd5b506101776102f8366004612fe0565b6110a7565b34801561030957600080fd5b50610312611160565b60405161018391906132a7565b34801561032b57600080fd5b5061029361033a36600461330b565b6113a7565b34801561034b57600080fd5b5061035f61035a366004613194565b6113f8565b6040805192151583526001600160a01b03909116602083015201610183565b34801561038a57600080fd5b5061039e610399366004613353565b61144f565b60405161018391906133e4565b3480156103b757600080fd5b506103c06115b4565b604051610183919061343b565b3480156103d957600080fd5b506102936103e836600461344f565b6115fd565b3480156103f957600080fd5b50610293610408366004612fe0565b61168d565b34801561041957600080fd5b506101da61042836600461353c565b63bc197c8160e01b95945050505050565b34801561044557600080fd5b506103c07f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b81565b34801561047957600080fd5b506101ac6116bf565b34801561048e57600080fd5b5061029361049d3660046135e9565b61173f565b3480156104ae57600080fd5b506103126118f7565b3480156104c357600080fd5b506104cc611a68565b6040516101839190613630565b3480156104e557600080fd5b506104ee611b00565b6040516101839190613643565b34801561050757600080fd5b5061051b610516366004612fe0565b611b12565b6040516101839190613690565b34801561053457600080fd5b506101da6105433660046136a3565b63f23a6e6160e01b95945050505050565b60006001600160e01b03198216630271189760e51b148061058557506001600160e01b03198216630a85bd0160e11b145b80610594575061059482611bea565b92915050565b6000807f82cac545155fcbf147f2a9013809613677ac7d65498556e6d19ce43bcbf6c28483805190602001206040516020016105e0929190918252602082015260400190565b604051602081830303815290604052805190602001209050610600611c1f565b60405161190160f01b602082015260228101919091526042810182905260620160405160208183030381529060405280519060200120915050919050565b630a85bd0160e11b5b949350505050565b60008061067c8460405160200161066891815260200190565b60405160208183030381529060405261059a565b9050600061068a8285611d46565b905061069581610a53565b156106ac5750630b135d3f60e11b91506105949050565b3360006106b7611d6a565b6001600160a01b03841660009081526006919091016020526040902090506106df8183611d8e565b8061070f57506106ee81611db0565b600114801561070f575060006107048282611dba565b6001600160a01b0316145b61076c5760405162461bcd60e51b8152602060048201526024808201527f4163636f756e743a2063616c6c6572206e6f7420617070726f7665642074617260448201526333b2ba1760e11b60648201526084015b60405180910390fd5b610775836110a7565b1561078557630b135d3f60e11b94505b5050505092915050565b6000610799611d6a565b6001600160a01b0384166000908152600491909101602052604090205460ff16156107c657506001610594565b60006107d0611d6a565b6001600160a01b0385166000908152600591909101602090815260408083208151606081018352815481526001909101546001600160801b0380821694830194909452600160801b900490921690820152915061082b611d6a565b6006016000866001600160a01b03166001600160a01b0316815260200190815260200160002090504282602001516001600160801b0316118061087b575081604001516001600160801b03164210155b8061088c575061088a81611db0565b155b1561089c57600092505050610594565b60006108b36108ae606087018761370b565b611dc6565b905060006108c083611db0565b60011480156108e1575060006108d68482611dba565b6001600160a01b0316145b90506324f16c0560e11b6001600160e01b03198316016109585760008061091361090e60608a018a61370b565b611e00565b9150915082610939576109268583611d8e565b6109395760009650505050505050610594565b85518111156109515760009650505050505050610594565b5050610a46565b635c0f12eb60e11b6001600160e01b0319831601610a395760008061098861098360608a018a61370b565b611e65565b5091509150826109e85760005b82518110156109e6576109ca8382815181106109b3576109b3613751565b602002602001015187611d8e90919063ffffffff16565b6109de576000975050505050505050610594565b600101610995565b505b60005b8251811015610a3157818181518110610a0657610a06613751565b602002602001015187600001511015610a29576000975050505050505050610594565b6001016109eb565b505050610a46565b6000945050505050610594565b5060019695505050505050565b6000610a5d611d6a565b6001600160a01b03909216600090815260049290920160205250604090205460ff1690565b6000610a8c611eb2565b610a968484611f1b565b9050610aa182612060565b9392505050565b610ab06115b4565b6001600160a01b0316336001600160a01b03161480610ad35750610ad333610a53565b610aef5760405162461bcd60e51b815260040161076390613767565b610af76120ad565b8481148015610b0557508483145b610b515760405162461bcd60e51b815260206004820152601d60248201527f4163636f756e743a2077726f6e67206172726179206c656e677468732e0000006044820152606401610763565b60005b85811015610c0657610bfd878783818110610b7157610b71613751565b9050602002016020810190610b869190612fe0565b868684818110610b9857610b98613751565b90506020020135858585818110610bb157610bb1613751565b9050602002810190610bc3919061370b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061219392505050565b50600101610b54565b50505050505050565b610c176115b4565b6001600160a01b031663b760faf934306040518363ffffffff1660e01b8152600401610c43919061343b565b6000604051808303818588803b158015610c5c57600080fd5b505af1158015610c70573d6000803e3d6000fd5b5050505050565b610c7f612204565b610c876115b4565b6001600160a01b031663205c287883836040518363ffffffff1660e01b8152600401610cb49291906137a8565b600060405180830381600087803b158015610cce57600080fd5b505af1158015610ce2573d6000803e3d6000fd5b505050505050565b6000610cf96020850185612fe0565b905042610d0c60e0860160c087016137d8565b6001600160801b031611158015610d3b5750610d2f610100850160e086016137d8565b6001600160801b031642105b610d715760405162461bcd60e51b8152602060048201526007602482015266085c195c9a5bd960ca1b6044820152606401610763565b600080610d7f8686866113f8565b9150915081610db95760405162461bcd60e51b8152600401610763906020808252600490820152632173696760e01b604082015260600190565b6001610dc3611d6a565b610100880135600090815260079190910160209081526040808320805460ff1916941515949094179093559091610dff91908901908901613804565b60ff161115610e2c576000610e1a6040880160208901613804565b60ff166001149050610c068482612242565b610e3583610a53565b15610e6a5760405162461bcd60e51b815260206004820152600560248201526430b236b4b760d91b6044820152606401610763565b610e7f83610e76611d6a565b60020190612317565b50604051806060016040528087606001358152602001876080016020810190610ea891906137d8565b6001600160801b03168152602001610ec660c0890160a08a016137d8565b6001600160801b03169052610ed9611d6a565b6001600160a01b03851660009081526005919091016020908152604080832084518155918401519301516001600160801b03908116600160801b02931692909217600190920191909155610f4f610f2e611d6a565b6001600160a01b03861660009081526006919091016020526040902061232c565b805190915060005b81811015610fb957610fa6838281518110610f7457610f74613751565b6020026020010151610f84611d6a565b6001600160a01b03891660009081526006919091016020526040902090612339565b50610fb2600182613835565b9050610f57565b50610fc76040890189613848565b9050905060005b8181101561104857611035610fe660408b018b613848565b83818110610ff657610ff6613751565b905060200201602081019061100b9190612fe0565b611013611d6a565b6001600160a01b03891660009081526006919091016020526040902090612317565b50611041600182613835565b9050610fce565b506110528861234e565b846001600160a01b0316836001600160a01b03167ff21d10c26e35863a8df291aca54181ee8c4a3bc8e00246c3f7a5a14b69d826a78a6040516110959190613922565b60405180910390a35050505050505050565b6000806110b2611d6a565b6001600160a01b038416600090815260059190910160209081526040918290208251606081018452815481526001909101546001600160801b03808216938301849052600160801b90910416928101929092529091504210801590611123575080604001516001600160801b031642105b8015610aa157506000611158611137611d6a565b6001600160a01b038616600090815260069190910160205260409020611db0565b119392505050565b6060600061117761116f611d6a565b60020161232c565b80519091506000805b82811015611208576111aa84828151811061119d5761119d613751565b60200260200101516110a7565b156111c157816111b981613a0d565b9250506111f6565b60008482815181106111d5576111d5613751565b60200260200101906001600160a01b031690816001600160a01b0316815250505b611201600182613835565b9050611180565b50806001600160401b0381111561122157611221612dbb565b60405190808252806020026020018201604052801561125a57816020015b611247612d47565b81526020019060019003908161123f5790505b5093506000805b8381101561139f5760006001600160a01b031685828151811061128657611286613751565b60200260200101516001600160a01b03161461138d5760008582815181106112b0576112b0613751565b6020026020010151905060006112c4611d6a565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a08101909452918352909250810161132e610f2e611d6a565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b031681525088858061136d90613a0d565b96508151811061137f5761137f613751565b602002602001018190525050505b611398600182613835565b9050611261565b505050505090565b6113af6123e3565b6113ec5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610763565b6113f5816123fb565b50565b60008061140e611407866124e2565b8585612626565b9050611418611d6a565b6101008601356000908152600791909101602052604090205460ff16158015611445575061144581610a53565b9150935093915050565b6060816001600160401b0381111561146957611469612dbb565b60405190808252806020026020018201604052801561149c57816020015b60608152602001906001900390816114875790505b509050336000805b848110156115ab57811561152357611501308787848181106114c8576114c8613751565b90506020028101906114da919061370b565b866040516020016114ed93929190613a26565b604051602081830303815290604052612678565b84828151811061151357611513613751565b60200260200101819052506115a3565b6115853087878481811061153957611539613751565b905060200281019061154b919061370b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061267892505050565b84828151811061159757611597613751565b60200260200101819052505b6001016114a4565b50505092915050565b6000806115bf61269d565b546001600160a01b0316905080156115d657919050565b7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278991505090565b6116056115b4565b6001600160a01b0316336001600160a01b03161480611628575061162833610a53565b6116445760405162461bcd60e51b815260040161076390613767565b61164c6120ad565b610c70848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061219392505050565b611695612204565b8061169e61269d565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60006116c96115b4565b604051631aab3f0d60e11b8152306004820152600060248201526001600160a01b0391909116906335567e1a90604401602060405180830381865afa158015611716573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061173a9190613a47565b905090565b60006117496126c1565b5460ff16905060006117596126c1565b54610100900460ff1690508015808015611776575060018360ff16105b806117955750611785306126e5565b15801561179557508260ff166001145b6117f85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610763565b60016118026126c1565b805460ff191660ff92909216919091179055801561183b5760016118246126c1565b80549115156101000261ff00199092169190911790555b61187b8686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506126f492505050565b61188361269d565b60010181905550611895866001612242565b8015610ce25760006118a56126c1565b80549115156101000261ff0019909216919091179055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6060600061190661116f611d6a565b8051909150806001600160401b0381111561192357611923612dbb565b60405190808252806020026020018201604052801561195c57816020015b611949612d47565b8152602001906001900390816119415790505b50925060005b81811015611a6257600083828151811061197e5761197e613751565b602002602001015190506000611992611d6a565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a0810190945291835290925081016119fc610f2e611d6a565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250868481518110611a4157611a41613751565b60200260200101819052505050600181611a5b9190613835565b9050611962565b50505090565b6060611a72612727565b8054611a7d90613a60565b80601f0160208091040260200160405190810160405280929190818152602001828054611aa990613a60565b8015611af65780601f10611acb57610100808354040283529160200191611af6565b820191906000526020600020905b815481529060010190602001808311611ad957829003601f168201915b5050505050905090565b606061173a611b0d611d6a565b61232c565b611b1a612d47565b6000611b24611d6a565b6001600160a01b038416600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101611baf611b8e611d6a565b6001600160a01b03871660009081526006919091016020526040902061232c565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250915050919050565b60006001600160e01b03198216630271189760e51b148061059457506301ffc9a760e01b6001600160e01b0319831614610594565b6000306001600160a01b037f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac16148015611c7857507f0000000000000000000000000000000000000000000000000000000000007a6946145b15611ca257507fbcdadf6444930a967ffda04923d78c49b3dd65df3ed39abb04a1e3eb1190553790565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527ff0729608244859f656d32ae4cbc6b0367695d68d8e941a28f5e2d33c6d5182dd828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000806000611d55858561274b565b91509150611d6281612790565b509392505050565b7f3181e78fc1b109bc611fd2406150bf06e33faa75f71cba12c3e1fd670f2def0090565b6001600160a01b03811660009081526001830160205260408120541515610aa1565b6000610594825490565b6000610aa183836128d5565b60006004821015611de95760405162461bcd60e51b815260040161076390613a94565b611df7600460008486613ab3565b610aa191613add565b6000806044831015611e245760405162461bcd60e51b815260040161076390613a94565b611e32602460048587613ab3565b810190611e3f9190612fe0565b9150611e4f604460248587613ab3565b810190611e5c9190613b0d565b90509250929050565b606080806064841015611e8a5760405162461bcd60e51b815260040161076390613a94565b611e978460048188613ab3565b810190611ea49190613ba5565b919790965090945092505050565b611eba6115b4565b6001600160a01b0316336001600160a01b031614611f195760405162461bcd60e51b815260206004820152601c60248201527b1858d8dbdd5b9d0e881b9bdd08199c9bdb48115b9d1c9e541bda5b9d60221b6044820152606401610763565b565b7b0ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d05199960211b6000908152601c829052603c81206000611f99611f5c61014087018761370b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611d469050565b9050611fa5818661078f565b611fb457600192505050610594565b6000611fbe611d6a565b6001600160a01b03929092166000908152600590920160209081526040808420815160608082018452825482526001909201546001600160801b0380821683870152600160801b8204908116928501929092528351928301845295825265ffffffffffff8087169483019490945292831691015260d09290921b6001600160d01b03191660a09290921b65ffffffffffff60a01b169190911795945050505050565b80156113f557604051600090339060001990849084818181858888f193505050503d8060008114610c70576040519150601f19603f3d011682016040523d82523d6000602084013e610c70565b60405163c3c5a54760e01b81527f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b906001600160a01b0382169063c3c5a547906120fb90309060040161343b565b602060405180830381865afa158015612118573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213c9190613c8a565b6113f557806001600160a01b03166383a03f8c61215761269d565b600101546040518263ffffffff1660e01b815260040161217991815260200190565b600060405180830381600087803b158015610c5c57600080fd5b60606000846001600160a01b031684846040516121b09190613cac565b60006040518083038185875af1925050503d80600081146121ed576040519150601f19603f3d011682016040523d82523d6000602084013e6121f2565b606091505b509250905080611d6257815160208301fd5b61220d33610a53565b611f195760405162461bcd60e51b815260206004820152600660248201526510b0b236b4b760d11b6044820152606401610763565b61224c82826128ff565b6001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b163b156123135780156122db577f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b6001600160a01b0316630b61e12b836122ba61269d565b600101546040518363ffffffff1660e01b8152600401610cb49291906137a8565b7f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b6001600160a01b0316639387a380836122ba61269d565b5050565b6000610aa1836001600160a01b0384166129ae565b60606000610aa1836129fd565b6000610aa1836001600160a01b038416612a59565b6001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b163b156113f5576001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b16630b61e12b6123ba6020840184612fe0565b6123c261269d565b600101546040518363ffffffff1660e01b81526004016121799291906137a8565b60006123ee33610a53565b8061173a57505030331490565b6000612405612727565b805461241090613a60565b80601f016020809104026020016040519081016040528092919081815260200182805461243c90613a60565b80156124895780601f1061245e57610100808354040283529160200191612489565b820191906000526020600020905b81548152906001019060200180831161246c57829003601f168201915b5050505050905081612499612727565b906124a49082613d15565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a1681836040516124d6929190613dd4565b60405180910390a15050565b60607f3fd4a1a1a267c84185e3b7eecd57c68783c0581d538b9d6e5f23e4670497c1e96125126020840184612fe0565b6125226040850160208601613804565b61252f6040860186613848565b604051602001612540929190613e02565b60408051601f198184030181529190528051602090910120606086013561256d60a08801608089016137d8565b61257d60c0890160a08a016137d8565b61258d60e08a0160c08b016137d8565b61259e6101008b0160e08c016137d8565b60408051602081019a909a526001600160a01b039098169789019790975260ff9095166060880152608087019390935260a08601919091526001600160801b0390811660c086015290811660e0850152908116610100848101919091529116610120830152830135610140820152610160016040516020818303038152906040529050919050565b600061064783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250508751602089012061267292509050612b4c565b90611d46565b6060610aa18383604051806060016040528060278152602001613ea860279139612b79565b7f036f52c1827dab135f7fd44ca0bddde297e2f659c710e0ec53e975f22b54830090565b7f322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee030090565b6001600160a01b03163b151590565b60008282604051602001612709929190613e44565b60405160208183030381529060405280519060200120905092915050565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b60008082516041036127815760208301516040840151606085015160001a61277587828585612bf1565b94509450505050612789565b506000905060025b9250929050565b60008160048111156127a4576127a4613e68565b036127ac5750565b60018160048111156127c0576127c0613e68565b036128085760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401610763565b600281600481111561281c5761281c613e68565b036128695760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610763565b600381600481111561287d5761287d613e68565b036113f55760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610763565b60008260000182815481106128ec576128ec613751565b9060005260206000200154905092915050565b80612908611d6a565b6001600160a01b038416600090815260049190910160205260409020805460ff191691151591909117905580156129515761294b82612945611d6a565b90612317565b50612965565b6129638261295d611d6a565b90612339565b505b816001600160a01b03167f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a11133826040516129a2911515815260200190565b60405180910390a25050565b60008181526001830160205260408120546129f557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610594565b506000610594565b606081600001805480602002602001604051908101604052809291908181526020018280548015612a4d57602002820191906000526020600020905b815481526020019060010190808311612a39575b50505050509050919050565b60008181526001830160205260408120548015612b42576000612a7d600183613e7e565b8554909150600090612a9190600190613e7e565b9050818114612af6576000866000018281548110612ab157612ab1613751565b9060005260206000200154905080876000018481548110612ad457612ad4613751565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612b0757612b07613e91565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610594565b6000915050610594565b6000610594612b59611c1f565b8360405161190160f01b8152600281019290925260228201526042902090565b6060600080856001600160a01b031685604051612b969190613cac565b600060405180830381855af49150503d8060008114612bd1576040519150601f19603f3d011682016040523d82523d6000602084013e612bd6565b606091505b5091509150612be786838387612cab565b9695505050505050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115612c1e5750600090506003612ca2565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612c72573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612c9b57600060019250925050612ca2565b9150600090505b94509492505050565b60608315612d18578251600003612d1157612cc5856126e5565b612d115760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610763565b5081610647565b6106478383815115612d2d5781518083602001fd5b8060405162461bcd60e51b81526004016107639190613630565b6040518060a0016040528060006001600160a01b03168152602001606081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b600060208284031215612da357600080fd5b81356001600160e01b031981168114610aa157600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612df957612df9612dbb565b604052919050565b60006001600160401b03831115612e1a57612e1a612dbb565b612e2d601f8401601f1916602001612dd1565b9050828152838383011115612e4157600080fd5b828260208301376000602084830101529392505050565b600082601f830112612e6957600080fd5b610aa183833560208501612e01565b600060208284031215612e8a57600080fd5b81356001600160401b03811115612ea057600080fd5b61064784828501612e58565b6001600160a01b03811681146113f557600080fd5b8035612ecc81612eac565b919050565b60008060008060808587031215612ee757600080fd5b8435612ef281612eac565b93506020850135612f0281612eac565b92506040850135915060608501356001600160401b03811115612f2457600080fd5b612f3087828801612e58565b91505092959194509250565b60008060408385031215612f4f57600080fd5b8235915060208301356001600160401b03811115612f6c57600080fd5b612f7885828601612e58565b9150509250929050565b60006101608284031215612f9557600080fd5b50919050565b60008060408385031215612fae57600080fd5b8235612fb981612eac565b915060208301356001600160401b03811115612fd457600080fd5b612f7885828601612f82565b600060208284031215612ff257600080fd5b8135610aa181612eac565b60008060006060848603121561301257600080fd5b83356001600160401b0381111561302857600080fd5b61303486828701612f82565b9660208601359650604090950135949350505050565b60008083601f84011261305c57600080fd5b5081356001600160401b0381111561307357600080fd5b6020830191508360208260051b850101111561278957600080fd5b600080600080600080606087890312156130a757600080fd5b86356001600160401b03808211156130be57600080fd5b6130ca8a838b0161304a565b909850965060208901359150808211156130e357600080fd5b6130ef8a838b0161304a565b9096509450604089013591508082111561310857600080fd5b5061311589828a0161304a565b979a9699509497509295939492505050565b6000806040838503121561313a57600080fd5b823561314581612eac565b946020939093013593505050565b60008083601f84011261316557600080fd5b5081356001600160401b0381111561317c57600080fd5b60208301915083602082850101111561278957600080fd5b6000806000604084860312156131a957600080fd5b83356001600160401b03808211156131c057600080fd5b9085019061012082880312156131d557600080fd5b909350602085013590808211156131eb57600080fd5b506131f886828701613153565b9497909650939450505050565b6001600160801b03169052565b80516001600160a01b03908116835260208083015160a082860181905281519086018190526000939183019290849060c08801905b8083101561326957855185168252948301946001929092019190830190613247565b5060408701516040890152606087015194506132886060890186613205565b6080870151945061329c6080890186613205565b979650505050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156132fe57603f198886030184526132ec858351613212565b945092850192908501906001016132d0565b5092979650505050505050565b60006020828403121561331d57600080fd5b81356001600160401b0381111561333357600080fd5b8201601f8101841361334457600080fd5b61064784823560208401612e01565b6000806020838503121561336657600080fd5b82356001600160401b0381111561337c57600080fd5b6133888582860161304a565b90969095509350505050565b60005b838110156133af578181015183820152602001613397565b50506000910152565b600081518084526133d0816020860160208601613394565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156132fe57603f198886030184526134298583516133b8565b9450928501929085019060010161340d565b6001600160a01b0391909116815260200190565b6000806000806060858703121561346557600080fd5b843561347081612eac565b93506020850135925060408501356001600160401b0381111561349257600080fd5b61349e87828801613153565b95989497509550505050565b60006001600160401b038211156134c3576134c3612dbb565b5060051b60200190565b600082601f8301126134de57600080fd5b813560206134f36134ee836134aa565b612dd1565b8083825260208201915060208460051b87010193508684111561351557600080fd5b602086015b84811015613531578035835291830191830161351a565b509695505050505050565b600080600080600060a0868803121561355457600080fd5b853561355f81612eac565b9450602086013561356f81612eac565b935060408601356001600160401b038082111561358b57600080fd5b61359789838a016134cd565b945060608801359150808211156135ad57600080fd5b6135b989838a016134cd565b935060808801359150808211156135cf57600080fd5b506135dc88828901612e58565b9150509295509295909350565b6000806000604084860312156135fe57600080fd5b833561360981612eac565b925060208401356001600160401b0381111561362457600080fd5b6131f886828701613153565b602081526000610aa160208301846133b8565b6020808252825182820181905260009190848201906040850190845b818110156136845783516001600160a01b03168352928401929184019160010161365f565b50909695505050505050565b602081526000610aa16020830184613212565b600080600080600060a086880312156136bb57600080fd5b85356136c681612eac565b945060208601356136d681612eac565b9350604086013592506060860135915060808601356001600160401b038111156136ff57600080fd5b6135dc88828901612e58565b6000808335601e1984360301811261372257600080fd5b8301803591506001600160401b0382111561373c57600080fd5b60200191503681900382131561278957600080fd5b634e487b7160e01b600052603260045260246000fd5b60208082526021908201527f4163636f756e743a206e6f742061646d696e206f7220456e747279506f696e746040820152601760f91b606082015260800190565b6001600160a01b03929092168252602082015260400190565b80356001600160801b0381168114612ecc57600080fd5b6000602082840312156137ea57600080fd5b610aa1826137c1565b803560ff81168114612ecc57600080fd5b60006020828403121561381657600080fd5b610aa1826137f3565b634e487b7160e01b600052601160045260246000fd5b808201808211156105945761059461381f565b6000808335601e1984360301811261385f57600080fd5b8301803591506001600160401b0382111561387957600080fd5b6020019150600581901b360382131561278957600080fd5b6000808335601e198436030181126138a857600080fd5b83016020810192503590506001600160401b038111156138c757600080fd5b8060051b360382131561278957600080fd5b8183526000602080850194508260005b858110156139175781356138fc81612eac565b6001600160a01b0316875295820195908201906001016138e9565b509495945050505050565b602081526139436020820161393684612ec1565b6001600160a01b03169052565b6000613951602084016137f3565b60ff81166040840152506139686040840184613891565b610120806060860152613980610140860183856138d9565b925060608601356080860152613998608087016137c1565b91506139a760a0860183613205565b6139b360a087016137c1565b91506139c260c0860183613205565b6139ce60c087016137c1565b91506139dd60e0860183613205565b6139e960e087016137c1565b91506101006139fa81870184613205565b9590950135939094019290925250919050565b600060018201613a1f57613a1f61381f565b5060010190565b8284823760609190911b6001600160601b0319169101908152601401919050565b600060208284031215613a5957600080fd5b5051919050565b600181811c90821680613a7457607f821691505b602082108103612f9557634e487b7160e01b600052602260045260246000fd5b602080825260059082015264214461746160d81b604082015260600190565b60008085851115613ac357600080fd5b83861115613ad057600080fd5b5050820193919092039150565b6001600160e01b03198135818116916004851015613b055780818660040360031b1b83161692505b505092915050565b600060208284031215613b1f57600080fd5b5035919050565b600082601f830112613b3757600080fd5b81356020613b476134ee836134aa565b82815260059290921b84018101918181019086841115613b6657600080fd5b8286015b848110156135315780356001600160401b03811115613b895760008081fd5b613b978986838b0101612e58565b845250918301918301613b6a565b600080600060608486031215613bba57600080fd5b83356001600160401b0380821115613bd157600080fd5b818601915086601f830112613be557600080fd5b81356020613bf56134ee836134aa565b82815260059290921b8401810191818101908a841115613c1457600080fd5b948201945b83861015613c3b578535613c2c81612eac565b82529482019490820190613c19565b97505087013592505080821115613c5157600080fd5b613c5d878388016134cd565b93506040860135915080821115613c7357600080fd5b50613c8086828701613b26565b9150509250925092565b600060208284031215613c9c57600080fd5b81518015158114610aa157600080fd5b60008251613cbe818460208701613394565b9190910192915050565b601f821115613d10576000816000526020600020601f850160051c81016020861015613cf15750805b601f850160051c820191505b81811015610ce257828155600101613cfd565b505050565b81516001600160401b03811115613d2e57613d2e612dbb565b613d4281613d3c8454613a60565b84613cc8565b602080601f831160018114613d775760008415613d5f5750858301515b600019600386901b1c1916600185901b178555610ce2565b600085815260208120601f198616915b82811015613da657888601518255948401946001909101908401613d87565b5085821015613dc45787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b604081526000613de760408301856133b8565b8281036020840152613df981856133b8565b95945050505050565b60008184825b85811015613e39578135613e1b81612eac565b6001600160a01b031683526020928301929190910190600101613e08565b509095945050505050565b6001600160a01b0383168152604060208201819052600090610647908301846133b8565b634e487b7160e01b600052602160045260246000fd5b818103818111156105945761059461381f565b634e487b7160e01b600052603160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212208c5778cccab69c03f4ec340866800c49e235a33618da3a2f04272a256725372f64736f6c63430008170033"; From 70e4e854e1303cfbaf91d53cff73631b1a87b1f4 Mon Sep 17 00:00:00 2001 From: Krishang Date: Fri, 23 Feb 2024 22:07:09 +0530 Subject: [PATCH 07/12] Update AccountBulkOrderSig to use ManagedAccount upgrades --- src/test/seaport/AccountBulkOrderSig.t.sol | 101 ++++++++++++++++++++- 1 file changed, 97 insertions(+), 4 deletions(-) diff --git a/src/test/seaport/AccountBulkOrderSig.t.sol b/src/test/seaport/AccountBulkOrderSig.t.sol index 825ba6f9b..bb646f321 100644 --- a/src/test/seaport/AccountBulkOrderSig.t.sol +++ b/src/test/seaport/AccountBulkOrderSig.t.sol @@ -3,17 +3,23 @@ pragma solidity ^0.8.0; // Test utils import "../utils/BaseTest.sol"; +import "@thirdweb-dev/dynamic-contracts/src/interface/IExtension.sol"; +import { IAccountPermissions } from "contracts/extension/interface/IAccountPermissions.sol"; +import { AccountPermissions } from "contracts/extension/upgradeable/AccountPermissions.sol"; +import { AccountExtension } from "contracts/prebuilts/account/utils/AccountExtension.sol"; // Account Abstraction setup for smart wallets. import { EntryPoint, IEntryPoint } from "contracts/prebuilts/account/utils/Entrypoint.sol"; import { UserOperation } from "contracts/prebuilts/account/utils/UserOperation.sol"; // Target -import { AccountFactory, Account as SimpleAccount } from "contracts/prebuilts/account/non-upgradeable/AccountFactory.sol"; +import { Account as SimpleAccount } from "contracts/prebuilts/account/non-upgradeable/Account.sol"; +import { ManagedAccountFactory, ManagedAccount } from "contracts/prebuilts/account/managed/ManagedAccountFactory.sol"; import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { Seaport } from "./Seaport.sol"; import { EIP712MerkleTree } from "./EIP712MerkleTree.sol"; +import { SeaportOrderEIP1271 } from "contracts/extension/SeaportOrderEIP1271.sol"; import { ConduitController } from "seaport-core/src/conduit/ConduitController.sol"; import { ConsiderationItem, OfferItem, ItemType, SpentItem, OrderComponents, Order, OrderParameters } from "seaport-types/src/lib/ConsiderationStructs.sol"; @@ -36,15 +42,18 @@ interface EIP1271Verifier { contract AccountBulkOrderSigTest is BaseTest { // Target contracts EntryPoint private entrypoint; - AccountFactory private accountFactory; + ManagedAccountFactory private accountFactory; ConduitController private conduitController; Seaport private seaport; // Signer uint256 private accountAdminPKey = 1; address private accountAdmin; + address private factoryDeployer = address(0x9876); // Test params + bytes internal data = bytes(""); + OfferItem offerItem; OfferItem[] offerItems; ConsiderationItem considerationItem; @@ -53,7 +62,7 @@ contract AccountBulkOrderSigTest is BaseTest { OrderParameters baseOrderParameters; // UserOp terminology: `sender` is the smart wallet. - address private sender = 0xAcF86fd6BA3b8A4CBDbc1F0A605e1667a8879640; + address private sender = 0xfD14C2809c876165D0c18878A2dE641018426a11; address payable private beneficiary = payable(address(0x45654)); function _configureOrderParameters(address offerer) internal { @@ -165,8 +174,65 @@ contract AccountBulkOrderSigTest is BaseTest { // Setup contracts entrypoint = new EntryPoint(); + + // Setting up default extension. + IExtension.Extension memory defaultExtension; + + defaultExtension.metadata = IExtension.ExtensionMetadata({ + name: "AccountExtension", + metadataURI: "ipfs://AccountExtension", + implementation: address(new AccountExtension()) + }); + + defaultExtension.functions = new IExtension.ExtensionFunction[](9); + + defaultExtension.functions[0] = IExtension.ExtensionFunction( + AccountExtension.supportsInterface.selector, + "supportsInterface(bytes4)" + ); + defaultExtension.functions[1] = IExtension.ExtensionFunction( + AccountExtension.execute.selector, + "execute(address,uint256,bytes)" + ); + defaultExtension.functions[2] = IExtension.ExtensionFunction( + AccountExtension.executeBatch.selector, + "executeBatch(address[],uint256[],bytes[])" + ); + defaultExtension.functions[3] = IExtension.ExtensionFunction( + ERC721Holder.onERC721Received.selector, + "onERC721Received(address,address,uint256,bytes)" + ); + defaultExtension.functions[4] = IExtension.ExtensionFunction( + ERC1155Holder.onERC1155Received.selector, + "onERC1155Received(address,address,uint256,uint256,bytes)" + ); + defaultExtension.functions[5] = IExtension.ExtensionFunction( + bytes4(0), // Selector for `receive()` function. + "receive()" + ); + defaultExtension.functions[6] = IExtension.ExtensionFunction( + AccountExtension.isValidSignature.selector, + "isValidSignature(bytes32,bytes)" + ); + defaultExtension.functions[7] = IExtension.ExtensionFunction( + AccountExtension.addDeposit.selector, + "addDeposit()" + ); + defaultExtension.functions[8] = IExtension.ExtensionFunction( + AccountExtension.withdrawDepositTo.selector, + "withdrawDepositTo(address,uint256)" + ); + + IExtension.Extension[] memory extensions = new IExtension.Extension[](1); + extensions[0] = defaultExtension; + // deploy account factory - accountFactory = new AccountFactory(deployer, IEntryPoint(payable(address(entrypoint)))); + vm.prank(factoryDeployer); + accountFactory = new ManagedAccountFactory( + factoryDeployer, + IEntryPoint(payable(address(entrypoint))), + extensions + ); // deploy seaport contract conduitController = new ConduitController(); seaport = new Seaport(address(conduitController)); @@ -189,7 +255,34 @@ contract AccountBulkOrderSigTest is BaseTest { Test: performing a contract call //////////////////////////////////////////////////////////////*/ + /// @dev Make the account support Seaport bulk order signatures. + function _upggradeIsValidSignature() internal { + // Update isValidSignature to support Seaport bulk order signatures. + IExtension.Extension memory extension; + + extension.metadata = IExtension.ExtensionMetadata({ + name: "SeaportOrderEIP1271", + metadataURI: "ipfs://SeaportOrderEIP1271", + implementation: address(new SeaportOrderEIP1271()) + }); + + extension.functions = new IExtension.ExtensionFunction[](1); + + extension.functions[0] = IExtension.ExtensionFunction( + AccountExtension.isValidSignature.selector, + "isValidSignature(bytes32,bytes)" + ); + + vm.prank(factoryDeployer); + accountFactory.disableFunctionInExtension("AccountExtension", AccountExtension.isValidSignature.selector); + + vm.prank(factoryDeployer); + accountFactory.addExtension(extension); + } + function test_POC() public { + _upggradeIsValidSignature(); + erc721.mint(address(accountAdmin), 1); vm.prank(accountAdmin); erc721.setApprovalForAll(address(seaport), true); From 295b00de67ef0c79ac489a6d5063b28376dba60b Mon Sep 17 00:00:00 2001 From: Krishang Date: Sun, 25 Feb 2024 23:17:21 +0530 Subject: [PATCH 08/12] Don't double hash in smart wallet isValidSignature replay protection --- .../account/non-upgradeable/Account.sol | 17 ++++++++++------- .../account/utils/AccountExtension.sol | 17 ++++++++++------- src/test/smart-wallet/AccountVulnPOC.t.sol | 4 ++-- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/contracts/prebuilts/account/non-upgradeable/Account.sol b/contracts/prebuilts/account/non-upgradeable/Account.sol index adc4bb3e3..46b585f1c 100644 --- a/contracts/prebuilts/account/non-upgradeable/Account.sol +++ b/contracts/prebuilts/account/non-upgradeable/Account.sol @@ -64,11 +64,13 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115 /// @notice See EIP-1271 function isValidSignature( - bytes32 _message, + bytes32 _originalMessageHash, bytes memory _signature ) public view virtual override returns (bytes4 magicValue) { - bytes32 messageHash = getMessageHash(abi.encode(_message)); - address signer = messageHash.recover(_signature); + bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, _originalMessageHash)); + bytes32 targetDigest = keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); + + address signer = targetDigest.recover(_signature); if (isAdmin(signer)) { return MAGICVALUE; @@ -89,12 +91,13 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115 /** * @notice Returns the hash of message that should be signed for EIP1271 verification. - * @param message Message to be hashed i.e. `keccak256(abi.encode(data))` + * @param _message The raw abi encoded data to hash and sign i.e. `abi.encode(data)` * @return Hashed message */ - function getMessageHash(bytes memory message) public view returns (bytes32) { - bytes32 messageHash = keccak256(abi.encode(MSG_TYPEHASH, keccak256(message))); - return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), messageHash)); + function getMessageHash(bytes memory _message) public view returns (bytes32) { + bytes32 messageHash = keccak256(_message); + bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, messageHash)); + return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); } /*/////////////////////////////////////////////////////////////// diff --git a/contracts/prebuilts/account/utils/AccountExtension.sol b/contracts/prebuilts/account/utils/AccountExtension.sol index c9aad670e..d747edfb5 100644 --- a/contracts/prebuilts/account/utils/AccountExtension.sol +++ b/contracts/prebuilts/account/utils/AccountExtension.sol @@ -66,11 +66,13 @@ contract AccountExtension is ContractMetadata, ERC1271, AccountPermissions, ERC7 /// @notice See EIP-1271 function isValidSignature( - bytes32 _message, + bytes32 _originalMessageHash, bytes memory _signature ) public view virtual override returns (bytes4 magicValue) { - bytes32 messageHash = getMessageHash(abi.encode(_message)); - address signer = messageHash.recover(_signature); + bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, _originalMessageHash)); + bytes32 targetDigest = keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); + + address signer = targetDigest.recover(_signature); if (isAdmin(signer)) { return MAGICVALUE; @@ -91,12 +93,13 @@ contract AccountExtension is ContractMetadata, ERC1271, AccountPermissions, ERC7 /** * @notice Returns the hash of message that should be signed for EIP1271 verification. - * @param message Message to be hashed i.e. `keccak256(abi.encode(data))` + * @param _message The raw abi encoded data to hash and sign i.e. `abi.encode(data)` * @return Hashed message */ - function getMessageHash(bytes memory message) public view returns (bytes32) { - bytes32 messageHash = keccak256(abi.encode(MSG_TYPEHASH, keccak256(message))); - return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), messageHash)); + function getMessageHash(bytes memory _message) public view returns (bytes32) { + bytes32 messageHash = keccak256(_message); + bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, messageHash)); + return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); } /*/////////////////////////////////////////////////////////////// diff --git a/src/test/smart-wallet/AccountVulnPOC.t.sol b/src/test/smart-wallet/AccountVulnPOC.t.sol index 6ffd8b6ad..9fa399d46 100644 --- a/src/test/smart-wallet/AccountVulnPOC.t.sol +++ b/src/test/smart-wallet/AccountVulnPOC.t.sol @@ -278,8 +278,8 @@ contract SimpleAccountVulnPOCTest is BaseTest { // However they can bypass this by using signature verification on number contract instead vm.prank(accountSigner); - bytes32 digest = keccak256(abi.encode(42)); - bytes32 toSign = SimpleAccount(payable(account)).getMessageHash(abi.encode(digest)); + bytes memory data = abi.encode(42); + bytes32 toSign = SimpleAccount(payable(account)).getMessageHash(data); (uint8 v, bytes32 r, bytes32 s) = vm.sign(accountSignerPKey, toSign); bytes memory signature = abi.encodePacked(r, s, v); From 1e9fe4160d69855f10e05fe33bcdeada1cbc9cbc Mon Sep 17 00:00:00 2001 From: Krishang Date: Mon, 26 Feb 2024 00:55:59 +0530 Subject: [PATCH 09/12] Update _originalMessageHash -> _hash --- .../prebuilts/account/non-upgradeable/Account.sol | 11 ++++++++--- .../prebuilts/account/utils/AccountExtension.sol | 11 ++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/contracts/prebuilts/account/non-upgradeable/Account.sol b/contracts/prebuilts/account/non-upgradeable/Account.sol index 46b585f1c..cc20b1e9f 100644 --- a/contracts/prebuilts/account/non-upgradeable/Account.sol +++ b/contracts/prebuilts/account/non-upgradeable/Account.sol @@ -62,12 +62,17 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115 super.supportsInterface(interfaceId); } - /// @notice See EIP-1271 + /** + * @notice See EIP-1271 + * + * @param _hash The original message hash of the data to sign (before mixing this contract's domain separator) + * @param _signature The signature produced on signing the typed data hash (result of `getMessageHash(abi.encode(rawData))`) + */ function isValidSignature( - bytes32 _originalMessageHash, + bytes32 _hash, bytes memory _signature ) public view virtual override returns (bytes4 magicValue) { - bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, _originalMessageHash)); + bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, _hash)); bytes32 targetDigest = keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); address signer = targetDigest.recover(_signature); diff --git a/contracts/prebuilts/account/utils/AccountExtension.sol b/contracts/prebuilts/account/utils/AccountExtension.sol index d747edfb5..f7c8353b9 100644 --- a/contracts/prebuilts/account/utils/AccountExtension.sol +++ b/contracts/prebuilts/account/utils/AccountExtension.sol @@ -64,12 +64,17 @@ contract AccountExtension is ContractMetadata, ERC1271, AccountPermissions, ERC7 super.supportsInterface(interfaceId); } - /// @notice See EIP-1271 + /** + * @notice See EIP-1271 + * + * @param _hash The original message hash of the data to sign (before mixing this contract's domain separator) + * @param _signature The signature produced on signing the typed data hash (result of `getMessageHash(abi.encode(rawData))`) + */ function isValidSignature( - bytes32 _originalMessageHash, + bytes32 _hash, bytes memory _signature ) public view virtual override returns (bytes4 magicValue) { - bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, _originalMessageHash)); + bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, _hash)); bytes32 targetDigest = keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); address signer = targetDigest.recover(_signature); From 76d5e39b6901b9060e5255d68bba210c5cf22919 Mon Sep 17 00:00:00 2001 From: Krishang Date: Mon, 26 Feb 2024 03:50:37 +0530 Subject: [PATCH 10/12] Replay protection for seaport bulk order sig --- contracts/extension/SeaportOrderEIP1271.sol | 33 ++-- contracts/extension/SeaportOrderParser.sol | 14 +- src/test/seaport/AccountBulkOrderSig.t.sol | 3 +- src/test/seaport/EIP712MerkleTree.sol | 161 ++++++++++++++++++-- 4 files changed, 176 insertions(+), 35 deletions(-) diff --git a/contracts/extension/SeaportOrderEIP1271.sol b/contracts/extension/SeaportOrderEIP1271.sol index 6b1ba8fb1..62e2c3bb8 100644 --- a/contracts/extension/SeaportOrderEIP1271.sol +++ b/contracts/extension/SeaportOrderEIP1271.sol @@ -16,12 +16,17 @@ contract SeaportOrderEIP1271 is SeaportOrderParser, ERC1271 { bytes32 private immutable HASHED_NAME = keccak256("Account"); bytes32 private immutable HASHED_VERSION = keccak256("1"); - /// @notice See EIP-1271 + /** + * @notice See EIP-1271 + * + * @param _hash The original message hash of the data to sign (before mixing this contract's domain separator) + * @param _signature The signature produced on signing the typed data hash (result of `getMessageHash(abi.encode(rawData))`) + */ function isValidSignature( - bytes32 _message, + bytes32 _hash, bytes memory _signature ) public view virtual override returns (bytes4 magicValue) { - bytes32 targetDigest; + bytes32 targetHash; bytes memory targetSig; // Handle OpenSea bulk order signatures that are >65 bytes in length. @@ -33,26 +38,27 @@ contract SeaportOrderEIP1271 is SeaportOrderParser, ERC1271 { ); // Verify that the original digest matches the digest built with order parameters. - bytes32 domainSeparator = _buildDomainSeparator(msg.sender); + bytes32 domainSeparator = _buildSeaportDomainSeparator(msg.sender); bytes32 orderHash = _deriveOrderHash(orderParameters, counter); require( - _deriveEIP712Digest(domainSeparator, orderHash) == _message, + _deriveEIP712Digest(domainSeparator, orderHash) == _hash, "Seaport: order hash does not match the provided message." ); - // Build bulk signature digest - targetDigest = _deriveEIP712Digest(domainSeparator, _computeBulkOrderProof(extractedPackedSig, orderHash)); - + // Build bulk order hash + targetHash = _deriveEIP712Digest(domainSeparator, _computeBulkOrderProof(extractedPackedSig, orderHash)); // Extract the signature, which is the first 65 bytes targetSig = new bytes(65); for (uint i = 0; i < 65; i++) { targetSig[i] = extractedPackedSig[i]; } } else { - targetDigest = getMessageHash(abi.encode(_message)); + targetHash = _hash; targetSig = _signature; } + bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, targetHash)); + bytes32 targetDigest = keccak256(abi.encodePacked("\x19\x01", _buildDomainSeparator(), typedDataHash)); address signer = targetDigest.recover(targetSig); AccountPermissionsStorage.Data storage data = AccountPermissionsStorage.data(); @@ -76,12 +82,13 @@ contract SeaportOrderEIP1271 is SeaportOrderParser, ERC1271 { /** * @notice Returns the hash of message that should be signed for EIP1271 verification. - * @param message Message to be hashed i.e. `keccak256(abi.encode(data))` + * @param _message The raw abi encoded data to hash and sign i.e. `abi.encode(data)` * @return Hashed message */ - function getMessageHash(bytes memory message) public view returns (bytes32) { - bytes32 messageHash = keccak256(abi.encode(MSG_TYPEHASH, keccak256(message))); - return keccak256(abi.encodePacked("\x19\x01", _buildDomainSeparator(), messageHash)); + function getMessageHash(bytes memory _message) public view returns (bytes32) { + bytes32 messageHash = keccak256(_message); + bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, messageHash)); + return keccak256(abi.encodePacked("\x19\x01", _buildDomainSeparator(), typedDataHash)); } /// @notice Returns whether the given account is an active signer on the account. diff --git a/contracts/extension/SeaportOrderParser.sol b/contracts/extension/SeaportOrderParser.sol index 6aa8865a0..9cd586315 100644 --- a/contracts/extension/SeaportOrderParser.sol +++ b/contracts/extension/SeaportOrderParser.sol @@ -7,12 +7,12 @@ import { EIP_712_PREFIX, EIP712_ConsiderationItem_size, EIP712_DigestPayload_siz contract SeaportOrderParser { uint256 constant ECDSA_MaxLength = 65; - bytes32 internal immutable _NAME_HASH; - bytes32 internal immutable _VERSION_HASH; - bytes32 internal immutable _EIP_712_DOMAIN_TYPEHASH; - bytes32 internal immutable _OFFER_ITEM_TYPEHASH; - bytes32 internal immutable _CONSIDERATION_ITEM_TYPEHASH; - bytes32 internal immutable _ORDER_TYPEHASH; + bytes32 private immutable _NAME_HASH; + bytes32 private immutable _VERSION_HASH; + bytes32 private immutable _EIP_712_DOMAIN_TYPEHASH; + bytes32 private immutable _OFFER_ITEM_TYPEHASH; + bytes32 private immutable _CONSIDERATION_ITEM_TYPEHASH; + bytes32 private immutable _ORDER_TYPEHASH; constructor() { ( @@ -30,7 +30,7 @@ contract SeaportOrderParser { return "Seaport"; } - function _buildDomainSeparator(address _domainAddress) internal view returns (bytes32) { + function _buildSeaportDomainSeparator(address _domainAddress) internal view returns (bytes32) { return keccak256(abi.encode(_EIP_712_DOMAIN_TYPEHASH, _NAME_HASH, _VERSION_HASH, block.chainid, _domainAddress)); } diff --git a/src/test/seaport/AccountBulkOrderSig.t.sol b/src/test/seaport/AccountBulkOrderSig.t.sol index bb646f321..8e4a174db 100644 --- a/src/test/seaport/AccountBulkOrderSig.t.sol +++ b/src/test/seaport/AccountBulkOrderSig.t.sol @@ -296,7 +296,8 @@ contract AccountBulkOrderSigTest is BaseTest { // The other order components can remain empty. EIP712MerkleTree merkleTree = new EIP712MerkleTree(); - bytes memory packedSignature = merkleTree.signBulkOrder( + bytes memory packedSignature = merkleTree.signBulkOrderSmartAccount( + sender, ConsiderationInterface(address(seaport)), accountAdminPKey, orderComponents, diff --git a/src/test/seaport/EIP712MerkleTree.sol b/src/test/seaport/EIP712MerkleTree.sol index 6c7b1fc84..5ab8789da 100644 --- a/src/test/seaport/EIP712MerkleTree.sol +++ b/src/test/seaport/EIP712MerkleTree.sol @@ -28,6 +28,12 @@ contract MerkleUnsorted is MurkyBase { } contract EIP712MerkleTree is Test { + bytes32 private constant MSG_TYPEHASH = keccak256("AccountMessage(bytes message)"); + bytes32 private constant TYPEHASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + bytes32 private immutable HASHED_NAME = keccak256("Account"); + bytes32 private immutable HASHED_VERSION = keccak256("1"); + // data contract to retrieve bulk order typehashes TypehashDirectory internal immutable _typehashDirectory; OrderComponents private emptyOrderComponents; @@ -38,13 +44,64 @@ contract EIP712MerkleTree is Test { merkle = new MerkleUnsorted(); } + // /** + // * @dev Creates a single bulk signature: a base signature + a three byte + // * index + a series of 32 byte proofs. The height of the tree is determined + // * by the length of the orderComponents array and only fills empty orders + // * into the tree to make the length a power of 2. + // */ + // function signBulkOrder( + // ConsiderationInterface consideration, + // uint256 privateKey, + // OrderComponents[] memory orderComponents, + // uint24 orderIndex, + // bool useCompact2098 + // ) public view returns (bytes memory) { + // // cache the hash of an empty order components struct to fill out any + // // nodes required to make the length a power of 2 + // bytes32 emptyComponentsHash = consideration.getOrderHash(emptyOrderComponents); + // // declare vars here to avoid stack too deep errors + // bytes32[] memory leaves; + // bytes32 bulkOrderTypehash; + // // block scope to avoid stacc 2 dank + // { + // // height of merkle tree is log2(length), rounded up to next power + // // of 2 + // uint256 height = Math.log2(orderComponents.length); + // // Murky won't let you compute a merkle tree with only 1 leaf, so + // // if height is 0 (length is 1), set height to 1 + // if (2 ** height != orderComponents.length || height == 0) { + // height += 1; + // } + // // get the typehash for a bulk order of this height + // bulkOrderTypehash = _lookupBulkOrderTypehash(height); + // // allocate array for leaf hashes + // leaves = new bytes32[](2 ** height); + // // hash each original order component + // for (uint256 i = 0; i < orderComponents.length; i++) { + // leaves[i] = consideration.getOrderHash(orderComponents[i]); + // } + // // fill out empty node hashes + // for (uint256 i = orderComponents.length; i < 2 ** height; i++) { + // leaves[i] = emptyComponentsHash; + // } + // } + + // // get the proof for the order index + // bytes32[] memory proof = merkle.getProof(leaves, orderIndex); + // bytes32 root = merkle.getRoot(leaves); + + // return _getSignature(consideration, privateKey, bulkOrderTypehash, root, proof, orderIndex, useCompact2098); + // } + /** * @dev Creates a single bulk signature: a base signature + a three byte * index + a series of 32 byte proofs. The height of the tree is determined * by the length of the orderComponents array and only fills empty orders * into the tree to make the length a power of 2. */ - function signBulkOrder( + function signBulkOrderSmartAccount( + address _account, ConsiderationInterface consideration, uint256 privateKey, OrderComponents[] memory orderComponents, @@ -85,7 +142,17 @@ contract EIP712MerkleTree is Test { bytes32[] memory proof = merkle.getProof(leaves, orderIndex); bytes32 root = merkle.getRoot(leaves); - return _getSignature(consideration, privateKey, bulkOrderTypehash, root, proof, orderIndex, useCompact2098); + return + _getSignatureSmartAccount( + _account, + consideration, + privateKey, + bulkOrderTypehash, + root, + proof, + orderIndex, + useCompact2098 + ); } /** @@ -100,7 +167,51 @@ contract EIP712MerkleTree is Test { } } - function _getSignature( + // function _getSignature( + // ConsiderationInterface consideration, + // uint256 privateKey, + // bytes32 bulkOrderTypehash, + // bytes32 root, + // bytes32[] memory proof, + // uint24 orderIndex, + // bool useCompact2098 + // ) internal view returns (bytes memory) { + // // bulkOrder hash is keccak256 of the specific bulk order typehash and + // // the merkle root of the order hashes + // bytes32 bulkOrderHash = keccak256(abi.encode(bulkOrderTypehash, root)); + + // // get domain separator from the particular seaport instance + // (, bytes32 domainSeparator, ) = consideration.information(); + + // // declare out here to avoid stack too deep errors + // bytes memory signature; + // // avoid stacc 2 thicc + // { + // (uint8 v, bytes32 r, bytes32 s) = vm.sign( + // privateKey, + // keccak256(abi.encodePacked(bytes2(0x1901), domainSeparator, bulkOrderHash)) + // ); + // // if useCompact2098 is true, encode yParity (v) into s + // if (useCompact2098) { + // uint256 yParity = (v == 27) ? 0 : 1; + // bytes32 yAndS = bytes32(uint256(s) | (yParity << 255)); + // signature = abi.encodePacked(r, yAndS); + // } else { + // signature = abi.encodePacked(r, s, v); + // } + // } + + // // return the packed signature, order index, and proof + // // encodePacked will pack everything tightly without lengths + // // ie, long-style rsv signatures will have 1 byte for v + // // orderIndex will be the next 3 bytes + // // then proof will be each element one after another; its offset and + // // length will not be encoded + // return abi.encodePacked(signature, orderIndex, proof); + // } + + function _getSignatureSmartAccount( + address _smartAccount, ConsiderationInterface consideration, uint256 privateKey, bytes32 bulkOrderTypehash, @@ -116,22 +227,22 @@ contract EIP712MerkleTree is Test { // get domain separator from the particular seaport instance (, bytes32 domainSeparator, ) = consideration.information(); + bytes32 targetDigest = _getTargetDigest(domainSeparator, bulkOrderHash, _smartAccount); + // declare out here to avoid stack too deep errors bytes memory signature; // avoid stacc 2 thicc { - (uint8 v, bytes32 r, bytes32 s) = vm.sign( - privateKey, - keccak256(abi.encodePacked(bytes2(0x1901), domainSeparator, bulkOrderHash)) - ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, targetDigest); + signature = abi.encodePacked(r, s, v); // if useCompact2098 is true, encode yParity (v) into s - if (useCompact2098) { - uint256 yParity = (v == 27) ? 0 : 1; - bytes32 yAndS = bytes32(uint256(s) | (yParity << 255)); - signature = abi.encodePacked(r, yAndS); - } else { - signature = abi.encodePacked(r, s, v); - } + // if (useCompact2098) { + // uint256 yParity = (v == 27) ? 0 : 1; + // bytes32 yAndS = bytes32(uint256(s) | (yParity << 255)); + // signature = abi.encodePacked(r, yAndS); + // } else { + // signature = abi.encodePacked(r, s, v); + // } } // return the packed signature, order index, and proof @@ -142,4 +253,26 @@ contract EIP712MerkleTree is Test { // length will not be encoded return abi.encodePacked(signature, orderIndex, proof); } + + function _getTargetDigest( + bytes32 _seaportDomainSeparator, + bytes32 _bulkOrderHash, + address _account + ) internal view returns (bytes32) { + bytes32 typedDataHash = keccak256( + abi.encode( + MSG_TYPEHASH, + keccak256(abi.encodePacked(bytes2(0x1901), _seaportDomainSeparator, _bulkOrderHash)) + ) + ); + bytes32 targetDigest = keccak256( + abi.encodePacked("\x19\x01", _buildDomainSeparatorSmartAccount(_account), typedDataHash) + ); + + return targetDigest; + } + + function _buildDomainSeparatorSmartAccount(address _account) private view returns (bytes32) { + return keccak256(abi.encode(TYPEHASH, HASHED_NAME, HASHED_VERSION, block.chainid, _account)); + } } From 3d5691bd0a9dfeb2b50317256e3f391611a194f7 Mon Sep 17 00:00:00 2001 From: Krishang Date: Mon, 26 Feb 2024 04:50:32 +0530 Subject: [PATCH 11/12] EIP712 signature for isValidSignature --- .../prebuilts/account/non-upgradeable/Account.sol | 12 +++++------- .../prebuilts/account/utils/AccountExtension.sol | 12 +++++------- src/test/smart-wallet/AccountVulnPOC.t.sol | 4 ++-- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/contracts/prebuilts/account/non-upgradeable/Account.sol b/contracts/prebuilts/account/non-upgradeable/Account.sol index cc20b1e9f..e8cea3243 100644 --- a/contracts/prebuilts/account/non-upgradeable/Account.sol +++ b/contracts/prebuilts/account/non-upgradeable/Account.sol @@ -72,9 +72,7 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115 bytes32 _hash, bytes memory _signature ) public view virtual override returns (bytes4 magicValue) { - bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, _hash)); - bytes32 targetDigest = keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); - + bytes32 targetDigest = getMessageHash(_hash); address signer = targetDigest.recover(_signature); if (isAdmin(signer)) { @@ -96,11 +94,11 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115 /** * @notice Returns the hash of message that should be signed for EIP1271 verification. - * @param _message The raw abi encoded data to hash and sign i.e. `abi.encode(data)` - * @return Hashed message + * @param _hash The message hash to sign for the EIP-1271 origin verifying contract. + * @return messageHash The digest to sign for EIP-1271 verification. */ - function getMessageHash(bytes memory _message) public view returns (bytes32) { - bytes32 messageHash = keccak256(_message); + function getMessageHash(bytes32 _hash) public view returns (bytes32) { + bytes32 messageHash = keccak256(abi.encode(_hash)); bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, messageHash)); return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); } diff --git a/contracts/prebuilts/account/utils/AccountExtension.sol b/contracts/prebuilts/account/utils/AccountExtension.sol index f7c8353b9..b2ceca2b7 100644 --- a/contracts/prebuilts/account/utils/AccountExtension.sol +++ b/contracts/prebuilts/account/utils/AccountExtension.sol @@ -74,9 +74,7 @@ contract AccountExtension is ContractMetadata, ERC1271, AccountPermissions, ERC7 bytes32 _hash, bytes memory _signature ) public view virtual override returns (bytes4 magicValue) { - bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, _hash)); - bytes32 targetDigest = keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); - + bytes32 targetDigest = getMessageHash(_hash); address signer = targetDigest.recover(_signature); if (isAdmin(signer)) { @@ -98,11 +96,11 @@ contract AccountExtension is ContractMetadata, ERC1271, AccountPermissions, ERC7 /** * @notice Returns the hash of message that should be signed for EIP1271 verification. - * @param _message The raw abi encoded data to hash and sign i.e. `abi.encode(data)` - * @return Hashed message + * @param _hash The message hash to sign for the EIP-1271 origin verifying contract. + * @return messageHash The digest to sign for EIP-1271 verification. */ - function getMessageHash(bytes memory _message) public view returns (bytes32) { - bytes32 messageHash = keccak256(_message); + function getMessageHash(bytes32 _hash) public view returns (bytes32) { + bytes32 messageHash = keccak256(abi.encode(_hash)); bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, messageHash)); return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); } diff --git a/src/test/smart-wallet/AccountVulnPOC.t.sol b/src/test/smart-wallet/AccountVulnPOC.t.sol index 9fa399d46..b9087f70d 100644 --- a/src/test/smart-wallet/AccountVulnPOC.t.sol +++ b/src/test/smart-wallet/AccountVulnPOC.t.sol @@ -278,8 +278,8 @@ contract SimpleAccountVulnPOCTest is BaseTest { // However they can bypass this by using signature verification on number contract instead vm.prank(accountSigner); - bytes memory data = abi.encode(42); - bytes32 toSign = SimpleAccount(payable(account)).getMessageHash(data); + bytes32 digest = keccak256(abi.encode(42)); + bytes32 toSign = SimpleAccount(payable(account)).getMessageHash(digest); (uint8 v, bytes32 r, bytes32 s) = vm.sign(accountSignerPKey, toSign); bytes memory signature = abi.encodePacked(r, s, v); From b361cc1efba41e7608744858f3b5cf12fd199c86 Mon Sep 17 00:00:00 2001 From: Krishang Date: Mon, 26 Feb 2024 04:52:30 +0530 Subject: [PATCH 12/12] EIP712 typed data signature for isValidSignature --- .../prebuilts/account/non-upgradeable/Account.sol | 12 +++++------- .../prebuilts/account/utils/AccountExtension.sol | 12 +++++------- src/test/smart-wallet/AccountVulnPOC.t.sol | 4 ++-- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/contracts/prebuilts/account/non-upgradeable/Account.sol b/contracts/prebuilts/account/non-upgradeable/Account.sol index cc20b1e9f..e8cea3243 100644 --- a/contracts/prebuilts/account/non-upgradeable/Account.sol +++ b/contracts/prebuilts/account/non-upgradeable/Account.sol @@ -72,9 +72,7 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115 bytes32 _hash, bytes memory _signature ) public view virtual override returns (bytes4 magicValue) { - bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, _hash)); - bytes32 targetDigest = keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); - + bytes32 targetDigest = getMessageHash(_hash); address signer = targetDigest.recover(_signature); if (isAdmin(signer)) { @@ -96,11 +94,11 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115 /** * @notice Returns the hash of message that should be signed for EIP1271 verification. - * @param _message The raw abi encoded data to hash and sign i.e. `abi.encode(data)` - * @return Hashed message + * @param _hash The message hash to sign for the EIP-1271 origin verifying contract. + * @return messageHash The digest to sign for EIP-1271 verification. */ - function getMessageHash(bytes memory _message) public view returns (bytes32) { - bytes32 messageHash = keccak256(_message); + function getMessageHash(bytes32 _hash) public view returns (bytes32) { + bytes32 messageHash = keccak256(abi.encode(_hash)); bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, messageHash)); return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); } diff --git a/contracts/prebuilts/account/utils/AccountExtension.sol b/contracts/prebuilts/account/utils/AccountExtension.sol index f7c8353b9..b2ceca2b7 100644 --- a/contracts/prebuilts/account/utils/AccountExtension.sol +++ b/contracts/prebuilts/account/utils/AccountExtension.sol @@ -74,9 +74,7 @@ contract AccountExtension is ContractMetadata, ERC1271, AccountPermissions, ERC7 bytes32 _hash, bytes memory _signature ) public view virtual override returns (bytes4 magicValue) { - bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, _hash)); - bytes32 targetDigest = keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); - + bytes32 targetDigest = getMessageHash(_hash); address signer = targetDigest.recover(_signature); if (isAdmin(signer)) { @@ -98,11 +96,11 @@ contract AccountExtension is ContractMetadata, ERC1271, AccountPermissions, ERC7 /** * @notice Returns the hash of message that should be signed for EIP1271 verification. - * @param _message The raw abi encoded data to hash and sign i.e. `abi.encode(data)` - * @return Hashed message + * @param _hash The message hash to sign for the EIP-1271 origin verifying contract. + * @return messageHash The digest to sign for EIP-1271 verification. */ - function getMessageHash(bytes memory _message) public view returns (bytes32) { - bytes32 messageHash = keccak256(_message); + function getMessageHash(bytes32 _hash) public view returns (bytes32) { + bytes32 messageHash = keccak256(abi.encode(_hash)); bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, messageHash)); return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash)); } diff --git a/src/test/smart-wallet/AccountVulnPOC.t.sol b/src/test/smart-wallet/AccountVulnPOC.t.sol index 9fa399d46..b9087f70d 100644 --- a/src/test/smart-wallet/AccountVulnPOC.t.sol +++ b/src/test/smart-wallet/AccountVulnPOC.t.sol @@ -278,8 +278,8 @@ contract SimpleAccountVulnPOCTest is BaseTest { // However they can bypass this by using signature verification on number contract instead vm.prank(accountSigner); - bytes memory data = abi.encode(42); - bytes32 toSign = SimpleAccount(payable(account)).getMessageHash(data); + bytes32 digest = keccak256(abi.encode(42)); + bytes32 toSign = SimpleAccount(payable(account)).getMessageHash(digest); (uint8 v, bytes32 r, bytes32 s) = vm.sign(accountSignerPKey, toSign); bytes memory signature = abi.encodePacked(r, s, v);