diff --git a/.env.example b/.env.example index 74981144..5e6ebc3e 100644 --- a/.env.example +++ b/.env.example @@ -15,5 +15,8 @@ SETTLEMENT=0x9008D19f58AAbD9eD0D60971565AA8510560ab41 # SAFE= # TWAP= +# Owner of the rotatable handlers, read by deploy_GnosisStack. +# ADMIN= + # Read by dev/verify-contracts.sh, and by forge script --verify. # ETHERSCAN_API_KEY= diff --git a/.gas-snapshot b/.gas-snapshot index 737a38ee..2cf9e8aa 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -8,36 +8,36 @@ ComposableCowDescriptorDocTest:test_descriptor_SelectorMatchesDeclaredName() (ga ComposableCowDescriptorDocTest:test_descriptor_SelectorsAreDistinct() (gas: 163733) ComposableCowDiscoveryTest:test_SetUpState_ComposableCowDomainSeparator_is_set() (gas: 11305) ComposableCowDiscoveryTest:test_SetUpState_ComposableCowDomainVerifier_is_set() (gas: 18325) -ComposableCowDiscoveryTest:test_descriptor_CommittedAdvertisesAndRoundTrips() (gas: 2033244) -ComposableCowDiscoveryTest:test_descriptor_ConstructorEmitsUpdate() (gas: 2027846) -ComposableCowDiscoveryTest:test_descriptor_UncommittedDoesNotAdvertise() (gas: 1931847) -ComposableCowDiscoveryTest:test_module_CommittedAdvertisesAndRoundTrips() (gas: 1498629) -ComposableCowDiscoveryTest:test_module_ContentAddressedNeedsNoURI() (gas: 1398108) -ComposableCowDiscoveryTest:test_module_NeedsInputSignal() (gas: 1405789) -ComposableCowDiscoveryTest:test_module_RevertsContentAddressedWithURI() (gas: 39723) -ComposableCowDiscoveryTest:test_module_RevertsSha256WithoutURI() (gas: 38899) -ComposableCowDiscoveryTest:test_module_RevertsUncommittedURI() (gas: 40273) -ComposableCowDiscoveryTest:test_module_UncommittedDoesNotAdvertise() (gas: 1395475) +ComposableCowDiscoveryTest:test_descriptor_CommittedAdvertisesAndRoundTrips() (gas: 2061293) +ComposableCowDiscoveryTest:test_descriptor_ConstructorEmitsUpdate() (gas: 2055583) +ComposableCowDiscoveryTest:test_descriptor_UncommittedDoesNotAdvertise() (gas: 1919984) +ComposableCowDiscoveryTest:test_module_CommittedAdvertisesAndRoundTrips() (gas: 1526676) +ComposableCowDiscoveryTest:test_module_ContentAddressedNeedsNoURI() (gas: 1406046) +ComposableCowDiscoveryTest:test_module_NeedsInputSignal() (gas: 1413627) +ComposableCowDiscoveryTest:test_module_RevertsContentAddressedWithURI() (gas: 40179) +ComposableCowDiscoveryTest:test_module_RevertsSha256WithoutURI() (gas: 39351) +ComposableCowDiscoveryTest:test_module_RevertsUncommittedURI() (gas: 40730) +ComposableCowDiscoveryTest:test_module_UncommittedDoesNotAdvertise() (gas: 1383610) ComposableCowForwarderTest:test_ERC1271Forwarder_isValidSignature_RevertsOnBadHash() (gas: 630770) ComposableCowForwarderTest:test_SetUpState_ComposableCowDomainSeparator_is_set() (gas: 11443) ComposableCowForwarderTest:test_SetUpState_ComposableCowDomainVerifier_is_set() (gas: 18481) ComposableCowGatTest:test_SetUpState_ComposableCowDomainSeparator_is_set() (gas: 11487) ComposableCowGatTest:test_SetUpState_ComposableCowDomainVerifier_is_set() (gas: 18657) -ComposableCowGatTest:test_generateOrder_FuzzContext(address,address,address,uint256,uint256,uint256,uint256,bool) (runs: 256, μ: 121422, ~: 121420) +ComposableCowGatTest:test_generateOrder_FuzzContext(address,address,address,uint256,uint256,uint256,uint256,bool) (runs: 256, μ: 121422, ~: 121422) ComposableCowGatTest:test_generateOrder_FuzzRevertBeforeStartTime(uint256,uint256) (runs: 256, μ: 21804, ~: 21804) -ComposableCowGatTest:test_generateOrder_FuzzRevertBelowMinBalance(uint256,uint256) (runs: 256, μ: 114446, ~: 114454) -ComposableCowGatTest:test_generateOrder_FuzzRevertTooLowOutput(uint256,uint256,uint256) (runs: 256, μ: 124256, ~: 124320) +ComposableCowGatTest:test_generateOrder_FuzzRevertBelowMinBalance(uint256,uint256) (runs: 256, μ: 114446, ~: 114453) +ComposableCowGatTest:test_generateOrder_FuzzRevertTooLowOutput(uint256,uint256,uint256) (runs: 256, μ: 124242, ~: 124309) ComposableCowGatTest:test_generateOrder_RevertZeroAmount() (gas: 113369) -ComposableCowGatTest:test_generateOrder_e2e_Fuzz(uint256,uint256,uint256,uint256,uint256,uint256) (runs: 256, μ: 299418, ~: 299344) -ComposableCowGatTest:test_generateOrder_e2e_FuzzWithPriceChecker(uint256,uint256,uint256,uint256,uint256) (runs: 256, μ: 308759, ~: 308596) +ComposableCowGatTest:test_generateOrder_e2e_Fuzz(uint256,uint256,uint256,uint256,uint256,uint256) (runs: 256, μ: 299402, ~: 299342) +ComposableCowGatTest:test_generateOrder_e2e_FuzzWithPriceChecker(uint256,uint256,uint256,uint256,uint256) (runs: 256, μ: 308748, ~: 308594) ComposableCowGatTest:test_pollHints_SingleShot() (gas: 16098) ComposableCowGatTest:test_settle_e2e() (gas: 491417) -ComposableCowGatTest:test_verify_e2e_fuzz(uint256,uint256,uint256,uint256,uint256) (runs: 256, μ: 137200, ~: 137037) +ComposableCowGatTest:test_verify_e2e_fuzz(uint256,uint256,uint256,uint256,uint256) (runs: 256, μ: 137188, ~: 137035) ComposableCowGuardsTest:test_BaseSwapGuard_supportsInterface() (gas: 138710) ComposableCowGuardsTest:test_ReceiverLock_verify_FuzzRevertsWhenReceiverNotSelf(address) (runs: 256, μ: 299499, ~: 299499) ComposableCowGuardsTest:test_SetUpState_ComposableCowDomainSeparator_is_set() (gas: 11487) ComposableCowGuardsTest:test_SetUpState_ComposableCowDomainVerifier_is_set() (gas: 18546) -ComposableCowGuardsTest:test_setSwapGuard_FuzzSetAndEmit(address,address) (runs: 256, μ: 31254, ~: 31236) +ComposableCowGuardsTest:test_setSwapGuard_FuzzSetAndEmit(address,address) (runs: 256, μ: 31255, ~: 31236) ComposableCowGuardsTest:test_setSwapGuard_e2e() (gas: 1030509) ComposableCowManifestTest:test_PSS_ManifestPage_NotFundedCarriesStatus() (gas: 37596) ComposableCowManifestTest:test_PSS_ManifestPage_WithBalance() (gas: 125366) @@ -60,6 +60,17 @@ ComposableCowManifestTest:test_manifestPage_EmptyPageCarriesWaitReason() (gas: 1 ComposableCowManifestTest:test_manifestPage_OutOfRangeTerminates() (gas: 1545516) ComposableCowManifestTest:test_manifest_DoesNotPerturbGeneratorInterfaceId() (gas: 855) ComposableCowManifestTest:test_manifest_SupportsInterface() (gas: 1538778) +ComposableCowOwnedTest:test_SetUpState_ComposableCowDomainSeparator_is_set() (gas: 11327) +ComposableCowOwnedTest:test_SetUpState_ComposableCowDomainVerifier_is_set() (gas: 18281) +ComposableCowOwnedTest:test_owned_EnforcesURIInvariants() (gas: 25516) +ComposableCowOwnedTest:test_owned_OrderGenerationIsUnchanged() (gas: 1937389) +ComposableCowOwnedTest:test_owned_RenounceFreezesCommitment() (gas: 48085) +ComposableCowOwnedTest:test_owned_RevertsForStranger() (gas: 18088) +ComposableCowOwnedTest:test_owned_RotationReplacesCommitment() (gas: 116420) +ComposableCowOwnedTest:test_owned_SetDescriptorAdvertisesAndRoundTrips() (gas: 49376) +ComposableCowOwnedTest:test_owned_SetModuleIsIndependentOfDescriptor() (gas: 156097) +ComposableCowOwnedTest:test_owned_TransferIsTwoStep() (gas: 42923) +ComposableCowOwnedTest:test_owned_UncommittedOnDeploy() (gas: 21473) ComposableCowPollTest:test_SetUpState_ComposableCowDomainSeparator_is_set() (gas: 11531) ComposableCowPollTest:test_SetUpState_ComposableCowDomainVerifier_is_set() (gas: 19119) ComposableCowPollTest:test_checkOrder_ComposesFillOverlay() (gas: 1833891) @@ -80,9 +91,9 @@ ComposableCowPollTest:test_poll_DecodesPollNeedsOffchainInput() (gas: 1402236) ComposableCowPollTest:test_poll_DecodesPollTryAtBlock() (gas: 1330995) ComposableCowPollTest:test_poll_DecodesPollTryAtTimestamp() (gas: 1330907) ComposableCowPollTest:test_poll_DecodesPollTryNextBlock() (gas: 1290285) -ComposableCowPollTest:test_poll_FuzzOrderNotValid(bytes4) (runs: 256, μ: 1283632, ~: 1291095) -ComposableCowPollTest:test_poll_FuzzPollTryAtBlock(uint256,bytes4) (runs: 256, μ: 1323738, ~: 1330890) -ComposableCowPollTest:test_poll_FuzzPollTryAtTimestamp(uint256,bytes4) (runs: 256, μ: 1324266, ~: 1331418) +ComposableCowPollTest:test_poll_FuzzOrderNotValid(bytes4) (runs: 256, μ: 1283943, ~: 1291095) +ComposableCowPollTest:test_poll_FuzzPollTryAtBlock(uint256,bytes4) (runs: 256, μ: 1323272, ~: 1330890) +ComposableCowPollTest:test_poll_FuzzPollTryAtTimestamp(uint256,bytes4) (runs: 256, μ: 1323800, ~: 1331418) ComposableCowPollTest:test_poll_NeedsInputHandlerPostsWithInput() (gas: 1404879) ComposableCowPollTest:test_poll_PanicMapsToTryNextBlock() (gas: 1294536) ComposableCowPollTest:test_poll_ReturnsPostOnValidOrder() (gas: 1763768) @@ -107,7 +118,7 @@ ComposableCowProofTest:test_setRoot_RevertsZeroRootWithBlobs() (gas: 13434) ComposableCowProofTest:test_setRoot_RevertsZeroRootWithUris() (gas: 12784) ComposableCowProofTest:test_setRoot_ZeroRootClears() (gas: 32934) ComposableCowStopLossTest:test_OracleNormalisesPrice_concrete() (gas: 27435) -ComposableCowStopLossTest:test_OracleNormalisesPrice_fuzz(uint8,uint8,uint8,uint8) (runs: 256, μ: 29593, ~: 29613) +ComposableCowStopLossTest:test_OracleNormalisesPrice_fuzz(uint8,uint8,uint8,uint8) (runs: 256, μ: 29592, ~: 29607) ComposableCowStopLossTest:test_OracleRevertOnExpiredOrder_fuzz(uint32,uint32) (runs: 256, μ: 23185, ~: 23185) ComposableCowStopLossTest:test_OracleRevertOnInvalidPrice_fuzz(int256,int256) (runs: 256, μ: 36635, ~: 36635) ComposableCowStopLossTest:test_OracleRevertOnStalePrice_fuzz(uint256,uint256,uint256) (runs: 256, μ: 25348, ~: 25348) @@ -118,15 +129,15 @@ ComposableCowStopLossTest:test_generateOrder_RevertZeroAmount() (gas: 22286) ComposableCowStopLossTest:test_pollHints_SingleShot() (gas: 15780) ComposableCowStopLossTest:test_strikePriceMet_fuzz(int256,int256,int256,uint32) (runs: 256, μ: 29077, ~: 29077) ComposableCowStopLossTest:test_strikePriceNotMet_concrete() (gas: 26555) -ComposableCowTatTest:test_BalanceMet_fuzz(address,uint256,bytes32,uint256) (runs: 256, μ: 113402, ~: 113386) +ComposableCowTatTest:test_BalanceMet_fuzz(address,uint256,bytes32,uint256) (runs: 256, μ: 113403, ~: 113384) ComposableCowTatTest:test_SetUpState_ComposableCowDomainSeparator_is_set() (gas: 11283) ComposableCowTatTest:test_SetUpState_ComposableCowDomainVerifier_is_set() (gas: 18177) -ComposableCowTatTest:test_generateOrder_FuzzRevertBelowThreshold(uint256,uint256) (runs: 256, μ: 111617, ~: 111620) +ComposableCowTatTest:test_generateOrder_FuzzRevertBelowThreshold(uint256,uint256) (runs: 256, μ: 111619, ~: 111626) ComposableCowTest:test_SetUpState_ComposableCowDomainSeparator_is_set() (gas: 11575) ComposableCowTest:test_SetUpState_ComposableCowDomainVerifier_is_set() (gas: 18877) -ComposableCowTest:test_createAndRemove_FuzzSetAndEmit(address,address,bytes32,bytes) (runs: 256, μ: 39997, ~: 39883) +ComposableCowTest:test_createAndRemove_FuzzSetAndEmit(address,address,bytes32,bytes) (runs: 256, μ: 40000, ~: 39883) ComposableCowTest:test_createAndRemove_e2e() (gas: 468135) -ComposableCowTest:test_createWithContextAndRemove_FuzzSetAndEmit(address,address,bytes32,bytes,bytes32) (runs: 256, μ: 63661, ~: 63592) +ComposableCowTest:test_createWithContextAndRemove_FuzzSetAndEmit(address,address,bytes32,bytes,bytes32) (runs: 256, μ: 63662, ~: 63594) ComposableCowTest:test_create_RevertOnInvalidHandler() (gas: 10433) ComposableCowTest:test_getTradeableOrderWithSignature_FuzzRevertInvalidProof(address,bytes32[],bytes32,address,bytes32,bytes) (runs: 256, μ: 97007, ~: 96804) ComposableCowTest:test_getTradeableOrderWithSignature_FuzzRevertInvalidSingleOrder(address,address,bytes32,bytes) (runs: 256, μ: 18659, ~: 18642) @@ -136,24 +147,24 @@ ComposableCowTest:test_getTradeableOrderWithSignature_RevertInterfaceNotSupporte ComposableCowTest:test_isValidSafeSignature_BaseConditionalOrder_RevertOnInvalidHash() (gas: 60746) ComposableCowTest:test_isValidSafeSignature_FuzzPassesContextToHandler(address,bytes32) (runs: 256, μ: 57671, ~: 57671) ComposableCowTest:test_isValidSafeSignature_FuzzRevertInvalidProof(address,bytes32[],bytes32,address,bytes32,bytes) (runs: 256, μ: 98629, ~: 98333) -ComposableCowTest:test_isValidSafeSignature_FuzzRevertInvalidSingleOrder(address,address,bytes32,bytes) (runs: 256, μ: 18637, ~: 18615) +ComposableCowTest:test_isValidSafeSignature_FuzzRevertInvalidSingleOrder(address,address,bytes32,bytes) (runs: 256, μ: 18638, ~: 18615) ComposableCowTest:test_remove_EmitsConditionalOrderRemoved() (gas: 36281) -ComposableCowTest:test_remove_FuzzEmitsEvent(address,bytes32) (runs: 256, μ: 31569, ~: 31544) +ComposableCowTest:test_remove_FuzzEmitsEvent(address,bytes32) (runs: 256, μ: 31570, ~: 31544) ComposableCowTest:test_safeSignaturePayload_SelectorMatchesMuxerMagicValue() (gas: 1145) ComposableCowTest:test_setRootWithContext_FuzzSetAndEmit(address,bytes32,bytes32) (runs: 256, μ: 73696, ~: 73774) ComposableCowTest:test_setRootWithContext_e2e() (gas: 13599638) -ComposableCowTest:test_setRoot_FuzzSetAndEmit(address,bytes32) (runs: 256, μ: 41952, ~: 42105) +ComposableCowTest:test_setRoot_FuzzSetAndEmit(address,bytes32) (runs: 256, μ: 42028, ~: 42105) ComposableCowTest:test_setRoot_e2e() (gas: 13568277) ComposableCowTwapTest:test_SetUpState_ComposableCowDomainSeparator_is_set() (gas: 11488) ComposableCowTwapTest:test_SetUpState_ComposableCowDomainVerifier_is_set() (gas: 18987) -ComposableCowTwapTest:test_TWAPOrderMathLib_calculateValidTo(uint256,uint256,uint256,uint256,uint256) (runs: 256, μ: 12642, ~: 12389) +ComposableCowTwapTest:test_TWAPOrderMathLib_calculateValidTo(uint256,uint256,uint256,uint256,uint256) (runs: 256, μ: 12636, ~: 12389) ComposableCowTwapTest:test_describeOrder_RevertOnZeroFrequency() (gas: 21049) ComposableCowTwapTest:test_describeOrder_TwapParts() (gas: 29107) ComposableCowTwapTest:test_generateOrder_FuzzRevertIfBeforeStart(uint256,uint256) (runs: 256, μ: 29035, ~: 29035) ComposableCowTwapTest:test_generateOrder_FuzzRevertIfExpired(uint256,uint256) (runs: 256, μ: 30257, ~: 30108) ComposableCowTwapTest:test_generateOrder_FuzzRevertIfOrderAfterBlocktimestampValidity(uint256,uint256) (runs: 256, μ: 186801, ~: 187176) ComposableCowTwapTest:test_generateOrder_FuzzRevertIfOrderBeforeBlockTimestamp(uint256,uint256) (runs: 256, μ: 187290, ~: 187290) -ComposableCowTwapTest:test_generateOrder_FuzzRevertIfOutsideSpan(uint256,uint256) (runs: 256, μ: 32236, ~: 32137) +ComposableCowTwapTest:test_generateOrder_FuzzRevertIfOutsideSpan(uint256,uint256) (runs: 256, μ: 32285, ~: 32137) ComposableCowTwapTest:test_generateOrder_FuzzRevertOnInvalidFrequency(uint256) (runs: 256, μ: 19744, ~: 19747) ComposableCowTwapTest:test_generateOrder_FuzzRevertOnInvalidNumParts(uint256) (runs: 256, μ: 19601, ~: 19605) ComposableCowTwapTest:test_generateOrder_FuzzRevertOnInvalidSpan(uint256,uint256) (runs: 256, μ: 20164, ~: 20164) @@ -169,5 +180,19 @@ ComposableCowTwapTest:test_getNextPollTimestamp_PointsAtNextPart() (gas: 20153) ComposableCowTwapTest:test_getNextPollTimestamp_RevertOnZeroFrequency() (gas: 19285) ComposableCowTwapTest:test_getNextPollTimestamp_RevertOnZeroNumParts() (gas: 19451) ComposableCowTwapTest:test_settle_e2e() (gas: 13514423) -ComposableCowTwapTest:test_simulate_fuzz(uint32,uint32,uint32) (runs: 256, μ: 20619419, ~: 21359116) -ComposableCowTwapTest:test_verify_e2e_fuzz(uint256,uint256) (runs: 256, μ: 36221, ~: 35995) \ No newline at end of file +ComposableCowTwapTest:test_simulate_fuzz(uint32,uint32,uint32) (runs: 256, μ: 20318564, ~: 20794728) +ComposableCowTwapTest:test_verify_e2e_fuzz(uint256,uint256) (runs: 256, μ: 36221, ~: 35995) +DeployAddressTest:test_predict_AdminMovesHandlersOnly() (gas: 125019) +DeployAddressTest:test_predict_IsTheSameOnEveryChain() (gas: 185119) +DeployAddressTest:test_predict_MatchesCreate2() (gas: 73174) +DeployAddressTest:test_predict_TwapEncodesTheRegistryNotTheSettlement() (gas: 94443) +DeployAddressTest:test_predict_TwapFollowsTheRegistry() (gas: 124229) +DeployStackTest:test_validate_AcceptsAValidConfig() (gas: 12459) +DeployStackTest:test_validate_RejectsCodelessSettlement() (gas: 13780) +DeployStackTest:test_validate_RejectsWrongChain() (gas: 13497) +DeployStackTest:test_validate_RejectsZeroOwner() (gas: 13402) +DescriptorPublishTest:test_descriptor_DigestIsTheDocumentsSha256() (gas: 22715) +DescriptorPublishTest:test_descriptor_OptionalWhenUriUnset() (gas: 7536) +DescriptorPublishTest:test_descriptor_RejectsANonHttpsUri() (gas: 13730) +DescriptorPublishTest:test_descriptor_RequiresTheOwnerKey() (gas: 12366) +DescriptorPublishTest:test_isHttps() (gas: 13639) \ No newline at end of file diff --git a/README.md b/README.md index 4037caee..3dcd185e 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ The following audits cover the **upstream** contracts before the changes in this ### Environment setup -Copy `.env.example` to `.env`. Every script reads `PRIVATE_KEY`; `SETTLEMENT` is needed to deploy `ComposableCow`, `COMPOSABLE_COW` to deploy order types against it, and `SAFE` plus `TWAP` to submit a single order. Contract verification reads `ETHERSCAN_API_KEY`. The RPC endpoint is passed per command with `--rpc-url`. +Copy `.env.example` to `.env`. Every script reads `PRIVATE_KEY`; `SETTLEMENT` is needed to deploy `ComposableCow`, `COMPOSABLE_COW` to deploy order types against it, and `SAFE` plus `TWAP` to submit a single order. The Gnosis integration deployment also reads `ADMIN`. Contract verification reads `ETHERSCAN_API_KEY`. The RPC endpoint is passed per command with `--rpc-url`. ### Testing diff --git a/broadcast/deploy_OwnedStack.s.sol/1/run-1785761019907.json b/broadcast/deploy_OwnedStack.s.sol/1/run-1785761019907.json new file mode 100644 index 00000000..4a9baf62 --- /dev/null +++ b/broadcast/deploy_OwnedStack.s.sol/1/run-1785761019907.json @@ -0,0 +1,156 @@ +{ + "transactions": [ + { + "hash": "0x873ec994d57f818ef4375e861ffd2c3e5666978927bcf6e9742e147836a88ac5", + "transactionType": "CREATE2", + "contractName": "ComposableCow", + "contractAddress": "0xf9ba6f64c9b41df1cee76a50e2039d3847064232", + "function": null, + "arguments": [ + "0x9008D19f58AAbD9eD0D60971565AA8510560ab41" + ], + "transaction": { + "from": "0x6e17cac0db135a5c6a9fa45758e2a314b399bf00", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "gas": "0x3173f5", + "value": "0x0", + "input": "0x000000000000000000000000000000000000000000000000000000000000000060c080604052346100ca5760208161282c803803809161001f82856100e1565b8339810103126100ca57516001600160a01b038116908190036100ca576020816004926080526040519283809263f698da2560e01b82525afa9081156100d6575f916100a0575b5060a0526040516127139081610119823960805181818161072d0152612691015260a051818181610ece01528181612304015261252a0152f35b90506020813d6020116100ce575b816100bb602093836100e1565b810103126100ca57515f610066565b5f80fd5b3d91506100ae565b6040513d5f823e3d90fd5b601f909101601f19168101906001600160401b0382119082101761010457604052565b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c80630960c249146101145780630d0d98001461010f5780631c7662c81461010a57806326e0a19614610105578063511606301461010057806353f00b14146100fb5780635500079d146100f6578063595001b2146100f15780636108c532146100ec5780636bfae1ca146100e7578063738f7bf1146100e25780637ca3baa1146100dd5780638f7984ed146100d857806395bc2673146100d3578063a4546876146100ce5763f698da25146100c9575f80fd5b610eb7565b610e6f565b610de0565b610d30565b610cda565b610b6b565b610b0b565b610aaf565b610a34565b6109f1565b610751565b610701565b6106ae565b610398565b6101ec565b61012b565b908160409103126101275790565b5f80fd5b346101275760406003193601126101275760243560043567ffffffffffffffff821161012757610162610179923690600401610119565b604051916101716020846108aa565b5f83526117c7565b005b908160609103126101275790565b73ffffffffffffffffffffffffffffffffffffffff81160361012757565b9181601f840112156101275782359167ffffffffffffffff8311610127576020838186019501011161012757565b8015150361012757565b35906101ea826101d5565b565b346101275760806003193601126101275760043567ffffffffffffffff81116101275761021d90369060040161017b565b6024359061022a82610189565b6044359167ffffffffffffffff83116101275760206102506102ba9436906004016101a7565b91906064359361025f856101d5565b610268866118da565b9373ffffffffffffffffffffffffffffffffffffffff6040518099819582947fb6576bdf0000000000000000000000000000000000000000000000000000000084528860048501526024840191611619565b0392165afa9283156103885761035461032894610179965f91610359575b5080610313856103063373ffffffffffffffffffffffffffffffffffffffff165f52600360205260405f2090565b905f5260205260405f2090565b55604051958691602083019190602083019252565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018652856108aa565b611945565b61037b915060203d602011610381575b61037381836108aa565b810190611936565b5f6102d8565b503d610369565b611333565b35906101ea82610189565b34610127576040600319360112610127576004356103b581610189565b73ffffffffffffffffffffffffffffffffffffffff60243591165f52600360205260405f20905f52602052602060405f2054604051908152f35b9060806003198301126101275760043561040881610189565b9160243567ffffffffffffffff811161012757816104289160040161017b565b9160443567ffffffffffffffff81116101275782610448916004016101a7565b9290929160643567ffffffffffffffff811161012757826023820112156101275780600401359267ffffffffffffffff84116101275760248460051b83010111610127576024019190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b600611156104ca57565b610493565b61016080916104f484825173ffffffffffffffffffffffffffffffffffffffff169052565b60208181015173ffffffffffffffffffffffffffffffffffffffff169085015260408181015173ffffffffffffffffffffffffffffffffffffffff1690850152606081015160608501526080810151608085015261055f60a082015160a086019063ffffffff169052565b60c081015160c085015260e081015160e085015261010081015161010085015261059461012082015161012086019015159052565b6101408101516101408501520151910152565b600411156104ca57565b9060048210156104ca5752565b600211156104ca57565b9060028210156104ca5752565b908151805160068110156104ca576101ea937fffffffff000000000000000000000000000000000000000000000000000000006080610240946060948752610625602082015160208901906104cf565b60408101516101a0880152848101516101c08801520151166101e085015261065660208201516102008601906105b1565b604081015161022085015201519101906105c8565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b34610127576106df6106f36106d16106c5366103ef565b94939093929192611004565b6040519384939284906105d5565b61028061026084015261028083019061066b565b0390f35b5f91031261012757565b34610127575f60031936011261012757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101275760e06003193601126101275760043561076e81610189565b6024359061077b82610189565b604435916064359160a43567ffffffffffffffff8111610127576107a39036906004016101a7565b9060c4359467ffffffffffffffff8611610127576106f3966107cc6107d49736906004016101a7565b96909561133e565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681529081906020820190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761085057604052565b610807565b6080810190811067ffffffffffffffff82111761085057604052565b60a0810190811067ffffffffffffffff82111761085057604052565b610180810190811067ffffffffffffffff82111761085057604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761085057604052565b604051906101ea610180836108aa565b604051906101ea6060836108aa565b67ffffffffffffffff811161085057601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b9291926109508261090a565b9161095e60405193846108aa565b829481845281830111610127578281602093845f960137010152565b9080601f830112156101275781602061099593359101610944565b90565b919060608382031261012757604051906109b182610834565b819380356109be81610189565b83526020810135602084015260408101359167ffffffffffffffff8311610127576040926109ec920161097a565b910152565b346101275760206003193601126101275760043567ffffffffffffffff811161012757610a2c610a276020923690600401610998565b6114b7565b604051908152f35b346101275760206003193601126101275773ffffffffffffffffffffffffffffffffffffffff600435610a6681610189565b165f52600260205273ffffffffffffffffffffffffffffffffffffffff60405f205416604051809173ffffffffffffffffffffffffffffffffffffffff60208301911682520390f35b3461012757604060031936011261012757600435610acc81610189565b73ffffffffffffffffffffffffffffffffffffffff60243591165f52600160205260405f20905f52602052602060ff60405f2054166040519015158152f35b346101275760406003193601126101275760043567ffffffffffffffff811161012757610b3f61017991369060040161017b565b602435610b4b816101d5565b610b54826118da565b60405192610b636020856108aa565b5f8452611945565b346101275760806003193601126101275760043560243567ffffffffffffffff811161012757610b9f903690600401610119565b9060443591610bad83610189565b60643567ffffffffffffffff811161012757610c2993610bd360209236906004016101a7565b5f9291925073ffffffffffffffffffffffffffffffffffffffff6040518098819582947fb6576bdf0000000000000000000000000000000000000000000000000000000084528860048501526024840191611619565b0392165afa91821561038857610cb6610c8a93610179955f91610cbb575b5080610c755f6103063373ffffffffffffffffffffffffffffffffffffffff165f52600360205260405f2090565b55604051948591602083019190602083019252565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018552846108aa565b6117c7565b610cd4915060203d6020116103815761037381836108aa565b5f610c47565b3461012757610260610d21610d1b610d14610cf4366103ef565b9196929590610d01610f05565b50610d0c3686610998565b923691610fa1565b9084611a4c565b91611d82565b610d2e60405180926105d5565bf35b3461012757602060031936011261012757600435610d4d81610189565b335f52600260205260405f2073ffffffffffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790557f41f583e2d25b3921afe66987b63b0b5e4cf2acbbbed4a477fd19a22180f3f85960405173ffffffffffffffffffffffffffffffffffffffff60208201931681528033930390a2005b3461012757602060031936011261012757600435335f52600160205260405f20815f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008154169055335f52600360205260405f20815f526020525f6040812055337f67e0f2b23e842ce65d7edff49765689c9c0931f911fc5971d09bb598cc1af4a95f80a3005b346101275760206003193601126101275773ffffffffffffffffffffffffffffffffffffffff600435610ea181610189565b165f525f602052602060405f2054604051908152f35b34610127575f6003193601126101275760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b60405190610f006020836108aa565b5f8252565b60405190610f1282610855565b5f606083604051610f2281610871565b838152604051610f318161088d565b84815284602082015284604082015284848201528460808201528460a08201528460c08201528460e0820152846101008201528461012082015284610140820152846101608201526020820152836040820152838382015283608082015281528260208201528260408201520152565b9291909267ffffffffffffffff8411610850578360051b906020604051610fca828501826108aa565b809681520191810192831161012757905b828210610fe757505050565b8135815260209182019101610fdb565b5160068110156104ca5790565b9295949195939093611014610f05565b506110408188611039611027368a610998565b611032368989610fa1565b9089611a4c565b8888611d82565b9661104b8851610ff7565b611054816104c0565b6110cf576020880160028151611069816105a7565b611072816105a7565b149081156110fd575b506110cf5760016020890151611090816105a7565b611099816105a7565b14806110dd575b6110cf5760608801516110b2816105be565b6110bb816105be565b6110cf57610995956020895101519561215d565b505050505050610995610ef1565b506110f86110f461012060208b5101510151151590565b1590565b6110a0565b600391505161110b816105a7565b611114816105a7565b145f61107b565b6020818303126101275780359067ffffffffffffffff82116101275701606081830312610127576040519161114f83610834565b813567ffffffffffffffff811161012757820181601f82011215610127578181602061117d93359101610fa1565b8352602082013567ffffffffffffffff8111610127578161119f918401610998565b6020840152604082013567ffffffffffffffff8111610127576111c2920161097a565b604082015290565b63ffffffff81160361012757565b35906101ea826111ca565b9081610180910312610127576101606111fa6108eb565b916112048161038d565b83526112126020820161038d565b60208401526112236040820161038d565b6040840152606081013560608401526080810135608084015261124860a082016111d8565b60a084015260c081013560c084015260e081013560e084015261010081013561010084015261127a61012082016101df565b610120840152610140810135610140840152013561016082015290565b1561129e57565b7f03fc2a7e000000000000000000000000000000000000000000000000000000005f5260045ffd5b989795909461132b946101ea989473ffffffffffffffffffffffffffffffffffffffff61131d958d8260e09b1690521660208d015260408c015260608b015260808a015261026060a08a015261026089019061066b565b9087820360c089015261066b565b9401906104cf565b6040513d5f823e3d90fd5b956113669073ffffffffffffffffffffffffffffffffffffffff92949896939681019061111b565b951690611388602087019461137f865189519086611a4c565b928101906111e3565b936113a66113a186604084519a01998a519086886123b1565b611297565b519360406113e46113cb875173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b9501519651853b15610127575f9761142c936040519a8b998a9889987f14a2a784000000000000000000000000000000000000000000000000000000008a5260048a016112c6565b03915afa801561038857611460575b507f1626ba7e0000000000000000000000000000000000000000000000000000000090565b8061146e5f611474936108aa565b806106f7565b5f61143b565b90606060406109959373ffffffffffffffffffffffffffffffffffffffff815116845260208101516020850152015191816040820152019061066b565b604051611500816114d4602082019460208652604083019061147a565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826108aa565b51902090565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610127570180359067ffffffffffffffff821161012757602001918160051b3603831361012757565b919081101561156a5760051b0190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b1561159e57565b7f6fe76104000000000000000000000000000000000000000000000000000000005f5260045ffd5b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561012757016020813591019167ffffffffffffffff8211610127578160051b3603831361012757565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561012757016020813591019167ffffffffffffffff821161012757813603831361012757565b9081526060602082015260a0810192916116c181806115c6565b809195604060608601525260c083019060c08160051b8501019580925f915b8383106117735750505050508060206116fa9201906115c6565b91907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08286030160808301528285527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311610127576109959460209360051b809285830137019060408382840301910152019061066b565b90919293976020806117b8837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff408b600196030187526117b28d87611657565b90611619565b9a0193019301919392906116e0565b9192821561187b575b5f5b602083016117e08185611506565b9050821015611817579061181161180c6118068361180060019689611506565b9061155a565b35612487565b611597565b016117d2565b5050927faa8df5268339649ef2752ea240168c52869c3ab59c8c64078df854916f1b86d591836118643373ffffffffffffffffffffffffffffffffffffffff165f525f60205260405f2090565b556118766040519283923396846116a7565b0390a2565b6118858280611506565b905015806118ba575b6117d0577f14f5a94c000000000000000000000000000000000000000000000000000000005f5260045ffd5b506118c86020830183611506565b90501561188e565b3561099581610189565b73ffffffffffffffffffffffffffffffffffffffff81356118fa81610189565b161561190e57610a27610995913690610998565b7fd8f59fa5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90816020910312610127575190565b9190335f52600160205260405f20905f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905561198e575050565b6119fd7f681609694274e6398a06f0051ec46e3ef05ed684d33a23297b5ebda248fcd9a191611876611a0e6040519384936040855273ffffffffffffffffffffffffffffffffffffffff81356119e381610189565b166040860152602081013560608601526040810190611657565b6060608086015260a0850191611619565b8281036020840152339561066b565b15611a2457565b7f4a821464000000000000000000000000000000000000000000000000000000005f5260045ffd5b82515f9493929015611ae157611a61906114b7565b5f52611a8e60205f209173ffffffffffffffffffffffffffffffffffffffff165f525f60205260405f2090565b549082519283611aa5575b506101ea925014611a1d565b8060208092019460051b0101905b8351811160051b90815260208451911852602060405f20930192818410611ab35790506101ea92505f611a99565b611b0391945073ffffffffffffffffffffffffffffffffffffffff92506114b7565b92165f52600160205260405f20825f5260205260ff60405f20541615611b2557565b7f7a933234000000000000000000000000000000000000000000000000000000005f5260045ffd5b51906101ea826101d5565b908160209103126101275751610995816101d5565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610127570180359067ffffffffffffffff82116101275760200191813603831361012757565b51906101ea82610189565b51906101ea826111ca565b51907fffffffff000000000000000000000000000000000000000000000000000000008216820361012757565b8091039061020082126101275760405191611c1b83610871565b8151600681101561012757610180917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09185520112610127576101e0611d2591611c636108eb565b611c6f60208301611bbe565b8152611c7d60408301611bbe565b6020820152611c8e60608301611bbe565b60408201526080820151606082015260a08201516080820152611cb360c08301611bc9565b60a082015260e082015160c082015261010082015160e0820152610120820151610100820152611ce66101408301611b4d565b61012082015261016082015161014082015261018082015161016082015260208501526101a081015160408501526101c0810151606085015201611bd4565b608082015290565b94929093611d689273ffffffffffffffffffffffffffffffffffffffff61099598961687526020870152608060408701526080860191611619565b926060818503910152611619565b60048210156104ca5752565b919294939094611d90610f05565b95611da36113cb6113cb6113cb846118d0565b602060405180927f01ffc9a70000000000000000000000000000000000000000000000000000000082528180611e0060048201907ff97f095600000000000000000000000000000000000000000000000000000000602083019252565b03915afa5f9181612030575b50611e39577f2c7ca6d7000000000000000000000000000000000000000000000000000000005f5260045ffd5b1561200857611e506113cb6113cb6113cb846118d0565b610200611e606040840184611b6d565b928888611e9e8989604051988997889687967f36eed5f600000000000000000000000000000000000000000000000000000000885260048801611d2d565b03915afa908115610388575f91611fd9575b5080885251611ebe816104c0565b611ec7816104c0565b15611ed4575b5050505050565b611f1494611f0393611efc6110f494611ef460208c510151953690610998565b923691610944565b91866123b1565b611fcd575b60208451015190612513565b80604084015280155f14611f3457505f60208301525b5f80808080611ecd565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8103611f6d575060036020830152611f2a565b611f2a565b8251602001516101008101517ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677503611fc35760600151905b10611fb957611f6860025b60208401611d76565b611f686001611fb0565b6080015190611fa5565b60016060850152611f08565b611ffb91506102003d8111612001575b611ff381836108aa565b810190611c01565b5f611eb0565b503d611fe9565b7f2c7ca6d7000000000000000000000000000000000000000000000000000000005f5260045ffd5b61205391925060203d60201161205a575b61204b81836108aa565b810190611b58565b905f611e0c565b503d612041565b610180810192916101ea91906104cf565b80516060808452815190840181905260808401949391602001905f5b8181106120c55750505060406120b461099594956020850151848203602086015261147a565b92015190604081840391015261066b565b825187526020968701969092019160010161208e565b906020610995928181520190612072565b9161212f90610995949284527fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e489602085015260806040850152608084019061066b565b91606081840391015261066b565b8061214f6101a09261099595946104cf565b816101808201520190612072565b95949593909193602060405180927f01ffc9a70000000000000000000000000000000000000000000000000000000082528173ffffffffffffffffffffffffffffffffffffffff816121d660048201907f62af8dc200000000000000000000000000000000000000000000000000000000602083019252565b0392165afa5f9181612354575b5061223657509161221361099595949261220a61221f956122026108fb565b993691610fa1565b88523690610998565b60208701523691610944565b60408401526114d46040519384926020840161213d565b959192949093951561232c57610c8a95610995956122b36122d3956122aa61226e9861229a6122bf976040519b8c9160208301612061565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018c528b6108aa565b6122a26108fb565b973691610fa1565b86523690610998565b60208501523691610944565b6040820152604051948591602083016120db565b6114d46040519384927f5fd7e97d0000000000000000000000000000000000000000000000000000000060208501527f0000000000000000000000000000000000000000000000000000000000000000602485016120ec565b7f79ac63cd000000000000000000000000000000000000000000000000000000005f5260045ffd5b61236e91925060203d60201161205a5761204b81836108aa565b905f6121e3565b926109959492612388856123a2946104cf565b6101808501526101e06101a08501526101e084019061147a565b916101c081840391015261066b565b73ffffffffffffffffffffffffffffffffffffffff90949394165f5260026020526123f76113cb60405f2073ffffffffffffffffffffffffffffffffffffffff90541690565b9073ffffffffffffffffffffffffffffffffffffffff821661241d575050505050600190565b602093612459604051968795869485947ff9ae35a200000000000000000000000000000000000000000000000000000000865260048601612375565b03915afa908115610388575f9161246e575090565b610995915060203d60201161205a5761204b81836108aa565b905f5b804980156124fb5783146124f4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146124c75760010161248a565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5060019150565b505f925050565b90602061099592818152019061066b565b602090612645612678936114d46125dd60a06125d17f000000000000000000000000000000000000000000000000000000000000000085907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06042920180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a082209152604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b93015163ffffffff1690565b60405186810193845260609590951b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016602084015260e01b7fffffffff00000000000000000000000000000000000000000000000000000000166034830152839160380190565b604051809381927f2479fb6e00000000000000000000000000000000000000000000000000000000835260048301612502565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa908115610388575f916126c4575090565b610995915060203d6020116103815761037381836108aa56fea2646970667358221220284f9be73c484c05e3dfe348146e007f2bc9026893ca60a56bb8d5a42d05f64864736f6c634300081e00330000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41", + "nonce": "0x2", + "chainId": "0x1" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x8bd480bff240fc7f34e8a7852f244940ebdefb93ee8808265b50b4655d522760", + "transactionType": "CREATE2", + "contractName": "OwnedTWAP", + "contractAddress": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91", + "function": null, + "arguments": [ + "0xf9ba6F64c9b41Df1cEe76A50e2039D3847064232", + "0x6e17cAc0db135A5C6A9FA45758e2A314b399BF00" + ], + "transaction": { + "from": "0x6e17cac0db135a5c6a9fa45758e2a314b399bf00", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "gas": "0x465565", + "value": "0x0", + "input": "0x000000000000000000000000000000000000000000000000000000000000000060a06040523461062857613ec66040813803918261001c8161064b565b938492833981010312610628578051906001600160a01b038216820361062857602001516001600160a01b03811691908290036106285761005b6106fb565b906100646106fb565b805151906020810180519260408301938451906002821015610228576105fa57506103ee575b8151805190680100000000000000008211610358575f54825f55808310610579575b505f8080525f516020613ea65f395f51905f5292916020015b82821061047457505050508051600155825160028110156102285760ff80196002541691161760025551908161042b575b505050608052805151906020810180519260408301938451906002821015610228576103fd57506103ee575b8151805190680100000000000000008211610358576003548260035580831061036c575b5060035f9081525f516020613e865f395f51905f5292916020015b82821061023c57505050508051600455825160028110156102285760ff8019600554169116176005555190816101df575b8380638b78c6d819555f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a36040516136fe908161078882396080518181816110df01526128450152f35b5191519160028310156102285761021d7fe1d44331b30c93e74db74c814c88415da5d48e865502fd54dc27efb376995f739360405193849384610670565b0390a15f8080610192565b634e487b7160e01b5f52602160045260245ffd5b80518051906001600160401b038211610358576102598654610739565b601f811161031d575b50602090601f83116001146102b4579261029a836001959460209487965f926102a9575b50508160011b915f199060031b1c19161790565b87555b01940191019092610161565b015190505f80610286565b90601f19831691875f52815f20925f5b81811061030557509360209360019693879693838895106102ed575b505050811b01875561029d565b01515f1960f88460031b161c191690555f80806102e0565b929360206001819287860151815501950193016102c4565b61034890875f5260205f20601f850160051c8101916020861061034e575b601f0160051c0190610771565b5f610262565b909150819061033b565b634e487b7160e01b5f52604160045260245ffd5b60035f525f516020613e865f395f51905f529081019083015b8181106103925750610146565b8061039f60019254610739565b806103ac575b5001610385565b601f811183146103c157505f81555b5f6103a5565b6103dd90825f5283601f60205f20920160051c82019101610771565b805f525f60208120818355556103bb565b63e293d02560e01b5f5260045ffd5b600103610417576101225763b522a9f360e01b5f5260045ffd5b1561012257637c549cbb60e11b5f5260045ffd5b519151916002831015610228576104697ffe5ca6316fce32d692eb4adafe8d133e02a1936b75e56709cf1b413673a228199360405193849384610670565b0390a15f80806100f6565b80518051906001600160401b038211610358576104918654610739565b601f8111610549575b50602090601f83116001146104e057926104d1836001959460209487965f926102a95750508160011b915f199060031b1c19161790565b87555b019401910190926100c5565b90601f19831691875f52815f20925f5b8181106105315750936020936001969387969383889510610519575b505050811b0187556104d4565b01515f1960f88460031b161c191690555f808061050c565b929360206001819287860151815501950193016104f0565b61057390875f5260205f20601f850160051c8101916020861061034e57601f0160051c0190610771565b5f61049a565b5f80525f516020613ea65f395f51905f529081019083015b81811061059e57506100ac565b806105ab60019254610739565b806105b8575b5001610591565b601f811183146105cd57505f81555b5f6105b1565b6105e990825f5283601f60205f20920160051c82019101610771565b805f525f60208120818355556105c7565b6001036106145761008a5763b522a9f360e01b5f5260045ffd5b1561008a57637c549cbb60e11b5f5260045ffd5b5f80fd5b60405190606082016001600160401b0381118382101761035857604052565b6040519190601f01601f191682016001600160401b0381118382101761035857604052565b9093929193606082016060835281518091526080830190602060808260051b8601019301915f905b8282106106b8575050505093602082015260028210156102285760400152565b9091929360208080600193607f198a82030186528189518051918291828552018484015e5f828201840152601f01601f1916010196019493919091019101610698565b5f604061070661062c565b60608152826020820152015261071c602061064b565b5f815261072761062c565b9081525f60208201525f604082015290565b90600182811c92168015610767575b602083101461075357565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610748565b81811061077c575050565b5f815560010161077156fe60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a71461019457806314a2a7841461018f578063256929621461018a5780632cfe09fb146101855780632e242d37146101805780633618005b1461017b57806336eed5f6146101765780633859f494146101715780634665dc751461016c57806354d1f13d1461016757806359e367e514610162578063715018a61461015d5780637dd03ac91461015857806384d1b38c146101535780638b2e24191461014e5780638da5cb5b1461014957806393504c5214610144578063ae7d5a5b1461013f578063d6ae74421461013a578063e888a3a514610135578063f04e283e14610130578063f2fde38b1461012b578063fb4c2ad1146101265763fee81cf414610121575f80fd5b6114a3565b611438565b6113f9565b6113a8565b611278565b61124f565b6111c5565b6110b3565b611061565b61103c565b610f0f565b610d7f565b610d00565b610bf4565b610a21565b6109d3565b6109aa565b6108f8565b610831565b61076d565b61048b565b610307565b610251565b6101c7565b7fffffffff000000000000000000000000000000000000000000000000000000008116036101c357565b5f80fd5b346101c35760206003193601126101c35760206101ee6004356101e981610199565b6114d9565b6040519015158152f35b73ffffffffffffffffffffffffffffffffffffffff8116036101c357565b3590610221826101f8565b565b9181601f840112156101c35782359167ffffffffffffffff83116101c357602083818601950101116101c357565b346101c3576102606003193601126101c35760043561026f816101f8565b61027a6024356101f8565b60643560443560843560a43567ffffffffffffffff81116101c3576102a3903690600401610223565b9160c43567ffffffffffffffff81116101c3576102c4903690600401610223565b9590946101807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1c3601126101c3576102fb9761181f565b005b5f9103126101c357565b5f6003193601126101c35763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b60806003198201126101c357600435610368816101f8565b916024359160443567ffffffffffffffff81116101c3578161038c91600401610223565b929092916064359067ffffffffffffffff82116101c3576103af91600401610223565b9091565b61016080916103d884825173ffffffffffffffffffffffffffffffffffffffff169052565b60208181015173ffffffffffffffffffffffffffffffffffffffff169085015260408181015173ffffffffffffffffffffffffffffffffffffffff1690850152606081015160608501526080810151608085015261044360a082015160a086019063ffffffff169052565b60c081015160c085015260e081015160e085015261010081015161010085015261047861012082015161012086019015159052565b6101408101516101408501520151910152565b346101c3576101806104aa61049f36610350565b5050929190916119bf565b6104b760405180926103b3565bf35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761050257604052565b6104b9565b610180810190811067ffffffffffffffff82111761050257604052565b60a0810190811067ffffffffffffffff82111761050257604052565b610140810190811067ffffffffffffffff82111761050257604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761050257604052565b604051906102216101808361055d565b604051906102216101408361055d565b6040519061022160a08361055d565b6040519061022160608361055d565b6040519061022160408361055d565b6040519061022160808361055d565b63ffffffff8116036101c357565b3590610221826105fa565b801515036101c357565b359061022182610613565b6101e06003198201126101c357600435610641816101f8565b91602435916044359167ffffffffffffffff83116101c35761018061068a837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c95600401610223565b9490949301126101c35761069c61059e565b6106a66064610216565b81526106b26084610216565b60208201526106c160a4610216565b604082015260c435606082015260e43560808201526106e1610104610608565b60a08201526101243560c08201526101443560e08201526101643561010082015261070d61018461061d565b6101208201526101a4356101408201526101c43561016082015290565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b346101c35761079f61078b61078136610628565b5092919091611c58565b60405191829160208352602083019061072a565b0390f35b90816101409103126101c3576101206107ba6105ae565b916107c481610216565b83526107d260208201610216565b60208401526107e360408201610216565b6040840152606081013560608401526080810135608084015260a081013560a084015260c081013560c084015260e081013560e0840152610100810135610100840152013561012082015290565b346101c3576101406003193601126101c3576102fb61084e6105ae565b6108586004610216565b81526108646024610216565b60208201526108736044610216565b60408201526064356060820152608435608082015260a43560a082015260c43560c082015260e43560e082015261010435610100820152610124356101208201526128aa565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9060068210156108f35752565b6108b9565b346101c35761020061091861090c36610350565b94939093929192611f1e565b7fffffffff0000000000000000000000000000000000000000000000000000000060806040519261094a8482516108e6565b61095c602082015160208601906103b3565b60408101516101a085015260608101516101c08501520151166101e0820152f35b600211156108f357565b9060028210156108f35752565b9081526040810192916102219160200190610987565b346101c3575f6003193601126101c35760015460ff600254169061079f60405192839283610994565b346101c35761079f6109f36109e736610350565b9493909392919261206a565b610a0d6040949294519485941515855260208501906103b3565b6101c06101a08401526101c083019061072a565b5f6003193601126101c35763389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2005b67ffffffffffffffff81116105025760051b60200190565b67ffffffffffffffff811161050257601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b359060028210156101c357565b60206003198201126101c35760043567ffffffffffffffff81116101c357606060031982840301126101c35760405191610afd836104e6565b816004013567ffffffffffffffff81116101c357820190806023830112156101c357600482013591610b2e83610a65565b92610b3c604051948561055d565b808452602060048186019260051b84010101918383116101c35760248101915b838310610b89575050505050610b819160449184526024810135602085015201610ab7565b604082015290565b823567ffffffffffffffff81116101c35760049083010185603f820112156101c357602081013591610bba83610a7d565b610bc7604051918261055d565b83815260408385010188106101c3575f602085819660408397018386013783010152815201920191610b5c565b346101c357610c0236610ac4565b610c0a612c01565b8051516020820191825191604082019283519060028210156108f357610ca05750610c3590156135f9565b610c4181516003612db8565b8251600455610c5b8251610c548161097d565b6005612e94565b51915190519160028310156108f357610c9b7fe1d44331b30c93e74db74c814c88415da5d48e865502fd54dc27efb376995f739360405193849384612117565b0390a1005b600103610cd357610c35577fb522a9f3000000000000000000000000000000000000000000000000000000005f5260045ffd5b15610c35577ff8a93976000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f6003193601126101c357610d13612c01565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392755005b346101c357610d8d36610ac4565b610d95612c01565b8051516020820191825191604082019283519060028210156108f357610e255750610dc090156135f9565b610dcb81515f612db8565b8251600155610de58251610dde8161097d565b6002612e94565b51915190519160028310156108f357610c9b7ffe5ca6316fce32d692eb4adafe8d133e02a1936b75e56709cf1b413673a228199360405193849384612117565b600103610e5857610dc0577fb522a9f3000000000000000000000000000000000000000000000000000000005f5260045ffd5b15610dc0577ff8a93976000000000000000000000000000000000000000000000000000000005f5260045ffd5b9080602083519182815201916020808360051b8301019401925f915b838310610eb057505050505090565b9091929394602080610eec837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08660019603018752895161072a565b97019301930191939290610ea1565b906020610f0c928181520190610e85565b90565b346101c3575f6003193601126101c3575f54610f2a81610a65565b610f37604051918261055d565b8181525f8080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639290602083015b828210610f7b576040518061079f8682610efb565b6040515f8654610f8a8161213f565b8084529060018116908115610ffb5750600114610fc4575b5060019282610fb68594602094038261055d565b815201950191019093610f66565b5f888152602081209092505b818310610fe557505081016020016001610fa2565b6001816020925483868801015201920191610fd0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208581019190915291151560051b8401909101915060019050610fa2565b346101c357602061105961104f36610628565b5092919091612190565b604051908152f35b346101c3575f6003193601126101c35760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346101c3575f6003193601126101c357602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b7fffffffff00000000000000000000000000000000000000000000000000000000604080926111338582516108e6565b60208101516020860152015116910152565b909392919360a0820160a083528151809152602060c084019201905f5b818110611182575050509315156020820152610221919060400190611103565b90919260206101e060019260608751805183526111a585820151868501906103b3565b60408101516101a0840152015115156101c0820152019401929101611162565b346101c35760c06003193601126101c3576004356111e2816101f8565b6024359060443567ffffffffffffffff81116101c357611206903690600401610223565b9190926064359267ffffffffffffffff84116101c35761079f94611231611240953690600401610223565b50506084359260a43594612358565b60409391935193849384611145565b346101c3575f6003193601126101c35760045460ff600554169061079f60405192839283610994565b346101c3575f6003193601126101c35760035461129481610a65565b6112a1604051918261055d565b818152602081019160035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b925f905b8282106112e7576040518061079f8682610efb565b6040515f86546112f68161213f565b80845290600181169081156113675750600114611330575b50600192826113228594602094038261055d565b8152019501910190936112d2565b5f888152602081209092505b8183106113515750508101602001600161130e565b600181602092548386880101520192019161133c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208581019190915291151560051b840190910191506001905061130e565b60206003193601126101c3576004356113c0816101f8565b6113c8612c01565b63389a75e1600c52805f526020600c2090815442116113ec575f6102fb9255612ecb565b636f5e88185f526004601cfd5b60206003193601126101c357600435611411816101f8565b611419612c01565b8060601b1561142b576102fb90612ecb565b637448fbae5f526004601cfd5b346101c35760606003193601126101c357600435611455816101f8565b6024356044359167ffffffffffffffff83116101c35761147c611484933690600401610223565b929091612574565b604051815160038110156108f357604092602091835201516020820152f35b346101c35760206003193601126101c3576004356114c0816101f8565b63389a75e1600c525f52602080600c2054604051908152f35b7f3e26d7e7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000082161461152b57610f0c906126ae565b50600454151590565b1561153b57565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527f8ccc2bc90000000000000000000000000000000000000000000000000000000060045260245ffd5b1561158e57565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527fda09e34a0000000000000000000000000000000000000000000000000000000060045260245ffd5b156115e157565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527fc1ab6dc10000000000000000000000000000000000000000000000000000000060045260245ffd5b1561163457565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527f295964ea0000000000000000000000000000000000000000000000000000000060045260245ffd5b1561168757565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527f6cdfb5fe0000000000000000000000000000000000000000000000000000000060045260245ffd5b156116da57565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527fb290253c0000000000000000000000000000000000000000000000000000000060045260245ffd5b1561172d57565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527f92b120810000000000000000000000000000000000000000000000000000000060045260245ffd5b1561178057565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527fe3c2448f0000000000000000000000000000000000000000000000000000000060045260245ffd5b156117d357565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527fef98fad70000000000000000000000000000000000000000000000000000000060045260245ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0949197506042965092611855939592956119bf565b0180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a082209152604051917f190100000000000000000000000000000000000000000000000000000000000083526002830152602282015220036118bb57565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527f0af806e00000000000000000000000000000000000000000000000000000000060045260245ffd5b6040519061191482610507565b5f610160838281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152826101408201520152565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b906001820180921161199a57565b61195f565b9190820180921161199a57565b8181029291811591840414171561199a57565b906119d49392916119ce611907565b50612786565b906119dd611907565b506119e7826128aa565b815173ffffffffffffffffffffffffffffffffffffffff1691611a21602082015173ffffffffffffffffffffffffffffffffffffffff1690565b9061010081611bb2611bad611ba4611a50604085015173ffffffffffffffffffffffffffffffffffffffff1690565b98606085015197608086015160a0870199611af4611a88611a838d5160c08c019d8e5160e082019e8f5192015192613235565b613334565b9d611ad76101208b015195611aba611a9e61059e565b73ffffffffffffffffffffffffffffffffffffffff9099168952565b73ffffffffffffffffffffffffffffffffffffffff166020880152565b73ffffffffffffffffffffffffffffffffffffffff166040860152565b60608401526080830152611b1260a083019b8c9063ffffffff169052565b60c08201525f60e08201527ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467756101008201525f6101208201527f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc96101408201527f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9610160820152985163ffffffff1690565b63ffffffff1690565b421190565b611bbc5750505050565b611c559392611bed611c0693611bf3611bd7611bff95612896565b611bed611be589519261198c565b8451906119ac565b9061199f565b955192519051906119ac565b8210611534565b7f2c9e2059000000000000000000000000000000000000000000000000000000005f526004527ff79955c700000000000000000000000000000000000000000000000000000000602452604490565b5ffd5b90611c64939291612786565b611c6d816128aa565b611c7681612896565b906001820180921161199a5760c001511115611cc757604051611c9a60408261055d565b600f81527f7477617020706172742072656164790000000000000000000000000000000000602082015290565b604051611cd560408261055d565b600f81527f66696e616c207477617020706172740000000000000000000000000000000000602082015290565b60405190611d0f82610524565b5f608083828152611d1e611907565b60208201528260408201528260608201520152565b5190610221826101f8565b5190610221826105fa565b519061022182610613565b90816101809103126101c357610160611d6b61059e565b91611d7581611d33565b8352611d8360208201611d33565b6020840152611d9460408201611d33565b60408401526060810151606084015260808101516080840152611db960a08201611d3e565b60a084015260c081015160c084015260e081015160e0840152610100810151610100840152611deb6101208201611d49565b610120840152610140810151610140840152015161016082015290565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b94929093611e819273ffffffffffffffffffffffffffffffffffffffff610f0c98961687526020870152608060408701526080860191611e08565b926060818503910152611e08565b6040513d5f823e3d90fd5b908160209103126101c3575190565b9594926102219460609373ffffffffffffffffffffffffffffffffffffffff611ee79416895260208901526101e060408901526101e0880191611e08565b9401906103b3565b3d15611f19573d90611f0082610a7d565b91611f0e604051938461055d565b82523d5f602084013e565b606090565b909193611f6a9561018091611f31611d02565b5060405197889283927f2cfe09fb000000000000000000000000000000000000000000000000000000008452888a898960048801611e46565b0381305afa5f9581612039575b50611f91575050505050610f0c611f8c611eef565b612a30565b611fcc8560209460405196879586957f8b2e241900000000000000000000000000000000000000000000000000000000875260048701611ea9565b0381305afa908115612034575f91612005575b50611fe86105be565b915f8352602083015260408201525f60608201525f608082015290565b612027915060203d60201161202d575b61201f818361055d565b810190611e9a565b5f611fdf565b503d612015565b611e8f565b61205c9196506101803d8111612063575b612054818361055d565b810190611d54565b945f611f77565b503d61204a565b9194610180946120b2929461207d611907565b5060405197889687967f2cfe09fb00000000000000000000000000000000000000000000000000000000885260048801611e46565b0381305afa5f91816120f6575b506120dc57506120cd611eef565b6120d5612ba0565b915f929190565b90604051906120ec60208361055d565b5f82526001929190565b6121109192506101803d811161206357612054818361055d565b905f6120bf565b60409061213261022194969593606083526060830190610e85565b9560208201520190610987565b90600182811c92168015612186575b602083101461215957565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f169161214e565b9061219c939291612786565b6121a5816128aa565b6121ae81612896565b6001810180911161199a5760c08201518110156121e5576121d99060e060a0840151930151906119ac565b810180911161199a5790565b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90565b60405190612218826104e6565b5f6040838281528260208201520152565b604051906080820182811067ffffffffffffffff821117610502576040525f606083828152612256611907565b60208201528260408201520152565b6040519061227460208361055d565b5f80835282815b82811061228757505050565b602090612292612229565b8282850101520161227b565b906122a882610a65565b6122b5604051918261055d565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06122e38294610a65565b01905f5b8281106122f357505050565b6020906122fe612229565b828285010152016122e7565b9190820391821161199a57565b805182101561232b5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9290916123709295949561236a61220b565b94612786565b9160a08301511561252a57303b156101c357604080517f3618005b000000000000000000000000000000000000000000000000000000008152845173ffffffffffffffffffffffffffffffffffffffff9081166004830152602086015181166024830152918501519091166044820152606084015160648201526080840151608482015260a084015160a482015260c084015160c482015260e084015160e48201526101008401516101048201526101208401516101248201525f8161014481305afa9081612510575b50612463575050505061244b611eef565b61245c612456612265565b91612f4c565b90915f9190565b939091929360c084015190818610801590612508575b6124f257612487868361230a565b90808210156124ea5750905b61249d828761199f565b10936124a88261229e565b955f5b8381106124b85750505050565b806124ce6124c86001938561199f565b85612fe3565b6124d8828b612317565b526124e3818a612317565b50016124ab565b905090612493565b505092505050612500612265565b61245c612fbc565b508015612479565b8061251e5f6125249361055d565b806102fd565b5f61243a565b50505050612536612265565b61253e6105cd565b600381525f602082018190527f453ffb600000000000000000000000000000000000000000000000000000000060408301529192565b92919060405193604085019480861067ffffffffffffffff871117610502576125a9956040525f81525f602082015250612786565b303b156101c357604080517f3618005b000000000000000000000000000000000000000000000000000000008152825173ffffffffffffffffffffffffffffffffffffffff9081166004830152602084015181166024830152918301519091166044820152606082015160648201526080820151608482015260a082015160a482015260c082015160c482015260e082015160e48201526101008201516101048201526101208201516101248201525f8161014481305afa908161269a575b5061268257506126766105dc565b5f81525f602082015290565b60c0015161268e6105dc565b905f8252602082015290565b8061251e5f6126a89361055d565b5f612668565b7fffffffff00000000000000000000000000000000000000000000000000000000167fbc88471800000000000000000000000000000000000000000000000000000000811461277d577ff97f0956000000000000000000000000000000000000000000000000000000008114908115612753575b811561272c575090565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501490565b7f5531708a0000000000000000000000000000000000000000000000000000000081149150612722565b50600154151590565b9392916127dc91925f61012060405161279e81610540565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015201528101906107a3565b9260a08401908151156127ee57505050565b6040517f1c7662c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526024810193909352602090839060449082907f0000000000000000000000000000000000000000000000000000000000000000165afa918215612034575f92612878575052565b61289291925060203d60201161202d5761201f818361055d565b9052565b610f0c9060e060a082015191015190613357565b610221906129756128cf825173ffffffffffffffffffffffffffffffffffffffff1690565b61292f602084019173ffffffffffffffffffffffffffffffffffffffff61292661290d855173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b91161415611587565b73ffffffffffffffffffffffffffffffffffffffff61296561290d855173ffffffffffffffffffffffffffffffffffffffff1690565b1615159081612a05575b506115da565b6129846060820151151561162d565b61299360808201511515611680565b6129a663ffffffff60a0830151106116d3565b6129bf60c08201516001811190816129f6575b50611726565b61010060e08201916129dc835180151590816129e7575b50611779565b0151905110156117cc565b6301e13380915011155f6129d6565b63ffffffff915011155f6129b9565b51612a28915061290d9073ffffffffffffffffffffffffffffffffffffffff1681565b15155f61296f565b612a38611d02565b50600481511015612a4c5750610f0c613582565b60208101517fffffffff0000000000000000000000000000000000000000000000000000000081167f6ac599b4000000000000000000000000000000000000000000000000000000008114612b8d577f6707bf6a000000000000000000000000000000000000000000000000000000008114612b7a577f2c9e2059000000000000000000000000000000000000000000000000000000008114612b66577f12053d38000000000000000000000000000000000000000000000000000000008114612b52577f01b495a30000000000000000000000000000000000000000000000000000000014612b4057610f0c9150613408565b50612b4d610f0c91613377565b613524565b5050612b60610f0c916135be565b906134c5565b5050612b74610f0c916135be565b90613466565b5050612b88610f0c91613377565b613408565b5050612b9b610f0c91613377565b6133aa565b612ba8611907565b50604051612bb581610507565b5f81525f60208201525f60408201525f60608201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f6101208201525f6101408201525f61016082015290565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543303612c2b57565b6382b429005f526004601cfd5b818110612c43575050565b5f8155600101612c38565b9190601f8111612c5d57505050565b610221925f5260205f20906020601f840160051c83019310612c87575b601f0160051c0190612c38565b9091508190612c7a565b919091825167ffffffffffffffff811161050257612cb981612cb3845461213f565b84612c4e565b6020601f8211600114612d16578190612d079394955f92612d0b575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b9055565b015190505f80612cd5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0821690612d47845f5260205f2090565b915f5b818110612da057509583600195969710612d69575b505050811b019055565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f8080612d5f565b9192602060018192868b015181550194019201612d4a565b815191680100000000000000008311610502578154838355808410612e17575b506020612dea9101915f5260205f2090565b5f915b838310612dfa5750505050565b6001602082612e0b83945186612c91565b01920192019190612ded565b825f528360205f2091820191015b818110612e325750612dd8565b80612e3f6001925461213f565b80612e4c575b5001612e25565b601f81118314612e6157505f81555b5f612e45565b612e839083601f612e75855f5260205f2090565b920160051c82019101612c38565b5f8181526020812081835555612e5b565b9060028110156108f35760ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008354169116179055565b73ffffffffffffffffffffffffffffffffffffffff16807fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a37fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392755565b612f5e90612f5861220b565b50612a30565b80519060068210156108f3577fffffffff0000000000000000000000000000000000000000000000000000000060806060830151920151169060405192612fa4846104e6565b60068110156108f35783526020830152604082015290565b612fc461220b565b50604051612fd1816104e6565b5f81525f60208201525f604082015290565b610f0c90612fef612229565b50612ffa8382613628565b91613003611907565b5061300e8582613628565b905061310e613031835173ffffffffffffffffffffffffffffffffffffffff1690565b92613053602082015173ffffffffffffffffffffffffffffffffffffffff1690565b92613075604083015173ffffffffffffffffffffffffffffffffffffffff1690565b6130f76060840151916130da610120613092608088015196613334565b960151976130bd6130a161059e565b73ffffffffffffffffffffffffffffffffffffffff909b168b52565b73ffffffffffffffffffffffffffffffffffffffff1660208a0152565b73ffffffffffffffffffffffffffffffffffffffff166040880152565b6060860152608085015263ffffffff1660a0840152565b60c08201525f60e08201527ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467756101008201525f6101208201527f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc96101408201527f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc96101608201528142101592836131bf575b506131a96105eb565b9485526020850152604084015215156060830152565b42111592505f6131a0565b156131d157565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b8115613208570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b909392916001851180613326575b61324c906131ca565b80151580613318575b61325e906131ca565b61326a818411156131ca565b4282116132c8576132a2817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff95960283014210611534565b6132ae818342036131fe565b83156132bb570201010190565b6001919293500102010190565b507f2c9e2059000000000000000000000000000000000000000000000000000000005f526004527febab10620000000000000000000000000000000000000000000000000000000060245260445ffd5b506301e13380811115613255565b5063ffffffff851115613243565b64010000000081101561334a5763ffffffff1690565b6335278d125f526004601cfd5b8042106133715742039042821161199a57610f0c916131fe565b50505f90565b905f916024815110156133875750565b6004810151919250906020908201829003126101c35760240151610f0c81610199565b6133b2611d02565b507fffffffff000000000000000000000000000000000000000000000000000000006133dc612ba0565b91604051926133ea84610524565b6004845260208401525f60408401525f606084015216608082015290565b613410611d02565b507fffffffff0000000000000000000000000000000000000000000000000000000061343a612ba0565b916040519261344884610524565b6003845260208401525f60408401525f606084015216608082015290565b907fffffffff0000000000000000000000000000000000000000000000000000000090613491611d02565b5061349a612ba0565b92604051936134a885610524565b6001855260208501525f6040850152606084015216608082015290565b907fffffffff00000000000000000000000000000000000000000000000000000000906134f0611d02565b506134f9612ba0565b926040519361350785610524565b6002855260208501525f6040850152606084015216608082015290565b61352c611d02565b507fffffffff00000000000000000000000000000000000000000000000000000000613556612ba0565b916040519261356484610524565b6005845260208401525f60408401525f606084015216608082015290565b61358a611d02565b50613593612ba0565b604051906135a082610524565b6003825260208201525f60408201525f60608201525f608082015290565b5f915f916044815110156135cf5750565b600481015191935091506040908201829003126101c357604460248201519101516103af81610199565b1561360057565b7fe293d025000000000000000000000000000000000000000000000000000000005f5260045ffd5b919060a08301519061364060e08501918251906119ac565b820180921161199a576101008294015180155f14613690575051810180911161199a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810190811161199a5790565b9050810180911161199a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810190811161199a579056fea26469706673582212201a3897a88979584f8f78d94a5eb76fd41b42455834de2610443c60a2382cee6e64736f6c634300081e0033c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563000000000000000000000000f9ba6f64c9b41df1cee76a50e2039d38470642320000000000000000000000006e17cac0db135a5c6a9fa45758e2a314b399bf00", + "nonce": "0x3", + "chainId": "0x1" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x48bdb5588e83f05e1d6be57731d5b39bb324e684eedb0ab9d0819925ff712cfe", + "transactionType": "CALL", + "contractName": "OwnedTWAP", + "contractAddress": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91", + "function": "setDescriptor((string[],bytes32,uint8))", + "arguments": [ + "([https://raw.githubusercontent.com/nullislabs/composable-cow/d1f3603208c32ccff7ab5f51bedf9eec9a46f81b/descriptors/TWAP.json], 0xb499b04e292a7fe808b982113e7e931446261bbc5d702517ba89a8403536ce1a, 1)" + ], + "transaction": { + "from": "0x6e17cac0db135a5c6a9fa45758e2a314b399bf00", + "to": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91", + "gas": "0x4b015", + "value": "0x0", + "input": "0x7dd03ac900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060b499b04e292a7fe808b982113e7e931446261bbc5d702517ba89a8403536ce1a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000007a68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f6e756c6c69736c6162732f636f6d706f7361626c652d636f772f643166333630333230386333326363666637616235663531626564663965656339613436663831622f64657363726970746f72732f545741502e6a736f6e000000000000", + "nonce": "0x4", + "chainId": "0x1" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0xa89fd0", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x8bd480bff240fc7f34e8a7852f244940ebdefb93ee8808265b50b4655d522760", + "transactionIndex": "0x4b", + "blockHash": "0x8a7b95c6440e6c66f3600c6eb027b6afb15b672a8d2e594f2d64462a7321a59e", + "blockNumber": "0x187c2c8", + "gasUsed": "0x21d062", + "effectiveGasPrice": "0x9139502", + "from": "0x6e17cac0db135a5c6a9fa45758e2a314b399bf00", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "contractAddress": "0xf9ba6f64c9b41df1cee76a50e2039d3847064232" + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0xd8b732", + "logs": [ + { + "address": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000006e17cac0db135a5c6a9fa45758e2a314b399bf00" + ], + "data": "0x", + "blockHash": "0x8a7b95c6440e6c66f3600c6eb027b6afb15b672a8d2e594f2d64462a7321a59e", + "blockNumber": "0x187c2c8", + "blockTimestamp": "0x6a708cc7", + "transactionHash": "0x48bdb5588e83f05e1d6be57731d5b39bb324e684eedb0ab9d0819925ff712cfe", + "transactionIndex": "0x4c", + "logIndex": "0xeb", + "removed": false + } + ], + "logsBloom": "0x00000000000000000000000000080000000000000000000000800000000000000000000080000000000000000000000000000000000000000400000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000008000020000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x48bdb5588e83f05e1d6be57731d5b39bb324e684eedb0ab9d0819925ff712cfe", + "transactionIndex": "0x4c", + "blockHash": "0x8a7b95c6440e6c66f3600c6eb027b6afb15b672a8d2e594f2d64462a7321a59e", + "blockNumber": "0x187c2c8", + "gasUsed": "0x301762", + "effectiveGasPrice": "0x9139502", + "from": "0x6e17cac0db135a5c6a9fa45758e2a314b399bf00", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "contractAddress": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91" + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0xdbebc4", + "logs": [ + { + "address": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91", + "topics": [ + "0xfe5ca6316fce32d692eb4adafe8d133e02a1936b75e56709cf1b413673a22819" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000060b499b04e292a7fe808b982113e7e931446261bbc5d702517ba89a8403536ce1a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000007a68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f6e756c6c69736c6162732f636f6d706f7361626c652d636f772f643166333630333230386333326363666637616235663531626564663965656339613436663831622f64657363726970746f72732f545741502e6a736f6e000000000000", + "blockHash": "0x8a7b95c6440e6c66f3600c6eb027b6afb15b672a8d2e594f2d64462a7321a59e", + "blockNumber": "0x187c2c8", + "blockTimestamp": "0x6a708cc7", + "transactionHash": "0x873ec994d57f818ef4375e861ffd2c3e5666978927bcf6e9742e147836a88ac5", + "transactionIndex": "0x4d", + "logIndex": "0xec", + "removed": false + } + ], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000800000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000002000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x873ec994d57f818ef4375e861ffd2c3e5666978927bcf6e9742e147836a88ac5", + "transactionIndex": "0x4d", + "blockHash": "0x8a7b95c6440e6c66f3600c6eb027b6afb15b672a8d2e594f2d64462a7321a59e", + "blockNumber": "0x187c2c8", + "gasUsed": "0x33492", + "effectiveGasPrice": "0x9139502", + "from": "0x6e17cac0db135a5c6a9fa45758e2a314b399bf00", + "to": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91", + "contractAddress": null + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1785761019907, + "chain": 1, + "commit": "d1f3603" +} \ No newline at end of file diff --git a/broadcast/deploy_OwnedStack.s.sol/1/run-latest.json b/broadcast/deploy_OwnedStack.s.sol/1/run-latest.json new file mode 100644 index 00000000..4a9baf62 --- /dev/null +++ b/broadcast/deploy_OwnedStack.s.sol/1/run-latest.json @@ -0,0 +1,156 @@ +{ + "transactions": [ + { + "hash": "0x873ec994d57f818ef4375e861ffd2c3e5666978927bcf6e9742e147836a88ac5", + "transactionType": "CREATE2", + "contractName": "ComposableCow", + "contractAddress": "0xf9ba6f64c9b41df1cee76a50e2039d3847064232", + "function": null, + "arguments": [ + "0x9008D19f58AAbD9eD0D60971565AA8510560ab41" + ], + "transaction": { + "from": "0x6e17cac0db135a5c6a9fa45758e2a314b399bf00", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "gas": "0x3173f5", + "value": "0x0", + "input": "0x000000000000000000000000000000000000000000000000000000000000000060c080604052346100ca5760208161282c803803809161001f82856100e1565b8339810103126100ca57516001600160a01b038116908190036100ca576020816004926080526040519283809263f698da2560e01b82525afa9081156100d6575f916100a0575b5060a0526040516127139081610119823960805181818161072d0152612691015260a051818181610ece01528181612304015261252a0152f35b90506020813d6020116100ce575b816100bb602093836100e1565b810103126100ca57515f610066565b5f80fd5b3d91506100ae565b6040513d5f823e3d90fd5b601f909101601f19168101906001600160401b0382119082101761010457604052565b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c80630960c249146101145780630d0d98001461010f5780631c7662c81461010a57806326e0a19614610105578063511606301461010057806353f00b14146100fb5780635500079d146100f6578063595001b2146100f15780636108c532146100ec5780636bfae1ca146100e7578063738f7bf1146100e25780637ca3baa1146100dd5780638f7984ed146100d857806395bc2673146100d3578063a4546876146100ce5763f698da25146100c9575f80fd5b610eb7565b610e6f565b610de0565b610d30565b610cda565b610b6b565b610b0b565b610aaf565b610a34565b6109f1565b610751565b610701565b6106ae565b610398565b6101ec565b61012b565b908160409103126101275790565b5f80fd5b346101275760406003193601126101275760243560043567ffffffffffffffff821161012757610162610179923690600401610119565b604051916101716020846108aa565b5f83526117c7565b005b908160609103126101275790565b73ffffffffffffffffffffffffffffffffffffffff81160361012757565b9181601f840112156101275782359167ffffffffffffffff8311610127576020838186019501011161012757565b8015150361012757565b35906101ea826101d5565b565b346101275760806003193601126101275760043567ffffffffffffffff81116101275761021d90369060040161017b565b6024359061022a82610189565b6044359167ffffffffffffffff83116101275760206102506102ba9436906004016101a7565b91906064359361025f856101d5565b610268866118da565b9373ffffffffffffffffffffffffffffffffffffffff6040518099819582947fb6576bdf0000000000000000000000000000000000000000000000000000000084528860048501526024840191611619565b0392165afa9283156103885761035461032894610179965f91610359575b5080610313856103063373ffffffffffffffffffffffffffffffffffffffff165f52600360205260405f2090565b905f5260205260405f2090565b55604051958691602083019190602083019252565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018652856108aa565b611945565b61037b915060203d602011610381575b61037381836108aa565b810190611936565b5f6102d8565b503d610369565b611333565b35906101ea82610189565b34610127576040600319360112610127576004356103b581610189565b73ffffffffffffffffffffffffffffffffffffffff60243591165f52600360205260405f20905f52602052602060405f2054604051908152f35b9060806003198301126101275760043561040881610189565b9160243567ffffffffffffffff811161012757816104289160040161017b565b9160443567ffffffffffffffff81116101275782610448916004016101a7565b9290929160643567ffffffffffffffff811161012757826023820112156101275780600401359267ffffffffffffffff84116101275760248460051b83010111610127576024019190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b600611156104ca57565b610493565b61016080916104f484825173ffffffffffffffffffffffffffffffffffffffff169052565b60208181015173ffffffffffffffffffffffffffffffffffffffff169085015260408181015173ffffffffffffffffffffffffffffffffffffffff1690850152606081015160608501526080810151608085015261055f60a082015160a086019063ffffffff169052565b60c081015160c085015260e081015160e085015261010081015161010085015261059461012082015161012086019015159052565b6101408101516101408501520151910152565b600411156104ca57565b9060048210156104ca5752565b600211156104ca57565b9060028210156104ca5752565b908151805160068110156104ca576101ea937fffffffff000000000000000000000000000000000000000000000000000000006080610240946060948752610625602082015160208901906104cf565b60408101516101a0880152848101516101c08801520151166101e085015261065660208201516102008601906105b1565b604081015161022085015201519101906105c8565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b34610127576106df6106f36106d16106c5366103ef565b94939093929192611004565b6040519384939284906105d5565b61028061026084015261028083019061066b565b0390f35b5f91031261012757565b34610127575f60031936011261012757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101275760e06003193601126101275760043561076e81610189565b6024359061077b82610189565b604435916064359160a43567ffffffffffffffff8111610127576107a39036906004016101a7565b9060c4359467ffffffffffffffff8611610127576106f3966107cc6107d49736906004016101a7565b96909561133e565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681529081906020820190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761085057604052565b610807565b6080810190811067ffffffffffffffff82111761085057604052565b60a0810190811067ffffffffffffffff82111761085057604052565b610180810190811067ffffffffffffffff82111761085057604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761085057604052565b604051906101ea610180836108aa565b604051906101ea6060836108aa565b67ffffffffffffffff811161085057601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b9291926109508261090a565b9161095e60405193846108aa565b829481845281830111610127578281602093845f960137010152565b9080601f830112156101275781602061099593359101610944565b90565b919060608382031261012757604051906109b182610834565b819380356109be81610189565b83526020810135602084015260408101359167ffffffffffffffff8311610127576040926109ec920161097a565b910152565b346101275760206003193601126101275760043567ffffffffffffffff811161012757610a2c610a276020923690600401610998565b6114b7565b604051908152f35b346101275760206003193601126101275773ffffffffffffffffffffffffffffffffffffffff600435610a6681610189565b165f52600260205273ffffffffffffffffffffffffffffffffffffffff60405f205416604051809173ffffffffffffffffffffffffffffffffffffffff60208301911682520390f35b3461012757604060031936011261012757600435610acc81610189565b73ffffffffffffffffffffffffffffffffffffffff60243591165f52600160205260405f20905f52602052602060ff60405f2054166040519015158152f35b346101275760406003193601126101275760043567ffffffffffffffff811161012757610b3f61017991369060040161017b565b602435610b4b816101d5565b610b54826118da565b60405192610b636020856108aa565b5f8452611945565b346101275760806003193601126101275760043560243567ffffffffffffffff811161012757610b9f903690600401610119565b9060443591610bad83610189565b60643567ffffffffffffffff811161012757610c2993610bd360209236906004016101a7565b5f9291925073ffffffffffffffffffffffffffffffffffffffff6040518098819582947fb6576bdf0000000000000000000000000000000000000000000000000000000084528860048501526024840191611619565b0392165afa91821561038857610cb6610c8a93610179955f91610cbb575b5080610c755f6103063373ffffffffffffffffffffffffffffffffffffffff165f52600360205260405f2090565b55604051948591602083019190602083019252565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018552846108aa565b6117c7565b610cd4915060203d6020116103815761037381836108aa565b5f610c47565b3461012757610260610d21610d1b610d14610cf4366103ef565b9196929590610d01610f05565b50610d0c3686610998565b923691610fa1565b9084611a4c565b91611d82565b610d2e60405180926105d5565bf35b3461012757602060031936011261012757600435610d4d81610189565b335f52600260205260405f2073ffffffffffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790557f41f583e2d25b3921afe66987b63b0b5e4cf2acbbbed4a477fd19a22180f3f85960405173ffffffffffffffffffffffffffffffffffffffff60208201931681528033930390a2005b3461012757602060031936011261012757600435335f52600160205260405f20815f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008154169055335f52600360205260405f20815f526020525f6040812055337f67e0f2b23e842ce65d7edff49765689c9c0931f911fc5971d09bb598cc1af4a95f80a3005b346101275760206003193601126101275773ffffffffffffffffffffffffffffffffffffffff600435610ea181610189565b165f525f602052602060405f2054604051908152f35b34610127575f6003193601126101275760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b60405190610f006020836108aa565b5f8252565b60405190610f1282610855565b5f606083604051610f2281610871565b838152604051610f318161088d565b84815284602082015284604082015284848201528460808201528460a08201528460c08201528460e0820152846101008201528461012082015284610140820152846101608201526020820152836040820152838382015283608082015281528260208201528260408201520152565b9291909267ffffffffffffffff8411610850578360051b906020604051610fca828501826108aa565b809681520191810192831161012757905b828210610fe757505050565b8135815260209182019101610fdb565b5160068110156104ca5790565b9295949195939093611014610f05565b506110408188611039611027368a610998565b611032368989610fa1565b9089611a4c565b8888611d82565b9661104b8851610ff7565b611054816104c0565b6110cf576020880160028151611069816105a7565b611072816105a7565b149081156110fd575b506110cf5760016020890151611090816105a7565b611099816105a7565b14806110dd575b6110cf5760608801516110b2816105be565b6110bb816105be565b6110cf57610995956020895101519561215d565b505050505050610995610ef1565b506110f86110f461012060208b5101510151151590565b1590565b6110a0565b600391505161110b816105a7565b611114816105a7565b145f61107b565b6020818303126101275780359067ffffffffffffffff82116101275701606081830312610127576040519161114f83610834565b813567ffffffffffffffff811161012757820181601f82011215610127578181602061117d93359101610fa1565b8352602082013567ffffffffffffffff8111610127578161119f918401610998565b6020840152604082013567ffffffffffffffff8111610127576111c2920161097a565b604082015290565b63ffffffff81160361012757565b35906101ea826111ca565b9081610180910312610127576101606111fa6108eb565b916112048161038d565b83526112126020820161038d565b60208401526112236040820161038d565b6040840152606081013560608401526080810135608084015261124860a082016111d8565b60a084015260c081013560c084015260e081013560e084015261010081013561010084015261127a61012082016101df565b610120840152610140810135610140840152013561016082015290565b1561129e57565b7f03fc2a7e000000000000000000000000000000000000000000000000000000005f5260045ffd5b989795909461132b946101ea989473ffffffffffffffffffffffffffffffffffffffff61131d958d8260e09b1690521660208d015260408c015260608b015260808a015261026060a08a015261026089019061066b565b9087820360c089015261066b565b9401906104cf565b6040513d5f823e3d90fd5b956113669073ffffffffffffffffffffffffffffffffffffffff92949896939681019061111b565b951690611388602087019461137f865189519086611a4c565b928101906111e3565b936113a66113a186604084519a01998a519086886123b1565b611297565b519360406113e46113cb875173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b9501519651853b15610127575f9761142c936040519a8b998a9889987f14a2a784000000000000000000000000000000000000000000000000000000008a5260048a016112c6565b03915afa801561038857611460575b507f1626ba7e0000000000000000000000000000000000000000000000000000000090565b8061146e5f611474936108aa565b806106f7565b5f61143b565b90606060406109959373ffffffffffffffffffffffffffffffffffffffff815116845260208101516020850152015191816040820152019061066b565b604051611500816114d4602082019460208652604083019061147a565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826108aa565b51902090565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610127570180359067ffffffffffffffff821161012757602001918160051b3603831361012757565b919081101561156a5760051b0190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b1561159e57565b7f6fe76104000000000000000000000000000000000000000000000000000000005f5260045ffd5b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561012757016020813591019167ffffffffffffffff8211610127578160051b3603831361012757565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561012757016020813591019167ffffffffffffffff821161012757813603831361012757565b9081526060602082015260a0810192916116c181806115c6565b809195604060608601525260c083019060c08160051b8501019580925f915b8383106117735750505050508060206116fa9201906115c6565b91907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08286030160808301528285527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311610127576109959460209360051b809285830137019060408382840301910152019061066b565b90919293976020806117b8837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff408b600196030187526117b28d87611657565b90611619565b9a0193019301919392906116e0565b9192821561187b575b5f5b602083016117e08185611506565b9050821015611817579061181161180c6118068361180060019689611506565b9061155a565b35612487565b611597565b016117d2565b5050927faa8df5268339649ef2752ea240168c52869c3ab59c8c64078df854916f1b86d591836118643373ffffffffffffffffffffffffffffffffffffffff165f525f60205260405f2090565b556118766040519283923396846116a7565b0390a2565b6118858280611506565b905015806118ba575b6117d0577f14f5a94c000000000000000000000000000000000000000000000000000000005f5260045ffd5b506118c86020830183611506565b90501561188e565b3561099581610189565b73ffffffffffffffffffffffffffffffffffffffff81356118fa81610189565b161561190e57610a27610995913690610998565b7fd8f59fa5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90816020910312610127575190565b9190335f52600160205260405f20905f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905561198e575050565b6119fd7f681609694274e6398a06f0051ec46e3ef05ed684d33a23297b5ebda248fcd9a191611876611a0e6040519384936040855273ffffffffffffffffffffffffffffffffffffffff81356119e381610189565b166040860152602081013560608601526040810190611657565b6060608086015260a0850191611619565b8281036020840152339561066b565b15611a2457565b7f4a821464000000000000000000000000000000000000000000000000000000005f5260045ffd5b82515f9493929015611ae157611a61906114b7565b5f52611a8e60205f209173ffffffffffffffffffffffffffffffffffffffff165f525f60205260405f2090565b549082519283611aa5575b506101ea925014611a1d565b8060208092019460051b0101905b8351811160051b90815260208451911852602060405f20930192818410611ab35790506101ea92505f611a99565b611b0391945073ffffffffffffffffffffffffffffffffffffffff92506114b7565b92165f52600160205260405f20825f5260205260ff60405f20541615611b2557565b7f7a933234000000000000000000000000000000000000000000000000000000005f5260045ffd5b51906101ea826101d5565b908160209103126101275751610995816101d5565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610127570180359067ffffffffffffffff82116101275760200191813603831361012757565b51906101ea82610189565b51906101ea826111ca565b51907fffffffff000000000000000000000000000000000000000000000000000000008216820361012757565b8091039061020082126101275760405191611c1b83610871565b8151600681101561012757610180917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09185520112610127576101e0611d2591611c636108eb565b611c6f60208301611bbe565b8152611c7d60408301611bbe565b6020820152611c8e60608301611bbe565b60408201526080820151606082015260a08201516080820152611cb360c08301611bc9565b60a082015260e082015160c082015261010082015160e0820152610120820151610100820152611ce66101408301611b4d565b61012082015261016082015161014082015261018082015161016082015260208501526101a081015160408501526101c0810151606085015201611bd4565b608082015290565b94929093611d689273ffffffffffffffffffffffffffffffffffffffff61099598961687526020870152608060408701526080860191611619565b926060818503910152611619565b60048210156104ca5752565b919294939094611d90610f05565b95611da36113cb6113cb6113cb846118d0565b602060405180927f01ffc9a70000000000000000000000000000000000000000000000000000000082528180611e0060048201907ff97f095600000000000000000000000000000000000000000000000000000000602083019252565b03915afa5f9181612030575b50611e39577f2c7ca6d7000000000000000000000000000000000000000000000000000000005f5260045ffd5b1561200857611e506113cb6113cb6113cb846118d0565b610200611e606040840184611b6d565b928888611e9e8989604051988997889687967f36eed5f600000000000000000000000000000000000000000000000000000000885260048801611d2d565b03915afa908115610388575f91611fd9575b5080885251611ebe816104c0565b611ec7816104c0565b15611ed4575b5050505050565b611f1494611f0393611efc6110f494611ef460208c510151953690610998565b923691610944565b91866123b1565b611fcd575b60208451015190612513565b80604084015280155f14611f3457505f60208301525b5f80808080611ecd565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8103611f6d575060036020830152611f2a565b611f2a565b8251602001516101008101517ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677503611fc35760600151905b10611fb957611f6860025b60208401611d76565b611f686001611fb0565b6080015190611fa5565b60016060850152611f08565b611ffb91506102003d8111612001575b611ff381836108aa565b810190611c01565b5f611eb0565b503d611fe9565b7f2c7ca6d7000000000000000000000000000000000000000000000000000000005f5260045ffd5b61205391925060203d60201161205a575b61204b81836108aa565b810190611b58565b905f611e0c565b503d612041565b610180810192916101ea91906104cf565b80516060808452815190840181905260808401949391602001905f5b8181106120c55750505060406120b461099594956020850151848203602086015261147a565b92015190604081840391015261066b565b825187526020968701969092019160010161208e565b906020610995928181520190612072565b9161212f90610995949284527fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e489602085015260806040850152608084019061066b565b91606081840391015261066b565b8061214f6101a09261099595946104cf565b816101808201520190612072565b95949593909193602060405180927f01ffc9a70000000000000000000000000000000000000000000000000000000082528173ffffffffffffffffffffffffffffffffffffffff816121d660048201907f62af8dc200000000000000000000000000000000000000000000000000000000602083019252565b0392165afa5f9181612354575b5061223657509161221361099595949261220a61221f956122026108fb565b993691610fa1565b88523690610998565b60208701523691610944565b60408401526114d46040519384926020840161213d565b959192949093951561232c57610c8a95610995956122b36122d3956122aa61226e9861229a6122bf976040519b8c9160208301612061565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018c528b6108aa565b6122a26108fb565b973691610fa1565b86523690610998565b60208501523691610944565b6040820152604051948591602083016120db565b6114d46040519384927f5fd7e97d0000000000000000000000000000000000000000000000000000000060208501527f0000000000000000000000000000000000000000000000000000000000000000602485016120ec565b7f79ac63cd000000000000000000000000000000000000000000000000000000005f5260045ffd5b61236e91925060203d60201161205a5761204b81836108aa565b905f6121e3565b926109959492612388856123a2946104cf565b6101808501526101e06101a08501526101e084019061147a565b916101c081840391015261066b565b73ffffffffffffffffffffffffffffffffffffffff90949394165f5260026020526123f76113cb60405f2073ffffffffffffffffffffffffffffffffffffffff90541690565b9073ffffffffffffffffffffffffffffffffffffffff821661241d575050505050600190565b602093612459604051968795869485947ff9ae35a200000000000000000000000000000000000000000000000000000000865260048601612375565b03915afa908115610388575f9161246e575090565b610995915060203d60201161205a5761204b81836108aa565b905f5b804980156124fb5783146124f4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146124c75760010161248a565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5060019150565b505f925050565b90602061099592818152019061066b565b602090612645612678936114d46125dd60a06125d17f000000000000000000000000000000000000000000000000000000000000000085907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06042920180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a082209152604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b93015163ffffffff1690565b60405186810193845260609590951b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016602084015260e01b7fffffffff00000000000000000000000000000000000000000000000000000000166034830152839160380190565b604051809381927f2479fb6e00000000000000000000000000000000000000000000000000000000835260048301612502565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa908115610388575f916126c4575090565b610995915060203d6020116103815761037381836108aa56fea2646970667358221220284f9be73c484c05e3dfe348146e007f2bc9026893ca60a56bb8d5a42d05f64864736f6c634300081e00330000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41", + "nonce": "0x2", + "chainId": "0x1" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x8bd480bff240fc7f34e8a7852f244940ebdefb93ee8808265b50b4655d522760", + "transactionType": "CREATE2", + "contractName": "OwnedTWAP", + "contractAddress": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91", + "function": null, + "arguments": [ + "0xf9ba6F64c9b41Df1cEe76A50e2039D3847064232", + "0x6e17cAc0db135A5C6A9FA45758e2A314b399BF00" + ], + "transaction": { + "from": "0x6e17cac0db135a5c6a9fa45758e2a314b399bf00", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "gas": "0x465565", + "value": "0x0", + "input": "0x000000000000000000000000000000000000000000000000000000000000000060a06040523461062857613ec66040813803918261001c8161064b565b938492833981010312610628578051906001600160a01b038216820361062857602001516001600160a01b03811691908290036106285761005b6106fb565b906100646106fb565b805151906020810180519260408301938451906002821015610228576105fa57506103ee575b8151805190680100000000000000008211610358575f54825f55808310610579575b505f8080525f516020613ea65f395f51905f5292916020015b82821061047457505050508051600155825160028110156102285760ff80196002541691161760025551908161042b575b505050608052805151906020810180519260408301938451906002821015610228576103fd57506103ee575b8151805190680100000000000000008211610358576003548260035580831061036c575b5060035f9081525f516020613e865f395f51905f5292916020015b82821061023c57505050508051600455825160028110156102285760ff8019600554169116176005555190816101df575b8380638b78c6d819555f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a36040516136fe908161078882396080518181816110df01526128450152f35b5191519160028310156102285761021d7fe1d44331b30c93e74db74c814c88415da5d48e865502fd54dc27efb376995f739360405193849384610670565b0390a15f8080610192565b634e487b7160e01b5f52602160045260245ffd5b80518051906001600160401b038211610358576102598654610739565b601f811161031d575b50602090601f83116001146102b4579261029a836001959460209487965f926102a9575b50508160011b915f199060031b1c19161790565b87555b01940191019092610161565b015190505f80610286565b90601f19831691875f52815f20925f5b81811061030557509360209360019693879693838895106102ed575b505050811b01875561029d565b01515f1960f88460031b161c191690555f80806102e0565b929360206001819287860151815501950193016102c4565b61034890875f5260205f20601f850160051c8101916020861061034e575b601f0160051c0190610771565b5f610262565b909150819061033b565b634e487b7160e01b5f52604160045260245ffd5b60035f525f516020613e865f395f51905f529081019083015b8181106103925750610146565b8061039f60019254610739565b806103ac575b5001610385565b601f811183146103c157505f81555b5f6103a5565b6103dd90825f5283601f60205f20920160051c82019101610771565b805f525f60208120818355556103bb565b63e293d02560e01b5f5260045ffd5b600103610417576101225763b522a9f360e01b5f5260045ffd5b1561012257637c549cbb60e11b5f5260045ffd5b519151916002831015610228576104697ffe5ca6316fce32d692eb4adafe8d133e02a1936b75e56709cf1b413673a228199360405193849384610670565b0390a15f80806100f6565b80518051906001600160401b038211610358576104918654610739565b601f8111610549575b50602090601f83116001146104e057926104d1836001959460209487965f926102a95750508160011b915f199060031b1c19161790565b87555b019401910190926100c5565b90601f19831691875f52815f20925f5b8181106105315750936020936001969387969383889510610519575b505050811b0187556104d4565b01515f1960f88460031b161c191690555f808061050c565b929360206001819287860151815501950193016104f0565b61057390875f5260205f20601f850160051c8101916020861061034e57601f0160051c0190610771565b5f61049a565b5f80525f516020613ea65f395f51905f529081019083015b81811061059e57506100ac565b806105ab60019254610739565b806105b8575b5001610591565b601f811183146105cd57505f81555b5f6105b1565b6105e990825f5283601f60205f20920160051c82019101610771565b805f525f60208120818355556105c7565b6001036106145761008a5763b522a9f360e01b5f5260045ffd5b1561008a57637c549cbb60e11b5f5260045ffd5b5f80fd5b60405190606082016001600160401b0381118382101761035857604052565b6040519190601f01601f191682016001600160401b0381118382101761035857604052565b9093929193606082016060835281518091526080830190602060808260051b8601019301915f905b8282106106b8575050505093602082015260028210156102285760400152565b9091929360208080600193607f198a82030186528189518051918291828552018484015e5f828201840152601f01601f1916010196019493919091019101610698565b5f604061070661062c565b60608152826020820152015261071c602061064b565b5f815261072761062c565b9081525f60208201525f604082015290565b90600182811c92168015610767575b602083101461075357565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610748565b81811061077c575050565b5f815560010161077156fe60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a71461019457806314a2a7841461018f578063256929621461018a5780632cfe09fb146101855780632e242d37146101805780633618005b1461017b57806336eed5f6146101765780633859f494146101715780634665dc751461016c57806354d1f13d1461016757806359e367e514610162578063715018a61461015d5780637dd03ac91461015857806384d1b38c146101535780638b2e24191461014e5780638da5cb5b1461014957806393504c5214610144578063ae7d5a5b1461013f578063d6ae74421461013a578063e888a3a514610135578063f04e283e14610130578063f2fde38b1461012b578063fb4c2ad1146101265763fee81cf414610121575f80fd5b6114a3565b611438565b6113f9565b6113a8565b611278565b61124f565b6111c5565b6110b3565b611061565b61103c565b610f0f565b610d7f565b610d00565b610bf4565b610a21565b6109d3565b6109aa565b6108f8565b610831565b61076d565b61048b565b610307565b610251565b6101c7565b7fffffffff000000000000000000000000000000000000000000000000000000008116036101c357565b5f80fd5b346101c35760206003193601126101c35760206101ee6004356101e981610199565b6114d9565b6040519015158152f35b73ffffffffffffffffffffffffffffffffffffffff8116036101c357565b3590610221826101f8565b565b9181601f840112156101c35782359167ffffffffffffffff83116101c357602083818601950101116101c357565b346101c3576102606003193601126101c35760043561026f816101f8565b61027a6024356101f8565b60643560443560843560a43567ffffffffffffffff81116101c3576102a3903690600401610223565b9160c43567ffffffffffffffff81116101c3576102c4903690600401610223565b9590946101807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1c3601126101c3576102fb9761181f565b005b5f9103126101c357565b5f6003193601126101c35763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b60806003198201126101c357600435610368816101f8565b916024359160443567ffffffffffffffff81116101c3578161038c91600401610223565b929092916064359067ffffffffffffffff82116101c3576103af91600401610223565b9091565b61016080916103d884825173ffffffffffffffffffffffffffffffffffffffff169052565b60208181015173ffffffffffffffffffffffffffffffffffffffff169085015260408181015173ffffffffffffffffffffffffffffffffffffffff1690850152606081015160608501526080810151608085015261044360a082015160a086019063ffffffff169052565b60c081015160c085015260e081015160e085015261010081015161010085015261047861012082015161012086019015159052565b6101408101516101408501520151910152565b346101c3576101806104aa61049f36610350565b5050929190916119bf565b6104b760405180926103b3565bf35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761050257604052565b6104b9565b610180810190811067ffffffffffffffff82111761050257604052565b60a0810190811067ffffffffffffffff82111761050257604052565b610140810190811067ffffffffffffffff82111761050257604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761050257604052565b604051906102216101808361055d565b604051906102216101408361055d565b6040519061022160a08361055d565b6040519061022160608361055d565b6040519061022160408361055d565b6040519061022160808361055d565b63ffffffff8116036101c357565b3590610221826105fa565b801515036101c357565b359061022182610613565b6101e06003198201126101c357600435610641816101f8565b91602435916044359167ffffffffffffffff83116101c35761018061068a837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c95600401610223565b9490949301126101c35761069c61059e565b6106a66064610216565b81526106b26084610216565b60208201526106c160a4610216565b604082015260c435606082015260e43560808201526106e1610104610608565b60a08201526101243560c08201526101443560e08201526101643561010082015261070d61018461061d565b6101208201526101a4356101408201526101c43561016082015290565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b346101c35761079f61078b61078136610628565b5092919091611c58565b60405191829160208352602083019061072a565b0390f35b90816101409103126101c3576101206107ba6105ae565b916107c481610216565b83526107d260208201610216565b60208401526107e360408201610216565b6040840152606081013560608401526080810135608084015260a081013560a084015260c081013560c084015260e081013560e0840152610100810135610100840152013561012082015290565b346101c3576101406003193601126101c3576102fb61084e6105ae565b6108586004610216565b81526108646024610216565b60208201526108736044610216565b60408201526064356060820152608435608082015260a43560a082015260c43560c082015260e43560e082015261010435610100820152610124356101208201526128aa565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9060068210156108f35752565b6108b9565b346101c35761020061091861090c36610350565b94939093929192611f1e565b7fffffffff0000000000000000000000000000000000000000000000000000000060806040519261094a8482516108e6565b61095c602082015160208601906103b3565b60408101516101a085015260608101516101c08501520151166101e0820152f35b600211156108f357565b9060028210156108f35752565b9081526040810192916102219160200190610987565b346101c3575f6003193601126101c35760015460ff600254169061079f60405192839283610994565b346101c35761079f6109f36109e736610350565b9493909392919261206a565b610a0d6040949294519485941515855260208501906103b3565b6101c06101a08401526101c083019061072a565b5f6003193601126101c35763389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2005b67ffffffffffffffff81116105025760051b60200190565b67ffffffffffffffff811161050257601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b359060028210156101c357565b60206003198201126101c35760043567ffffffffffffffff81116101c357606060031982840301126101c35760405191610afd836104e6565b816004013567ffffffffffffffff81116101c357820190806023830112156101c357600482013591610b2e83610a65565b92610b3c604051948561055d565b808452602060048186019260051b84010101918383116101c35760248101915b838310610b89575050505050610b819160449184526024810135602085015201610ab7565b604082015290565b823567ffffffffffffffff81116101c35760049083010185603f820112156101c357602081013591610bba83610a7d565b610bc7604051918261055d565b83815260408385010188106101c3575f602085819660408397018386013783010152815201920191610b5c565b346101c357610c0236610ac4565b610c0a612c01565b8051516020820191825191604082019283519060028210156108f357610ca05750610c3590156135f9565b610c4181516003612db8565b8251600455610c5b8251610c548161097d565b6005612e94565b51915190519160028310156108f357610c9b7fe1d44331b30c93e74db74c814c88415da5d48e865502fd54dc27efb376995f739360405193849384612117565b0390a1005b600103610cd357610c35577fb522a9f3000000000000000000000000000000000000000000000000000000005f5260045ffd5b15610c35577ff8a93976000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f6003193601126101c357610d13612c01565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392755005b346101c357610d8d36610ac4565b610d95612c01565b8051516020820191825191604082019283519060028210156108f357610e255750610dc090156135f9565b610dcb81515f612db8565b8251600155610de58251610dde8161097d565b6002612e94565b51915190519160028310156108f357610c9b7ffe5ca6316fce32d692eb4adafe8d133e02a1936b75e56709cf1b413673a228199360405193849384612117565b600103610e5857610dc0577fb522a9f3000000000000000000000000000000000000000000000000000000005f5260045ffd5b15610dc0577ff8a93976000000000000000000000000000000000000000000000000000000005f5260045ffd5b9080602083519182815201916020808360051b8301019401925f915b838310610eb057505050505090565b9091929394602080610eec837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08660019603018752895161072a565b97019301930191939290610ea1565b906020610f0c928181520190610e85565b90565b346101c3575f6003193601126101c3575f54610f2a81610a65565b610f37604051918261055d565b8181525f8080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639290602083015b828210610f7b576040518061079f8682610efb565b6040515f8654610f8a8161213f565b8084529060018116908115610ffb5750600114610fc4575b5060019282610fb68594602094038261055d565b815201950191019093610f66565b5f888152602081209092505b818310610fe557505081016020016001610fa2565b6001816020925483868801015201920191610fd0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208581019190915291151560051b8401909101915060019050610fa2565b346101c357602061105961104f36610628565b5092919091612190565b604051908152f35b346101c3575f6003193601126101c35760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346101c3575f6003193601126101c357602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b7fffffffff00000000000000000000000000000000000000000000000000000000604080926111338582516108e6565b60208101516020860152015116910152565b909392919360a0820160a083528151809152602060c084019201905f5b818110611182575050509315156020820152610221919060400190611103565b90919260206101e060019260608751805183526111a585820151868501906103b3565b60408101516101a0840152015115156101c0820152019401929101611162565b346101c35760c06003193601126101c3576004356111e2816101f8565b6024359060443567ffffffffffffffff81116101c357611206903690600401610223565b9190926064359267ffffffffffffffff84116101c35761079f94611231611240953690600401610223565b50506084359260a43594612358565b60409391935193849384611145565b346101c3575f6003193601126101c35760045460ff600554169061079f60405192839283610994565b346101c3575f6003193601126101c35760035461129481610a65565b6112a1604051918261055d565b818152602081019160035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b925f905b8282106112e7576040518061079f8682610efb565b6040515f86546112f68161213f565b80845290600181169081156113675750600114611330575b50600192826113228594602094038261055d565b8152019501910190936112d2565b5f888152602081209092505b8183106113515750508101602001600161130e565b600181602092548386880101520192019161133c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208581019190915291151560051b840190910191506001905061130e565b60206003193601126101c3576004356113c0816101f8565b6113c8612c01565b63389a75e1600c52805f526020600c2090815442116113ec575f6102fb9255612ecb565b636f5e88185f526004601cfd5b60206003193601126101c357600435611411816101f8565b611419612c01565b8060601b1561142b576102fb90612ecb565b637448fbae5f526004601cfd5b346101c35760606003193601126101c357600435611455816101f8565b6024356044359167ffffffffffffffff83116101c35761147c611484933690600401610223565b929091612574565b604051815160038110156108f357604092602091835201516020820152f35b346101c35760206003193601126101c3576004356114c0816101f8565b63389a75e1600c525f52602080600c2054604051908152f35b7f3e26d7e7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000082161461152b57610f0c906126ae565b50600454151590565b1561153b57565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527f8ccc2bc90000000000000000000000000000000000000000000000000000000060045260245ffd5b1561158e57565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527fda09e34a0000000000000000000000000000000000000000000000000000000060045260245ffd5b156115e157565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527fc1ab6dc10000000000000000000000000000000000000000000000000000000060045260245ffd5b1561163457565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527f295964ea0000000000000000000000000000000000000000000000000000000060045260245ffd5b1561168757565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527f6cdfb5fe0000000000000000000000000000000000000000000000000000000060045260245ffd5b156116da57565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527fb290253c0000000000000000000000000000000000000000000000000000000060045260245ffd5b1561172d57565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527f92b120810000000000000000000000000000000000000000000000000000000060045260245ffd5b1561178057565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527fe3c2448f0000000000000000000000000000000000000000000000000000000060045260245ffd5b156117d357565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527fef98fad70000000000000000000000000000000000000000000000000000000060045260245ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0949197506042965092611855939592956119bf565b0180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a082209152604051917f190100000000000000000000000000000000000000000000000000000000000083526002830152602282015220036118bb57565b7f6ac599b4000000000000000000000000000000000000000000000000000000005f527f0af806e00000000000000000000000000000000000000000000000000000000060045260245ffd5b6040519061191482610507565b5f610160838281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152826101408201520152565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b906001820180921161199a57565b61195f565b9190820180921161199a57565b8181029291811591840414171561199a57565b906119d49392916119ce611907565b50612786565b906119dd611907565b506119e7826128aa565b815173ffffffffffffffffffffffffffffffffffffffff1691611a21602082015173ffffffffffffffffffffffffffffffffffffffff1690565b9061010081611bb2611bad611ba4611a50604085015173ffffffffffffffffffffffffffffffffffffffff1690565b98606085015197608086015160a0870199611af4611a88611a838d5160c08c019d8e5160e082019e8f5192015192613235565b613334565b9d611ad76101208b015195611aba611a9e61059e565b73ffffffffffffffffffffffffffffffffffffffff9099168952565b73ffffffffffffffffffffffffffffffffffffffff166020880152565b73ffffffffffffffffffffffffffffffffffffffff166040860152565b60608401526080830152611b1260a083019b8c9063ffffffff169052565b60c08201525f60e08201527ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467756101008201525f6101208201527f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc96101408201527f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9610160820152985163ffffffff1690565b63ffffffff1690565b421190565b611bbc5750505050565b611c559392611bed611c0693611bf3611bd7611bff95612896565b611bed611be589519261198c565b8451906119ac565b9061199f565b955192519051906119ac565b8210611534565b7f2c9e2059000000000000000000000000000000000000000000000000000000005f526004527ff79955c700000000000000000000000000000000000000000000000000000000602452604490565b5ffd5b90611c64939291612786565b611c6d816128aa565b611c7681612896565b906001820180921161199a5760c001511115611cc757604051611c9a60408261055d565b600f81527f7477617020706172742072656164790000000000000000000000000000000000602082015290565b604051611cd560408261055d565b600f81527f66696e616c207477617020706172740000000000000000000000000000000000602082015290565b60405190611d0f82610524565b5f608083828152611d1e611907565b60208201528260408201528260608201520152565b5190610221826101f8565b5190610221826105fa565b519061022182610613565b90816101809103126101c357610160611d6b61059e565b91611d7581611d33565b8352611d8360208201611d33565b6020840152611d9460408201611d33565b60408401526060810151606084015260808101516080840152611db960a08201611d3e565b60a084015260c081015160c084015260e081015160e0840152610100810151610100840152611deb6101208201611d49565b610120840152610140810151610140840152015161016082015290565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b94929093611e819273ffffffffffffffffffffffffffffffffffffffff610f0c98961687526020870152608060408701526080860191611e08565b926060818503910152611e08565b6040513d5f823e3d90fd5b908160209103126101c3575190565b9594926102219460609373ffffffffffffffffffffffffffffffffffffffff611ee79416895260208901526101e060408901526101e0880191611e08565b9401906103b3565b3d15611f19573d90611f0082610a7d565b91611f0e604051938461055d565b82523d5f602084013e565b606090565b909193611f6a9561018091611f31611d02565b5060405197889283927f2cfe09fb000000000000000000000000000000000000000000000000000000008452888a898960048801611e46565b0381305afa5f9581612039575b50611f91575050505050610f0c611f8c611eef565b612a30565b611fcc8560209460405196879586957f8b2e241900000000000000000000000000000000000000000000000000000000875260048701611ea9565b0381305afa908115612034575f91612005575b50611fe86105be565b915f8352602083015260408201525f60608201525f608082015290565b612027915060203d60201161202d575b61201f818361055d565b810190611e9a565b5f611fdf565b503d612015565b611e8f565b61205c9196506101803d8111612063575b612054818361055d565b810190611d54565b945f611f77565b503d61204a565b9194610180946120b2929461207d611907565b5060405197889687967f2cfe09fb00000000000000000000000000000000000000000000000000000000885260048801611e46565b0381305afa5f91816120f6575b506120dc57506120cd611eef565b6120d5612ba0565b915f929190565b90604051906120ec60208361055d565b5f82526001929190565b6121109192506101803d811161206357612054818361055d565b905f6120bf565b60409061213261022194969593606083526060830190610e85565b9560208201520190610987565b90600182811c92168015612186575b602083101461215957565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f169161214e565b9061219c939291612786565b6121a5816128aa565b6121ae81612896565b6001810180911161199a5760c08201518110156121e5576121d99060e060a0840151930151906119ac565b810180911161199a5790565b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90565b60405190612218826104e6565b5f6040838281528260208201520152565b604051906080820182811067ffffffffffffffff821117610502576040525f606083828152612256611907565b60208201528260408201520152565b6040519061227460208361055d565b5f80835282815b82811061228757505050565b602090612292612229565b8282850101520161227b565b906122a882610a65565b6122b5604051918261055d565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06122e38294610a65565b01905f5b8281106122f357505050565b6020906122fe612229565b828285010152016122e7565b9190820391821161199a57565b805182101561232b5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9290916123709295949561236a61220b565b94612786565b9160a08301511561252a57303b156101c357604080517f3618005b000000000000000000000000000000000000000000000000000000008152845173ffffffffffffffffffffffffffffffffffffffff9081166004830152602086015181166024830152918501519091166044820152606084015160648201526080840151608482015260a084015160a482015260c084015160c482015260e084015160e48201526101008401516101048201526101208401516101248201525f8161014481305afa9081612510575b50612463575050505061244b611eef565b61245c612456612265565b91612f4c565b90915f9190565b939091929360c084015190818610801590612508575b6124f257612487868361230a565b90808210156124ea5750905b61249d828761199f565b10936124a88261229e565b955f5b8381106124b85750505050565b806124ce6124c86001938561199f565b85612fe3565b6124d8828b612317565b526124e3818a612317565b50016124ab565b905090612493565b505092505050612500612265565b61245c612fbc565b508015612479565b8061251e5f6125249361055d565b806102fd565b5f61243a565b50505050612536612265565b61253e6105cd565b600381525f602082018190527f453ffb600000000000000000000000000000000000000000000000000000000060408301529192565b92919060405193604085019480861067ffffffffffffffff871117610502576125a9956040525f81525f602082015250612786565b303b156101c357604080517f3618005b000000000000000000000000000000000000000000000000000000008152825173ffffffffffffffffffffffffffffffffffffffff9081166004830152602084015181166024830152918301519091166044820152606082015160648201526080820151608482015260a082015160a482015260c082015160c482015260e082015160e48201526101008201516101048201526101208201516101248201525f8161014481305afa908161269a575b5061268257506126766105dc565b5f81525f602082015290565b60c0015161268e6105dc565b905f8252602082015290565b8061251e5f6126a89361055d565b5f612668565b7fffffffff00000000000000000000000000000000000000000000000000000000167fbc88471800000000000000000000000000000000000000000000000000000000811461277d577ff97f0956000000000000000000000000000000000000000000000000000000008114908115612753575b811561272c575090565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501490565b7f5531708a0000000000000000000000000000000000000000000000000000000081149150612722565b50600154151590565b9392916127dc91925f61012060405161279e81610540565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015201528101906107a3565b9260a08401908151156127ee57505050565b6040517f1c7662c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526024810193909352602090839060449082907f0000000000000000000000000000000000000000000000000000000000000000165afa918215612034575f92612878575052565b61289291925060203d60201161202d5761201f818361055d565b9052565b610f0c9060e060a082015191015190613357565b610221906129756128cf825173ffffffffffffffffffffffffffffffffffffffff1690565b61292f602084019173ffffffffffffffffffffffffffffffffffffffff61292661290d855173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b91161415611587565b73ffffffffffffffffffffffffffffffffffffffff61296561290d855173ffffffffffffffffffffffffffffffffffffffff1690565b1615159081612a05575b506115da565b6129846060820151151561162d565b61299360808201511515611680565b6129a663ffffffff60a0830151106116d3565b6129bf60c08201516001811190816129f6575b50611726565b61010060e08201916129dc835180151590816129e7575b50611779565b0151905110156117cc565b6301e13380915011155f6129d6565b63ffffffff915011155f6129b9565b51612a28915061290d9073ffffffffffffffffffffffffffffffffffffffff1681565b15155f61296f565b612a38611d02565b50600481511015612a4c5750610f0c613582565b60208101517fffffffff0000000000000000000000000000000000000000000000000000000081167f6ac599b4000000000000000000000000000000000000000000000000000000008114612b8d577f6707bf6a000000000000000000000000000000000000000000000000000000008114612b7a577f2c9e2059000000000000000000000000000000000000000000000000000000008114612b66577f12053d38000000000000000000000000000000000000000000000000000000008114612b52577f01b495a30000000000000000000000000000000000000000000000000000000014612b4057610f0c9150613408565b50612b4d610f0c91613377565b613524565b5050612b60610f0c916135be565b906134c5565b5050612b74610f0c916135be565b90613466565b5050612b88610f0c91613377565b613408565b5050612b9b610f0c91613377565b6133aa565b612ba8611907565b50604051612bb581610507565b5f81525f60208201525f60408201525f60608201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f6101208201525f6101408201525f61016082015290565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543303612c2b57565b6382b429005f526004601cfd5b818110612c43575050565b5f8155600101612c38565b9190601f8111612c5d57505050565b610221925f5260205f20906020601f840160051c83019310612c87575b601f0160051c0190612c38565b9091508190612c7a565b919091825167ffffffffffffffff811161050257612cb981612cb3845461213f565b84612c4e565b6020601f8211600114612d16578190612d079394955f92612d0b575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b9055565b015190505f80612cd5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0821690612d47845f5260205f2090565b915f5b818110612da057509583600195969710612d69575b505050811b019055565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f8080612d5f565b9192602060018192868b015181550194019201612d4a565b815191680100000000000000008311610502578154838355808410612e17575b506020612dea9101915f5260205f2090565b5f915b838310612dfa5750505050565b6001602082612e0b83945186612c91565b01920192019190612ded565b825f528360205f2091820191015b818110612e325750612dd8565b80612e3f6001925461213f565b80612e4c575b5001612e25565b601f81118314612e6157505f81555b5f612e45565b612e839083601f612e75855f5260205f2090565b920160051c82019101612c38565b5f8181526020812081835555612e5b565b9060028110156108f35760ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008354169116179055565b73ffffffffffffffffffffffffffffffffffffffff16807fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a37fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392755565b612f5e90612f5861220b565b50612a30565b80519060068210156108f3577fffffffff0000000000000000000000000000000000000000000000000000000060806060830151920151169060405192612fa4846104e6565b60068110156108f35783526020830152604082015290565b612fc461220b565b50604051612fd1816104e6565b5f81525f60208201525f604082015290565b610f0c90612fef612229565b50612ffa8382613628565b91613003611907565b5061300e8582613628565b905061310e613031835173ffffffffffffffffffffffffffffffffffffffff1690565b92613053602082015173ffffffffffffffffffffffffffffffffffffffff1690565b92613075604083015173ffffffffffffffffffffffffffffffffffffffff1690565b6130f76060840151916130da610120613092608088015196613334565b960151976130bd6130a161059e565b73ffffffffffffffffffffffffffffffffffffffff909b168b52565b73ffffffffffffffffffffffffffffffffffffffff1660208a0152565b73ffffffffffffffffffffffffffffffffffffffff166040880152565b6060860152608085015263ffffffff1660a0840152565b60c08201525f60e08201527ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467756101008201525f6101208201527f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc96101408201527f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc96101608201528142101592836131bf575b506131a96105eb565b9485526020850152604084015215156060830152565b42111592505f6131a0565b156131d157565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b8115613208570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b909392916001851180613326575b61324c906131ca565b80151580613318575b61325e906131ca565b61326a818411156131ca565b4282116132c8576132a2817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff95960283014210611534565b6132ae818342036131fe565b83156132bb570201010190565b6001919293500102010190565b507f2c9e2059000000000000000000000000000000000000000000000000000000005f526004527febab10620000000000000000000000000000000000000000000000000000000060245260445ffd5b506301e13380811115613255565b5063ffffffff851115613243565b64010000000081101561334a5763ffffffff1690565b6335278d125f526004601cfd5b8042106133715742039042821161199a57610f0c916131fe565b50505f90565b905f916024815110156133875750565b6004810151919250906020908201829003126101c35760240151610f0c81610199565b6133b2611d02565b507fffffffff000000000000000000000000000000000000000000000000000000006133dc612ba0565b91604051926133ea84610524565b6004845260208401525f60408401525f606084015216608082015290565b613410611d02565b507fffffffff0000000000000000000000000000000000000000000000000000000061343a612ba0565b916040519261344884610524565b6003845260208401525f60408401525f606084015216608082015290565b907fffffffff0000000000000000000000000000000000000000000000000000000090613491611d02565b5061349a612ba0565b92604051936134a885610524565b6001855260208501525f6040850152606084015216608082015290565b907fffffffff00000000000000000000000000000000000000000000000000000000906134f0611d02565b506134f9612ba0565b926040519361350785610524565b6002855260208501525f6040850152606084015216608082015290565b61352c611d02565b507fffffffff00000000000000000000000000000000000000000000000000000000613556612ba0565b916040519261356484610524565b6005845260208401525f60408401525f606084015216608082015290565b61358a611d02565b50613593612ba0565b604051906135a082610524565b6003825260208201525f60408201525f60608201525f608082015290565b5f915f916044815110156135cf5750565b600481015191935091506040908201829003126101c357604460248201519101516103af81610199565b1561360057565b7fe293d025000000000000000000000000000000000000000000000000000000005f5260045ffd5b919060a08301519061364060e08501918251906119ac565b820180921161199a576101008294015180155f14613690575051810180911161199a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810190811161199a5790565b9050810180911161199a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810190811161199a579056fea26469706673582212201a3897a88979584f8f78d94a5eb76fd41b42455834de2610443c60a2382cee6e64736f6c634300081e0033c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563000000000000000000000000f9ba6f64c9b41df1cee76a50e2039d38470642320000000000000000000000006e17cac0db135a5c6a9fa45758e2a314b399bf00", + "nonce": "0x3", + "chainId": "0x1" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x48bdb5588e83f05e1d6be57731d5b39bb324e684eedb0ab9d0819925ff712cfe", + "transactionType": "CALL", + "contractName": "OwnedTWAP", + "contractAddress": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91", + "function": "setDescriptor((string[],bytes32,uint8))", + "arguments": [ + "([https://raw.githubusercontent.com/nullislabs/composable-cow/d1f3603208c32ccff7ab5f51bedf9eec9a46f81b/descriptors/TWAP.json], 0xb499b04e292a7fe808b982113e7e931446261bbc5d702517ba89a8403536ce1a, 1)" + ], + "transaction": { + "from": "0x6e17cac0db135a5c6a9fa45758e2a314b399bf00", + "to": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91", + "gas": "0x4b015", + "value": "0x0", + "input": "0x7dd03ac900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060b499b04e292a7fe808b982113e7e931446261bbc5d702517ba89a8403536ce1a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000007a68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f6e756c6c69736c6162732f636f6d706f7361626c652d636f772f643166333630333230386333326363666637616235663531626564663965656339613436663831622f64657363726970746f72732f545741502e6a736f6e000000000000", + "nonce": "0x4", + "chainId": "0x1" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0xa89fd0", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x8bd480bff240fc7f34e8a7852f244940ebdefb93ee8808265b50b4655d522760", + "transactionIndex": "0x4b", + "blockHash": "0x8a7b95c6440e6c66f3600c6eb027b6afb15b672a8d2e594f2d64462a7321a59e", + "blockNumber": "0x187c2c8", + "gasUsed": "0x21d062", + "effectiveGasPrice": "0x9139502", + "from": "0x6e17cac0db135a5c6a9fa45758e2a314b399bf00", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "contractAddress": "0xf9ba6f64c9b41df1cee76a50e2039d3847064232" + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0xd8b732", + "logs": [ + { + "address": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000006e17cac0db135a5c6a9fa45758e2a314b399bf00" + ], + "data": "0x", + "blockHash": "0x8a7b95c6440e6c66f3600c6eb027b6afb15b672a8d2e594f2d64462a7321a59e", + "blockNumber": "0x187c2c8", + "blockTimestamp": "0x6a708cc7", + "transactionHash": "0x48bdb5588e83f05e1d6be57731d5b39bb324e684eedb0ab9d0819925ff712cfe", + "transactionIndex": "0x4c", + "logIndex": "0xeb", + "removed": false + } + ], + "logsBloom": "0x00000000000000000000000000080000000000000000000000800000000000000000000080000000000000000000000000000000000000000400000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000008000020000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x48bdb5588e83f05e1d6be57731d5b39bb324e684eedb0ab9d0819925ff712cfe", + "transactionIndex": "0x4c", + "blockHash": "0x8a7b95c6440e6c66f3600c6eb027b6afb15b672a8d2e594f2d64462a7321a59e", + "blockNumber": "0x187c2c8", + "gasUsed": "0x301762", + "effectiveGasPrice": "0x9139502", + "from": "0x6e17cac0db135a5c6a9fa45758e2a314b399bf00", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "contractAddress": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91" + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0xdbebc4", + "logs": [ + { + "address": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91", + "topics": [ + "0xfe5ca6316fce32d692eb4adafe8d133e02a1936b75e56709cf1b413673a22819" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000060b499b04e292a7fe808b982113e7e931446261bbc5d702517ba89a8403536ce1a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000007a68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f6e756c6c69736c6162732f636f6d706f7361626c652d636f772f643166333630333230386333326363666637616235663531626564663965656339613436663831622f64657363726970746f72732f545741502e6a736f6e000000000000", + "blockHash": "0x8a7b95c6440e6c66f3600c6eb027b6afb15b672a8d2e594f2d64462a7321a59e", + "blockNumber": "0x187c2c8", + "blockTimestamp": "0x6a708cc7", + "transactionHash": "0x873ec994d57f818ef4375e861ffd2c3e5666978927bcf6e9742e147836a88ac5", + "transactionIndex": "0x4d", + "logIndex": "0xec", + "removed": false + } + ], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000800000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000002000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x873ec994d57f818ef4375e861ffd2c3e5666978927bcf6e9742e147836a88ac5", + "transactionIndex": "0x4d", + "blockHash": "0x8a7b95c6440e6c66f3600c6eb027b6afb15b672a8d2e594f2d64462a7321a59e", + "blockNumber": "0x187c2c8", + "gasUsed": "0x33492", + "effectiveGasPrice": "0x9139502", + "from": "0x6e17cac0db135a5c6a9fa45758e2a314b399bf00", + "to": "0x4e17a65d14e7f37d2a9f0389f17efd41aaa64c91", + "contractAddress": null + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1785761019907, + "chain": 1, + "commit": "d1f3603" +} \ No newline at end of file diff --git a/script/deploy_AnvilStack.s.sol b/script/deploy_AnvilStack.s.sol index 9dac18e4..8a55f9c4 100644 --- a/script/deploy_AnvilStack.s.sol +++ b/script/deploy_AnvilStack.s.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; +import {Commitment} from "../src/libraries/Commitment.sol"; import {Script, console} from "forge-std/Script.sol"; // CoW Protocol @@ -62,9 +63,9 @@ contract DeployAnvilStack is Script { // deploy the Composable CoW ComposableCow composableCow = new ComposableCow(address(settlement)); - new TWAP(composableCow, new string[](0), bytes32(0), PackageKind.BZZ_MANIFEST); - new GoodAfterTime(new string[](0), bytes32(0), PackageKind.BZZ_MANIFEST); - new PerpetualStableSwap(new string[](0), bytes32(0), PackageKind.BZZ_MANIFEST); + new TWAP(composableCow, Commitment.none()); + new GoodAfterTime(Commitment.none()); + new PerpetualStableSwap(Commitment.none()); new TradeAboveThreshold(); vm.stopBroadcast(); diff --git a/script/deploy_OrderTypes.s.sol b/script/deploy_OrderTypes.s.sol index 9fbab509..6c52820a 100644 --- a/script/deploy_OrderTypes.s.sol +++ b/script/deploy_OrderTypes.s.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; +import {Commitment} from "../src/libraries/Commitment.sol"; import {Script} from "forge-std/Script.sol"; import {ComposableCow} from "../src/ComposableCow.sol"; @@ -17,9 +18,9 @@ contract DeployOrderTypes is Script { address composableCow = vm.envAddress("COMPOSABLE_COW"); vm.startBroadcast(deployerPrivateKey); - new TWAP(ComposableCow(composableCow), new string[](0), bytes32(0), PackageKind.BZZ_MANIFEST); - new GoodAfterTime(new string[](0), bytes32(0), PackageKind.BZZ_MANIFEST); - new PerpetualStableSwap(new string[](0), bytes32(0), PackageKind.BZZ_MANIFEST); + new TWAP(ComposableCow(composableCow), Commitment.none()); + new GoodAfterTime(Commitment.none()); + new PerpetualStableSwap(Commitment.none()); new TradeAboveThreshold(); vm.stopBroadcast(); diff --git a/script/deploy_OwnedStack.s.sol b/script/deploy_OwnedStack.s.sol new file mode 100644 index 00000000..2f72e4ea --- /dev/null +++ b/script/deploy_OwnedStack.s.sol @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "forge-std/Script.sol"; + +import {ComposableCow} from "../src/ComposableCow.sol"; +import {Commitment} from "../src/libraries/Commitment.sol"; +import {PackageKind} from "../src/interfaces/PackageKind.sol"; +import {OwnedGoodAfterTime, OwnedStopLoss, OwnedTWAP} from "../src/types/Owned.sol"; + +/** + * @title Rotatable-handler deployments + * @dev Deploys the registry and rotatable handlers at the same addresses on + * every chain, via CREATE2 through the canonical factory. + * + * That works here because nothing in the initcode is chain-specific. + * `GPv2Settlement` is at one address on every chain CoW deploys to, so the + * registry's constructor argument does not vary; the registry's address + * therefore does not vary either, which in turn fixes each handler's + * constructor argument. The chain-specific part of the registry, the + * settlement domain separator, is read in the constructor and held as an + * immutable, so it lands in the deployed code without touching the address. + * + * Two preconditions come with that, and neither is enforceable from here: + * `SETTLEMENT` must be the same address used on every other chain, and + * `ADMIN` must be too, or the handlers diverge while the registry does not. + * Run `predict` first and compare against a chain already deployed to. + * + * CREATE2 is available to these handlers precisely because they deploy + * uncommitted. On the immutable handlers the descriptor digest is a + * constructor argument, so the address would depend on a descriptor that + * cannot be built until the address is known. The `Owned*` variants set + * their descriptor afterwards with `setDescriptor`, which breaks the cycle. + * + * `ComposableCow` takes no commitment mixin: it has no descriptor. + * + * Requires `SETTLEMENT` and `ADMIN`, plus a signer: either + * `PRIVATE_KEY` in the environment or `--account`/`--keystore`. + */ +abstract contract DeployOwnedStack is Script { + bytes32 internal constant SALT = bytes32(0); + + /// @dev A stale `ETH_RPC_URL` pointing at the wrong network. + error WrongChain(uint256 expected, uint256 actual); + + /// @dev `SETTLEMENT` has no code here, so it is the wrong address or the + /// wrong chain. Every order would be unsettleable. + error SettlementHasNoCode(address settlement); + + /// @dev A zero owner would strand both commitments permanently: the handler + /// would deploy uncommitted with no key able to call `setDescriptor`. + error OwnerIsZero(); + + /// @dev A deployment did not land where it was predicted to. + error AddressMismatch(address predicted, address actual); + + /// @dev `setDescriptor` is `onlyOwner`, so the deploying key must be the + /// owner to publish in the same run. Otherwise deploy uncommitted and + /// call `setDescriptor` separately from the owner. + error DescriptorNeedsOwnerKey(address deployer, address admin); + + /// @dev The descriptor is committed as `SHA256` over the published bytes, + /// so the URI has to be the thing serving those bytes over https. + error DescriptorUriNotHttps(string uri); + + /// @dev With `VERIFY_URI=1` the advertised URI was fetched and its bytes + /// do not hash to the committed digest: the URI is stale, mistyped, + /// or serving something else. + error UriServesDifferentBytes(string uri); + + /// @dev Split from `_preflight` so the checks are reachable without the + /// environment: `vm.setEnv` writes the host process environment, which + /// foundry's per-test isolation does not roll back, so a test that went + /// through the env would race every other test in the run. + function _validate(uint256 expectedChain, address settlement, address admin) internal view { + require(block.chainid == expectedChain, WrongChain(expectedChain, block.chainid)); + require(settlement.code.length != 0, SettlementHasNoCode(settlement)); + require(admin != address(0), OwnerIsZero()); + } + + function _preflight(uint256 expectedChain) internal view returns (address settlement, address admin) { + settlement = vm.envAddress("SETTLEMENT"); + admin = vm.envAddress("ADMIN"); + _validate(expectedChain, settlement, admin); + } + + /// @dev The TWAP descriptor document in this repository. The digest is + /// computed from it rather than supplied, so what is committed on + /// chain cannot drift from the document that was generated. + string internal constant TWAP_DESCRIPTOR = "descriptors/TWAP.json"; + + /// @dev `TWAP_DESCRIPTOR_URI` is optional. Unset, the handler deploys + /// uncommitted exactly as before and the descriptor is published + /// later with `setDescriptor`. + function _twapDescriptor(address deployer, address admin) internal view returns (bool, Commitment.Data memory) { + return _descriptorFor(vm.envOr("TWAP_DESCRIPTOR_URI", string("")), deployer, admin); + } + + /// @dev Split from the environment read for the same reason `_validate` is: + /// `vm.setEnv` writes the host process environment, which foundry does + /// not roll back between tests. + function _descriptorFor(string memory uri, address deployer, address admin) + internal + view + returns (bool set, Commitment.Data memory descriptor) + { + if (bytes(uri).length == 0) return (false, descriptor); + + require(deployer == admin, DescriptorNeedsOwnerKey(deployer, admin)); + require(_isHttps(uri), DescriptorUriNotHttps(uri)); + + string[] memory uris = new string[](1); + uris[0] = uri; + + set = true; + descriptor = Commitment.Data({ + uris: uris, digest: sha256(bytes(vm.readFile(TWAP_DESCRIPTOR))), kind: PackageKind.SHA256 + }); + } + + function _isHttps(string memory uri) internal pure returns (bool) { + bytes memory b = bytes(uri); + bytes memory prefix = "https://"; + if (b.length <= prefix.length) return false; + for (uint256 i; i < prefix.length; ++i) { + if (b[i] != prefix[i]) return false; + } + return true; + } + + /// @dev The digest is computed from the local document; whether the + /// advertised URI actually serves those bytes is a property of a web + /// server, so it can only be checked by fetching. `VERIFY_URI=1` does + /// that through `vm.ffi` (add `--ffi` to the invocation); otherwise + /// the URI is advertised unverified and says so loudly. + function _verifyOrWarn(Commitment.Data memory descriptor) internal { + string memory uri = descriptor.uris[0]; + if (vm.envOr("VERIFY_URI", false)) { + string[] memory cmd = new string[](3); + cmd[0] = "curl"; + cmd[1] = "-fsSL"; + cmd[2] = uri; + require(sha256(vm.ffi(cmd)) == descriptor.digest, UriServesDifferentBytes(uri)); + console.log("verified ", uri); + } else { + console.log("WARNING: advertised URI is NOT verified to serve the committed bytes"); + console.log(" %s", uri); + console.log(" rerun with VERIFY_URI=1 and --ffi, or check by hand:"); + console.log(" curl -fsSL | sha256sum"); + } + } + + /// @dev Skips a redundant transaction only when the chain already carries + /// this exact commitment - digest, kind, and URIs. Comparing the + /// digest alone would make a URI-only change (moving hosting, same + /// document) a silent no-op that leaves a dead URI advertised. + function _publish(OwnedTWAP twap, Commitment.Data memory descriptor) internal { + (bytes32 currentDigest, PackageKind currentKind) = twap.descriptorCommitment(); + bool same = currentDigest == descriptor.digest && currentKind == descriptor.kind + && keccak256(abi.encode(twap.descriptorURI())) == keccak256(abi.encode(descriptor.uris)); + if (!same) twap.setDescriptor(descriptor); + } + + /// @dev `PRIVATE_KEY` if set, otherwise whatever `--account`, `--keystore` + /// or `--ledger` supplies on the command line. A raw key in the + /// environment is the worse of the two, so it is not the only option. + function _broadcaster() internal view returns (address deployer, uint256 pk) { + pk = vm.envOr("PRIVATE_KEY", uint256(0)); + deployer = pk == 0 ? msg.sender : vm.addr(pk); + } + + function _begin(uint256 pk) internal { + if (pk == 0) { + vm.startBroadcast(); + } else { + vm.startBroadcast(pk); + } + } + + function _at(bytes memory initCode) internal pure returns (address) { + return vm.computeCreate2Address(SALT, keccak256(initCode)); + } + + /// @dev Every address this script can produce, without deploying anything. + /// The TWAP address depends on the registry's, which is why it is + /// derived here rather than computed independently. + function predict(address settlement, address admin) + public + pure + returns (address composableCow, address twap, address stopLoss, address goodAfterTime) + { + composableCow = _at(abi.encodePacked(type(ComposableCow).creationCode, abi.encode(settlement))); + twap = _at(abi.encodePacked(type(OwnedTWAP).creationCode, abi.encode(composableCow, admin))); + stopLoss = _at(abi.encodePacked(type(OwnedStopLoss).creationCode, abi.encode(admin))); + goodAfterTime = _at(abi.encodePacked(type(OwnedGoodAfterTime).creationCode, abi.encode(admin))); + } + + /// @dev The registry and the one handler every deployment wants. Returns + /// what is already there rather than reverting, so re-running across a + /// set of chains converges instead of failing on the second attempt. + function _core(address settlement, address admin) internal returns (ComposableCow composableCow, OwnedTWAP twap) { + (address at, address twapAt,,) = predict(settlement, admin); + + composableCow = at.code.length != 0 ? ComposableCow(at) : new ComposableCow{salt: SALT}(settlement); + require(address(composableCow) == at, AddressMismatch(at, address(composableCow))); + + twap = twapAt.code.length != 0 ? OwnedTWAP(twapAt) : new OwnedTWAP{salt: SALT}(composableCow, admin); + require(address(twap) == twapAt, AddressMismatch(twapAt, address(twap))); + } + + function _report(address admin, ComposableCow composableCow, OwnedTWAP twap) internal view { + console.log("chainId ", block.chainid); + console.log("owner ", admin); + console.log("ComposableCow ", address(composableCow)); + console.log("OwnedTWAP ", address(twap)); + } + + function _next() internal pure { + console.log(""); + console.log("Record these in deployments/networks.json, then publish each"); + console.log("descriptor and call setDescriptor from the owner."); + } +} + +/** + * @title Ethereum mainnet deployment + * @dev The registry and TWAP only. `StopLoss` and `GoodAfterTime` are not + * deployed here: `GoodAfterTime` still has the open `TRY_NEXT_BLOCK` + * defect in #58, and neither is wanted on mainnet yet. Deploying them + * later against this same registry moves no address, since neither is an + * input to anything else. + */ +contract DeployMainnetStack is DeployOwnedStack { + uint256 private constant MAINNET = 1; + + function run() external { + (address settlement, address admin) = _preflight(MAINNET); + + (address deployer, uint256 pk) = _broadcaster(); + (bool set, Commitment.Data memory descriptor) = _twapDescriptor(deployer, admin); + if (set) _verifyOrWarn(descriptor); + + _begin(pk); + (ComposableCow composableCow, OwnedTWAP twap) = _core(settlement, admin); + if (set) _publish(twap, descriptor); + vm.stopBroadcast(); + + _report(admin, composableCow, twap); + if (set) { + console.log("TWAP descriptor ", descriptor.uris[0]); + console.logBytes32(descriptor.digest); + } + _next(); + } +} + +/** + * @title Gnosis Chain integration deployment + * @dev The registry and all three rotatable handlers. + */ +contract DeployGnosisStack is DeployOwnedStack { + uint256 private constant GNOSIS = 100; + + function run() external { + (address settlement, address admin) = _preflight(GNOSIS); + (,, address stopLossAt, address gatAt) = predict(settlement, admin); + + (address deployer, uint256 pk) = _broadcaster(); + (bool set, Commitment.Data memory descriptor) = _twapDescriptor(deployer, admin); + if (set) _verifyOrWarn(descriptor); + + _begin(pk); + + (ComposableCow composableCow, OwnedTWAP twap) = _core(settlement, admin); + if (set) _publish(twap, descriptor); + + OwnedStopLoss stopLoss = + stopLossAt.code.length != 0 ? OwnedStopLoss(stopLossAt) : new OwnedStopLoss{salt: SALT}(admin); + OwnedGoodAfterTime goodAfterTime = + gatAt.code.length != 0 ? OwnedGoodAfterTime(gatAt) : new OwnedGoodAfterTime{salt: SALT}(admin); + + vm.stopBroadcast(); + + require(address(stopLoss) == stopLossAt, AddressMismatch(stopLossAt, address(stopLoss))); + require(address(goodAfterTime) == gatAt, AddressMismatch(gatAt, address(goodAfterTime))); + + _report(admin, composableCow, twap); + console.log("OwnedStopLoss ", address(stopLoss)); + console.log("OwnedGoodAfterTime", address(goodAfterTime)); + _next(); + } +} diff --git a/script/deploy_ProdStack.s.sol b/script/deploy_ProdStack.s.sol index 3f1eae7a..a7b9093c 100644 --- a/script/deploy_ProdStack.s.sol +++ b/script/deploy_ProdStack.s.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; +import {Commitment} from "../src/libraries/Commitment.sol"; import {Script} from "forge-std/Script.sol"; // ExtensibleFallbackHandler @@ -34,11 +35,11 @@ contract DeployProdStack is Script { ComposableCow composableCow = new ComposableCow{salt: bytes32(0)}(settlement); // Deploy order types - new TWAP{salt: bytes32(0)}(composableCow, new string[](0), bytes32(0), PackageKind.BZZ_MANIFEST); - new GoodAfterTime{salt: bytes32(0)}(new string[](0), bytes32(0), PackageKind.BZZ_MANIFEST); - new PerpetualStableSwap{salt: bytes32(0)}(new string[](0), bytes32(0), PackageKind.BZZ_MANIFEST); + new TWAP{salt: bytes32(0)}(composableCow, Commitment.none()); + new GoodAfterTime{salt: bytes32(0)}(Commitment.none()); + new PerpetualStableSwap{salt: bytes32(0)}(Commitment.none()); new TradeAboveThreshold{salt: bytes32(0)}(); - new StopLoss{salt: bytes32(0)}(new string[](0), bytes32(0), PackageKind.BZZ_MANIFEST); + new StopLoss{salt: bytes32(0)}(Commitment.none()); // Deploy value factories new CurrentBlockTimestampFactory{salt: bytes32(0)}(); diff --git a/src/OrderDescriptor.sol b/src/OrderDescriptor.sol index aca1fabf..2937430e 100644 --- a/src/OrderDescriptor.sol +++ b/src/OrderDescriptor.sol @@ -1,86 +1,72 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; +import {TwoStepOwnable} from "./TwoStepOwnable.sol"; + import {IOrderDescriptor} from "./interfaces/IOrderDescriptor.sol"; import {PackageKind} from "./interfaces/PackageKind.sol"; -import {BaseConditionalOrder} from "./BaseConditionalOrder.sol"; +import {Commitment} from "./libraries/Commitment.sol"; /** * @title Order Descriptor mixin - opt-in descriptor commitment for handlers * @author mfw78 - * @dev Immutable by omission: there is no setter, and `DescriptorUpdate` is - * emitted exactly once, from the constructor. Deployments that support - * rotation add their own access-controlled setter and re-emit. + * @dev Inherits nothing beyond its own interface, so a handler may compose it + * with `BaseConditionalOrder` and `OrderModule` without the three meeting + * at a common base. * - * A handler constructed with no URIs does NOT advertise - * `IOrderDescriptor` - feature detection stays honest for deployments - * that predate their descriptor document; committing requires a - * redeployment. The digest is a constructor argument and therefore - * part of the initcode that fixes a CREATE2 address, so the document it - * commits to carries no handler identity of its own. + * Immutable by omission: no setter, and `DescriptorUpdate` is emitted + * exactly once, from the constructor. The commitment is what advertises + * `IOrderDescriptor`, not the URI list, since a `BZZ_MANIFEST` commitment + * locates its own document and publishes no URI. Handlers consult + * `_descriptorAdvertised` from `supportsInterface`. */ -abstract contract OrderDescriptor is IOrderDescriptor, BaseConditionalOrder { - /** - * @dev URIs cannot be published without a commitment to verify them against - */ - error UncommittedDescriptorURI(); - - /** - * @dev `SHA256` does not locate the document, so it requires a URI - */ - error DescriptorURIRequired(); +abstract contract OrderDescriptor is IOrderDescriptor { + using Commitment for Commitment.Data; - /** - * @dev A `BZZ_MANIFEST` commitment locates its own document; a URI could not - * be verified against a structure root anyway - */ - error DescriptorURINotUsed(); + /// @dev `internal` so `OwnedOrderDescriptor` writes what these accessors read. + Commitment.Data internal _descriptor; - string[] private _descriptorUris; - bytes32 private immutable _DESCRIPTOR_DIGEST; - PackageKind private immutable _DESCRIPTOR_KIND; - - constructor(string[] memory uris, bytes32 digest, PackageKind kind) { - if (digest != bytes32(0)) { - if (kind == PackageKind.SHA256) { - require(uris.length > 0, DescriptorURIRequired()); - } else { - require(uris.length == 0, DescriptorURINotUsed()); - } - emit DescriptorUpdate(uris, digest, kind); - } else { - require(uris.length == 0, UncommittedDescriptorURI()); + constructor(Commitment.Data memory descriptor) { + _descriptor.set(descriptor); + if (descriptor.digest != bytes32(0)) { + emit DescriptorUpdate(descriptor.uris, descriptor.digest, descriptor.kind); } - _descriptorUris = uris; - _DESCRIPTOR_DIGEST = digest; - _DESCRIPTOR_KIND = kind; } /** * @inheritdoc IOrderDescriptor */ function descriptorURI() external view returns (string[] memory uris) { - return _descriptorUris; + return _descriptor.uris; } /** * @inheritdoc IOrderDescriptor */ function descriptorCommitment() external view returns (bytes32 digest, PackageKind kind) { - return (_DESCRIPTOR_DIGEST, _DESCRIPTOR_KIND); + return (_descriptor.digest, _descriptor.kind); } - /** - * @dev Advertise `IOrderDescriptor` only when a descriptor is committed: - * claiming the interface while returning empty values is - * non-conformant per the discovery specification. The commitment is - * the gate, not the URI list, since a `BZZ_MANIFEST` commitment - * locates its own document and publishes no URI. - */ - function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { - if (interfaceId == type(IOrderDescriptor).interfaceId) { - return _DESCRIPTOR_DIGEST != bytes32(0); - } - return super.supportsInterface(interfaceId); + function _descriptorAdvertised() internal view returns (bool) { + return _descriptor.advertised(); + } +} + +/** + * @dev Adds rotation. The setter writes the storage the read-only accessors + * already read, so nothing has to be overridden, and `DescriptorUpdate` is + * re-emitted so indexers observe the change without polling. + * + * Ownership is two-step only ({TwoStepOwnable}): the commitment is the + * only mutable state here, so a mistyped single-step transfer would + * strand it. The recipient must accept; `renounceOwnership` is the + * deliberate freeze. + */ +abstract contract OwnedOrderDescriptor is OrderDescriptor, TwoStepOwnable { + using Commitment for Commitment.Data; + + function setDescriptor(Commitment.Data memory descriptor) external onlyOwner { + _descriptor.set(descriptor); + emit DescriptorUpdate(descriptor.uris, descriptor.digest, descriptor.kind); } } diff --git a/src/OrderModule.sol b/src/OrderModule.sol index d2c89499..bdb094f4 100644 --- a/src/OrderModule.sol +++ b/src/OrderModule.sol @@ -1,76 +1,70 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; +import {TwoStepOwnable} from "./TwoStepOwnable.sol"; + import {IOrderModule} from "./interfaces/IOrderModule.sol"; import {PackageKind} from "./interfaces/PackageKind.sol"; -import {BaseConditionalOrder} from "./BaseConditionalOrder.sol"; +import {Commitment} from "./libraries/Commitment.sol"; /** * @title Order Module mixin - opt-in module commitment for handlers * @author mfw78 - * @dev Immutable by omission, as for `OrderDescriptor`. The commitment is what - * advertises `IOrderModule`, not the URI list: a `BZZ_MANIFEST` - * commitment locates its own package and so publishes no URI. Constructed - * with a zero digest, the handler does not advertise the interface. + * @dev Inherits nothing beyond its own interface, so a handler may compose it + * with `BaseConditionalOrder` and `OrderModule` without the three meeting + * at a common base. + * + * Immutable by omission: no setter, and `ModuleUpdate` is emitted + * exactly once, from the constructor. The commitment is what advertises + * `IOrderModule`, not the URI list, since a `BZZ_MANIFEST` commitment + * locates its own package and publishes no URI. Handlers consult + * `_moduleAdvertised` from `supportsInterface`. */ -abstract contract OrderModule is IOrderModule, BaseConditionalOrder { - /** - * @dev URIs cannot be published without a commitment to verify them against - */ - error UncommittedModuleURI(); - - /** - * @dev `SHA256` does not locate the package, so it requires a URI - */ - error ModuleURIRequired(); - - /** - * @dev A `BZZ_MANIFEST` commitment locates its own package; a URI could not - * be verified against a structure root anyway - */ - error ModuleURINotUsed(); +abstract contract OrderModule is IOrderModule { + using Commitment for Commitment.Data; - string[] private _moduleUris; - bytes32 private immutable _MODULE_DIGEST; - PackageKind private immutable _MODULE_KIND; + /// @dev `internal` so `OwnedOrderModule` writes what these accessors read. + Commitment.Data internal _module; - constructor(string[] memory uris, bytes32 digest, PackageKind kind) { - if (digest != bytes32(0)) { - if (kind == PackageKind.SHA256) { - require(uris.length > 0, ModuleURIRequired()); - } else { - require(uris.length == 0, ModuleURINotUsed()); - } - emit ModuleUpdate(uris, digest, kind); - } else { - require(uris.length == 0, UncommittedModuleURI()); - } - _moduleUris = uris; - _MODULE_DIGEST = digest; - _MODULE_KIND = kind; + constructor(Commitment.Data memory module) { + _module.set(module); + if (module.digest != bytes32(0)) emit ModuleUpdate(module.uris, module.digest, module.kind); } /** * @inheritdoc IOrderModule */ function moduleURI() external view returns (string[] memory uris) { - return _moduleUris; + return _module.uris; } /** * @inheritdoc IOrderModule */ function moduleCommitment() external view returns (bytes32 digest, PackageKind kind) { - return (_MODULE_DIGEST, _MODULE_KIND); + return (_module.digest, _module.kind); } - /** - * @dev Advertise `IOrderModule` only when a module is committed - */ - function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { - if (interfaceId == type(IOrderModule).interfaceId) { - return _MODULE_DIGEST != bytes32(0); - } - return super.supportsInterface(interfaceId); + function _moduleAdvertised() internal view returns (bool) { + return _module.advertised(); + } +} + +/** + * @dev Adds rotation. The setter writes the storage the read-only accessors + * already read, so nothing has to be overridden, and `ModuleUpdate` is + * re-emitted so indexers observe the change without polling. + * + * Ownership is two-step only ({TwoStepOwnable}): the commitment is the + * only mutable state here, so a mistyped single-step transfer would + * strand it. The recipient must accept; `renounceOwnership` is the + * deliberate freeze. + */ +abstract contract OwnedOrderModule is OrderModule, TwoStepOwnable { + using Commitment for Commitment.Data; + + function setModule(Commitment.Data memory module) external onlyOwner { + _module.set(module); + emit ModuleUpdate(module.uris, module.digest, module.kind); } } diff --git a/src/TwoStepOwnable.sol b/src/TwoStepOwnable.sol new file mode 100644 index 00000000..00d797c9 --- /dev/null +++ b/src/TwoStepOwnable.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import {Ownable} from "solady/auth/Ownable.sol"; + +/** + * @title Two-step-only ownership + * @author mfw78 + * @dev Disables Solady's single-step `transferOwnership`: the owned commitment + * is the only mutable state on the handlers that use this, and a mistyped + * direct transfer would strand it. The two-step handover + * (`requestOwnershipHandover`/`completeOwnershipHandover`) is the only + * transfer path. `renounceOwnership` stays live as the deliberate freeze: + * a renounced handler is permanently as-committed. + */ +abstract contract TwoStepOwnable is Ownable { + /// @dev Single-step ownership transfer is disabled; use the handover + error TransferDisabled(); + + function transferOwnership(address) public payable virtual override onlyOwner { + revert TransferDisabled(); + } +} diff --git a/src/libraries/Commitment.sol b/src/libraries/Commitment.sol new file mode 100644 index 00000000..17c4e613 --- /dev/null +++ b/src/libraries/Commitment.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import {PackageKind} from "../interfaces/PackageKind.sol"; + +/** + * @title A content commitment and where to fetch it from + * @author mfw78 + * @dev Shared by the descriptor and module surfaces, which differ in what they + * commit to and in nothing else. Each holds its own `Data`, so the two + * occupy distinct slots and are set independently. + */ +library Commitment { + /** + * @dev URIs cannot be published without a commitment to verify them against + */ + error UncommittedURI(); + + /** + * @dev `SHA256` does not locate the content, so it requires a URI + */ + error URIRequired(); + + /** + * @dev A `BZZ_MANIFEST` commitment locates its own content; a URI could not + * be verified against a structure root anyway + */ + error URINotUsed(); + + struct Data { + string[] uris; + bytes32 digest; + PackageKind kind; + } + + /** + * @dev An uncommitted surface. The kind is immaterial while the digest is + * zero, so this spells that out rather than leaving an arbitrary + * `PackageKind` at each construction site. + */ + function none() internal pure returns (Data memory) { + return Data({uris: new string[](0), digest: bytes32(0), kind: PackageKind.BZZ_MANIFEST}); + } + + /// @dev `bytes32(0)` means uncommitted; such a surface is not advertised. + function advertised(Data storage self) internal view returns (bool) { + return self.digest != bytes32(0); + } + + function set(Data storage self, Data memory value) internal { + validate(value.uris.length, value.digest, value.kind); + self.uris = value.uris; + self.digest = value.digest; + self.kind = value.kind; + } + + function validate(uint256 uriCount, bytes32 digest, PackageKind kind) internal pure { + if (digest == bytes32(0)) { + require(uriCount == 0, UncommittedURI()); + } else if (kind == PackageKind.SHA256) { + require(uriCount > 0, URIRequired()); + } else { + require(uriCount == 0, URINotUsed()); + } + } +} diff --git a/src/types/GoodAfterTime.sol b/src/types/GoodAfterTime.sol index 1b13aa26..9c44ed45 100644 --- a/src/types/GoodAfterTime.sol +++ b/src/types/GoodAfterTime.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; +import {Commitment} from "../libraries/Commitment.sol"; +import {BaseConditionalOrder} from "../BaseConditionalOrder.sol"; +import {IOrderDescriptor} from "../interfaces/IOrderDescriptor.sol"; import {SafeCastLib} from "solady/utils/SafeCastLib.sol"; import {IExpectedOutCalculator} from "../vendored/Milkman.sol"; @@ -45,10 +48,8 @@ error PriceCheckerFailed(); * ensure that the order is not filled multiple times, a `minSellBalance` is * checked before the order is placed. */ -contract GoodAfterTime is OrderDescriptor { - constructor(string[] memory descriptorUris, bytes32 descriptorDigest_, PackageKind descriptorKind) - OrderDescriptor(descriptorUris, descriptorDigest_, descriptorKind) - {} +contract GoodAfterTime is BaseConditionalOrder, OrderDescriptor { + constructor(Commitment.Data memory descriptor) OrderDescriptor(descriptor) {} using SafeCastLib for uint256; @@ -157,4 +158,13 @@ contract GoodAfterTime is OrderDescriptor { { return "good-after-time order ready"; } + + /** + * @inheritdoc BaseConditionalOrder + * @dev Adds the descriptor sidecar, which is advertised only once committed. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + if (interfaceId == type(IOrderDescriptor).interfaceId) return _descriptorAdvertised(); + return super.supportsInterface(interfaceId); + } } diff --git a/src/types/Owned.sol b/src/types/Owned.sol new file mode 100644 index 00000000..692dd726 --- /dev/null +++ b/src/types/Owned.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import {ComposableCow} from "../ComposableCow.sol"; +import {OwnedOrderDescriptor} from "../OrderDescriptor.sol"; +import {OrderModule, OwnedOrderModule} from "../OrderModule.sol"; +import {IOrderDescriptor} from "../interfaces/IOrderDescriptor.sol"; +import {IOrderModule} from "../interfaces/IOrderModule.sol"; +import {Commitment} from "../libraries/Commitment.sol"; +import {GoodAfterTime} from "./GoodAfterTime.sol"; +import {StopLoss} from "./StopLoss.sol"; +import {TWAP} from "./twap/TWAP.sol"; + +/** + * @dev The handlers with rotatable commitments. Each extends the handler it is + * named for, so order generation is the same code and only the discovery + * surface differs. One owner governs both commitments. + * + * Constructed uncommitted, then committed by the owner. That ordering is + * forced rather than convenient: on the immutable handlers the digest is a + * constructor argument, so under CREATE2 the address would depend on a + * descriptor that cannot be built until the address is known. + */ +contract OwnedTWAP is TWAP, OwnedOrderDescriptor, OwnedOrderModule { + constructor(ComposableCow composableCow_, address owner_) + TWAP(composableCow_, Commitment.none()) + OrderModule(Commitment.none()) + { + _initializeOwner(owner_); + } + + function supportsInterface(bytes4 interfaceId) public view override returns (bool) { + if (interfaceId == type(IOrderModule).interfaceId) return _moduleAdvertised(); + return super.supportsInterface(interfaceId); + } +} + +/// @dev See {OwnedTWAP}. +contract OwnedStopLoss is StopLoss, OwnedOrderDescriptor, OwnedOrderModule { + constructor(address owner_) StopLoss(Commitment.none()) OrderModule(Commitment.none()) { + _initializeOwner(owner_); + } + + function supportsInterface(bytes4 interfaceId) public view override returns (bool) { + if (interfaceId == type(IOrderModule).interfaceId) return _moduleAdvertised(); + return super.supportsInterface(interfaceId); + } +} + +/// @dev See {OwnedTWAP}. +contract OwnedGoodAfterTime is GoodAfterTime, OwnedOrderDescriptor, OwnedOrderModule { + constructor(address owner_) GoodAfterTime(Commitment.none()) OrderModule(Commitment.none()) { + _initializeOwner(owner_); + } + + function supportsInterface(bytes4 interfaceId) public view override returns (bool) { + if (interfaceId == type(IOrderModule).interfaceId) return _moduleAdvertised(); + return super.supportsInterface(interfaceId); + } +} diff --git a/src/types/PerpetualStableSwap.sol b/src/types/PerpetualStableSwap.sol index e3e1e332..1ff773d7 100644 --- a/src/types/PerpetualStableSwap.sol +++ b/src/types/PerpetualStableSwap.sol @@ -8,6 +8,9 @@ import { IConditionalOrderGenerator, BaseConditionalOrder } from "../BaseConditionalOrder.sol"; +import {Commitment} from "../libraries/Commitment.sol"; +import {BaseConditionalOrder} from "../BaseConditionalOrder.sol"; +import {IOrderDescriptor} from "../interfaces/IOrderDescriptor.sol"; import {IOrderManifest} from "../interfaces/IOrderManifest.sol"; import {ConditionalOrdersUtilsLib as Utils} from "./ConditionalOrdersUtilsLib.sol"; import {OrderDescriptor} from "../OrderDescriptor.sol"; @@ -23,10 +26,8 @@ error NotFunded(); * @title A smart contract that is always willing to trade between tokenA and tokenB 1:1, * taking decimals into account (and adding specifiable spread) */ -contract PerpetualStableSwap is OrderDescriptor { - constructor(string[] memory descriptorUris, bytes32 descriptorDigest_, PackageKind descriptorKind) - OrderDescriptor(descriptorUris, descriptorDigest_, descriptorKind) - {} +contract PerpetualStableSwap is BaseConditionalOrder, OrderDescriptor { + constructor(Commitment.Data memory descriptor) OrderDescriptor(descriptor) {} /** * Creates a new perpetual swap order. All resulting swaps will be made from the target contract. @@ -183,4 +184,13 @@ contract PerpetualStableSwap is OrderDescriptor { return (new ManifestEntry[](0), false, _manifestStatus(errorData)); } } + + /** + * @inheritdoc BaseConditionalOrder + * @dev Adds the descriptor sidecar, which is advertised only once committed. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + if (interfaceId == type(IOrderDescriptor).interfaceId) return _descriptorAdvertised(); + return super.supportsInterface(interfaceId); + } } diff --git a/src/types/StopLoss.sol b/src/types/StopLoss.sol index cf6234c7..0cf3362e 100644 --- a/src/types/StopLoss.sol +++ b/src/types/StopLoss.sol @@ -8,6 +8,9 @@ import { IConditionalOrderGenerator, BaseConditionalOrder } from "../BaseConditionalOrder.sol"; +import {Commitment} from "../libraries/Commitment.sol"; +import {BaseConditionalOrder} from "../BaseConditionalOrder.sol"; +import {IOrderDescriptor} from "../interfaces/IOrderDescriptor.sol"; import {IAggregatorV3Interface} from "../interfaces/IAggregatorV3Interface.sol"; import {ConditionalOrdersUtilsLib as Utils} from "./ConditionalOrdersUtilsLib.sol"; import {OrderDescriptor} from "../OrderDescriptor.sol"; @@ -42,10 +45,8 @@ error OrderExpired(); * @notice Both oracles need to be denominated in the same quote currency (e.g. GNO/ETH and USD/ETH for GNO/USD stop loss orders) * @dev This order type has replay protection due to the `validTo` parameter, ensuring it will just execute one time */ -contract StopLoss is OrderDescriptor { - constructor(string[] memory descriptorUris, bytes32 descriptorDigest_, PackageKind descriptorKind) - OrderDescriptor(descriptorUris, descriptorDigest_, descriptorKind) - {} +contract StopLoss is BaseConditionalOrder, OrderDescriptor { + constructor(Commitment.Data memory descriptor) OrderDescriptor(descriptor) {} /** * @dev Scaling factor for the strike price @@ -169,4 +170,13 @@ contract StopLoss is OrderDescriptor { { return "stop-loss triggered"; } + + /** + * @inheritdoc BaseConditionalOrder + * @dev Adds the descriptor sidecar, which is advertised only once committed. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + if (interfaceId == type(IOrderDescriptor).interfaceId) return _descriptorAdvertised(); + return super.supportsInterface(interfaceId); + } } diff --git a/src/types/twap/TWAP.sol b/src/types/twap/TWAP.sol index c88da651..1170bc71 100644 --- a/src/types/twap/TWAP.sol +++ b/src/types/twap/TWAP.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; +import {Commitment} from "../../libraries/Commitment.sol"; +import {BaseConditionalOrder} from "../../BaseConditionalOrder.sol"; +import {IOrderDescriptor} from "../../interfaces/IOrderDescriptor.sol"; import {SafeCastLib} from "solady/utils/SafeCastLib.sol"; import {ComposableCow} from "../../ComposableCow.sol"; @@ -36,17 +39,12 @@ error OrderNotInitialized(); * specific price, even if the price of the token changes during the trade. * @dev Designed to be used with the CoW Protocol Conditional Order Framework. */ -contract TWAP is OrderDescriptor { +contract TWAP is BaseConditionalOrder, OrderDescriptor { using SafeCastLib for uint256; ComposableCow public immutable composableCow; - constructor( - ComposableCow _composableCow, - string[] memory descriptorUris, - bytes32 descriptorDigest_, - PackageKind descriptorKind - ) OrderDescriptor(descriptorUris, descriptorDigest_, descriptorKind) { + constructor(ComposableCow _composableCow, Commitment.Data memory descriptor) OrderDescriptor(descriptor) { composableCow = _composableCow; } @@ -301,4 +299,13 @@ contract TWAP is OrderDescriptor { isActive: block.timestamp >= validFrom && block.timestamp <= validTo }); } + + /** + * @inheritdoc BaseConditionalOrder + * @dev Adds the descriptor sidecar, which is advertised only once committed. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + if (interfaceId == type(IOrderDescriptor).interfaceId) return _descriptorAdvertised(); + return super.supportsInterface(interfaceId); + } } diff --git a/test/ComposableCow.base.t.sol b/test/ComposableCow.base.t.sol index b3b86cc8..b7e91b9d 100644 --- a/test/ComposableCow.base.t.sol +++ b/test/ComposableCow.base.t.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; +import {Commitment} from "../src/libraries/Commitment.sol"; + import {Safe} from "safe/Safe.sol"; import {Enum} from "safe/libraries/Enum.sol"; import {IERC165} from "safe/interfaces/IERC165.sol"; @@ -76,7 +78,10 @@ contract BaseComposableCowTest is Base { passThrough = new TestConditionalOrderGenerator(); mirror = new MirrorConditionalOrder(); - twap = new TWAP(composableCow, testDescriptorUris(), TEST_DESCRIPTOR_DIGEST, PackageKind.SHA256); + twap = new TWAP( + composableCow, + Commitment.Data({uris: testDescriptorUris(), digest: TEST_DESCRIPTOR_DIGEST, kind: PackageKind.SHA256}) + ); } /** diff --git a/test/ComposableCow.discovery.t.sol b/test/ComposableCow.discovery.t.sol index e6a148f9..c4074f8c 100644 --- a/test/ComposableCow.discovery.t.sol +++ b/test/ComposableCow.discovery.t.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; +import {Commitment} from "../src/libraries/Commitment.sol"; import {GPv2Order} from "cowprotocol/contracts/libraries/GPv2Order.sol"; import {IERC165} from "safe/interfaces/IERC165.sol"; @@ -10,6 +11,7 @@ import {IOrderDescriptor} from "../src/interfaces/IOrderDescriptor.sol"; import {IOrderModule} from "../src/interfaces/IOrderModule.sol"; import {OrderDescriptor} from "../src/OrderDescriptor.sol"; import {OrderModule} from "../src/OrderModule.sol"; +import {BaseConditionalOrder} from "../src/BaseConditionalOrder.sol"; import {StopLoss} from "../src/types/StopLoss.sol"; import {PackageKind} from "../src/interfaces/PackageKind.sol"; @@ -18,8 +20,13 @@ error TestNoOrder(); /** * @dev Minimal handler committing a module: the OrderModule mixin under test */ -contract ModuleHandler is OrderModule { - constructor(string[] memory uris, bytes32 digest, PackageKind kind) OrderModule(uris, digest, kind) {} +contract ModuleHandler is BaseConditionalOrder, OrderModule { + constructor(Commitment.Data memory commitment) OrderModule(commitment) {} + + function supportsInterface(bytes4 interfaceId) public view override returns (bool) { + if (interfaceId == type(IOrderModule).interfaceId) return _moduleAdvertised(); + return super.supportsInterface(interfaceId); + } function generateOrder(address, bytes32, bytes calldata, bytes calldata) public @@ -49,7 +56,9 @@ contract ComposableCowDiscoveryTest is BaseComposableCowTest { * super chain */ function test_descriptor_CommittedAdvertisesAndRoundTrips() public { - StopLoss handler = new StopLoss(testDescriptorUris(), TEST_DESCRIPTOR_DIGEST, PackageKind.SHA256); + StopLoss handler = new StopLoss( + Commitment.Data({uris: testDescriptorUris(), digest: TEST_DESCRIPTOR_DIGEST, kind: PackageKind.SHA256}) + ); assertTrue(handler.supportsInterface(type(IOrderDescriptor).interfaceId)); assertTrue(handler.supportsInterface(type(IConditionalOrderGenerator).interfaceId)); @@ -68,7 +77,7 @@ contract ComposableCowDiscoveryTest is BaseComposableCowTest { * sidecar - feature detection never lies about empty metadata */ function test_descriptor_UncommittedDoesNotAdvertise() public { - StopLoss handler = new StopLoss(new string[](0), bytes32(0), PackageKind.BZZ_MANIFEST); + StopLoss handler = new StopLoss(Commitment.none()); assertFalse(handler.supportsInterface(type(IOrderDescriptor).interfaceId)); // the handler remains a fully functional generator @@ -82,7 +91,9 @@ contract ComposableCowDiscoveryTest is BaseComposableCowTest { function test_descriptor_ConstructorEmitsUpdate() public { vm.expectEmit(true, true, true, true); emit IOrderDescriptor.DescriptorUpdate(testDescriptorUris(), TEST_DESCRIPTOR_DIGEST, PackageKind.SHA256); - new StopLoss(testDescriptorUris(), TEST_DESCRIPTOR_DIGEST, PackageKind.SHA256); + new StopLoss( + Commitment.Data({uris: testDescriptorUris(), digest: TEST_DESCRIPTOR_DIGEST, kind: PackageKind.SHA256}) + ); } // --- module --- @@ -95,7 +106,8 @@ contract ComposableCowDiscoveryTest is BaseComposableCowTest { vm.expectEmit(true, true, true, true); emit IOrderModule.ModuleUpdate(moduleUris(), digest, PackageKind.SHA256); - ModuleHandler handler = new ModuleHandler(moduleUris(), digest, PackageKind.SHA256); + ModuleHandler handler = + new ModuleHandler(Commitment.Data({uris: moduleUris(), digest: digest, kind: PackageKind.SHA256})); assertTrue(handler.supportsInterface(type(IOrderModule).interfaceId)); assertFalse(handler.supportsInterface(type(IOrderDescriptor).interfaceId)); @@ -110,8 +122,8 @@ contract ComposableCowDiscoveryTest is BaseComposableCowTest { * non-conformant */ function test_module_RevertsUncommittedURI() public { - vm.expectRevert(OrderModule.UncommittedModuleURI.selector); - new ModuleHandler(moduleUris(), bytes32(0), PackageKind.BZZ_MANIFEST); + vm.expectRevert(Commitment.UncommittedURI.selector); + new ModuleHandler(Commitment.Data({uris: moduleUris(), digest: bytes32(0), kind: PackageKind.BZZ_MANIFEST})); } /** @@ -120,16 +132,18 @@ contract ComposableCowDiscoveryTest is BaseComposableCowTest { * root, and publishing one would write a gateway into the contract */ function test_module_RevertsContentAddressedWithURI() public { - vm.expectRevert(OrderModule.ModuleURINotUsed.selector); - new ModuleHandler(moduleUris(), keccak256("pkg"), PackageKind.BZZ_MANIFEST); + vm.expectRevert(Commitment.URINotUsed.selector); + new ModuleHandler( + Commitment.Data({uris: moduleUris(), digest: keccak256("pkg"), kind: PackageKind.BZZ_MANIFEST}) + ); } /** * @dev `SHA256` does not locate the package, so it requires a URI */ function test_module_RevertsSha256WithoutURI() public { - vm.expectRevert(OrderModule.ModuleURIRequired.selector); - new ModuleHandler(new string[](0), keccak256("pkg"), PackageKind.SHA256); + vm.expectRevert(Commitment.URIRequired.selector); + new ModuleHandler(Commitment.Data({uris: new string[](0), digest: keccak256("pkg"), kind: PackageKind.SHA256})); } /** @@ -137,7 +151,9 @@ contract ComposableCowDiscoveryTest is BaseComposableCowTest { * advertises with no URI published at all */ function test_module_ContentAddressedNeedsNoURI() public { - ModuleHandler handler = new ModuleHandler(new string[](0), keccak256("pkg"), PackageKind.BZZ_MANIFEST); + ModuleHandler handler = new ModuleHandler( + Commitment.Data({uris: new string[](0), digest: keccak256("pkg"), kind: PackageKind.BZZ_MANIFEST}) + ); assertTrue(handler.supportsInterface(type(IOrderModule).interfaceId)); assertEq(handler.moduleURI().length, 0); } @@ -146,7 +162,7 @@ contract ComposableCowDiscoveryTest is BaseComposableCowTest { * @dev No module committed: no advertising, handler still functions */ function test_module_UncommittedDoesNotAdvertise() public { - ModuleHandler handler = new ModuleHandler(new string[](0), bytes32(0), PackageKind.BZZ_MANIFEST); + ModuleHandler handler = new ModuleHandler(Commitment.none()); assertFalse(handler.supportsInterface(type(IOrderModule).interfaceId)); assertTrue(handler.supportsInterface(type(IConditionalOrderGenerator).interfaceId)); } @@ -156,7 +172,9 @@ contract ComposableCowDiscoveryTest is BaseComposableCowTest { * empty - the discovery trigger end to end */ function test_module_NeedsInputSignal() public { - ModuleHandler handler = new ModuleHandler(new string[](0), keccak256("module"), PackageKind.BZZ_MANIFEST); + ModuleHandler handler = new ModuleHandler( + Commitment.Data({uris: new string[](0), digest: keccak256("module"), kind: PackageKind.BZZ_MANIFEST}) + ); IConditionalOrderGenerator.GeneratorResult memory result = handler.poll(address(safe1), bytes32(0), bytes(""), bytes("")); diff --git a/test/ComposableCow.gat.t.sol b/test/ComposableCow.gat.t.sol index 11905001..6c5b8efd 100644 --- a/test/ComposableCow.gat.t.sol +++ b/test/ComposableCow.gat.t.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; +import {Commitment} from "../src/libraries/Commitment.sol"; import {ERC1271} from "safe/handler/extensible/SignatureVerifierMuxer.sol"; import { @@ -37,7 +38,9 @@ contract ComposableCowGatTest is BaseComposableCowTest { super.setUp(); // deploy the GAT handler - gat = new GoodAfterTime(testDescriptorUris(), TEST_DESCRIPTOR_DIGEST, PackageKind.SHA256); + gat = new GoodAfterTime( + Commitment.Data({uris: testDescriptorUris(), digest: TEST_DESCRIPTOR_DIGEST, kind: PackageKind.SHA256}) + ); // deploy the test expected out calculator testOutCalculator = new TestExpectedOutCalculator(); diff --git a/test/ComposableCow.manifest.t.sol b/test/ComposableCow.manifest.t.sol index 59486b3a..a6b32368 100644 --- a/test/ComposableCow.manifest.t.sol +++ b/test/ComposableCow.manifest.t.sol @@ -11,6 +11,7 @@ import { PollTryAtTimestampHandler, SuccessHandler } from "./ComposableCow.base.t.sol"; +import {Commitment} from "../src/libraries/Commitment.sol"; import {IOrderManifest} from "../src/interfaces/IOrderManifest.sol"; import {IERC165} from "safe/interfaces/IERC165.sol"; import {TWAPOrder} from "../src/types/twap/libraries/TWAPOrder.sol"; @@ -42,7 +43,9 @@ contract ComposableCowManifestTest is BaseComposableCowTest { function setUp() public virtual override(BaseComposableCowTest) { super.setUp(); - perpetualSwap = new PerpetualStableSwap(testDescriptorUris(), TEST_DESCRIPTOR_DIGEST, PackageKind.SHA256); + perpetualSwap = new PerpetualStableSwap( + Commitment.Data({uris: testDescriptorUris(), digest: TEST_DESCRIPTOR_DIGEST, kind: PackageKind.SHA256}) + ); currentBlockTimestampFactory = new CurrentBlockTimestampFactory(); } diff --git a/test/ComposableCow.owned.t.sol b/test/ComposableCow.owned.t.sol new file mode 100644 index 00000000..4414b2ed --- /dev/null +++ b/test/ComposableCow.owned.t.sol @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import {Ownable} from "solady/auth/Ownable.sol"; + +import {Commitment} from "../src/libraries/Commitment.sol"; +import "./ComposableCow.base.t.sol"; + +import {OrderDescriptor} from "../src/OrderDescriptor.sol"; +import {IOrderDescriptor} from "../src/interfaces/IOrderDescriptor.sol"; +import {IOrderModule} from "../src/interfaces/IOrderModule.sol"; +import {PackageKind} from "../src/interfaces/PackageKind.sol"; +import {OwnedGoodAfterTime, OwnedStopLoss, OwnedTWAP} from "../src/types/Owned.sol"; +import {StopLoss} from "../src/types/StopLoss.sol"; +import {TwoStepOwnable} from "../src/TwoStepOwnable.sol"; + +contract ComposableCowOwnedTest is BaseComposableCowTest { + OwnedTWAP private ownedTwap; + OwnedStopLoss private ownedStopLoss; + OwnedGoodAfterTime private ownedGat; + + address private constant OWNER = address(0xA11CE); + address private constant STRANGER = address(0xBAD); + + bytes32 private constant DIGEST = keccak256("descriptor"); + + function setUp() public virtual override(BaseComposableCowTest) { + super.setUp(); + ownedTwap = new OwnedTWAP(composableCow, OWNER); + ownedStopLoss = new OwnedStopLoss(OWNER); + ownedGat = new OwnedGoodAfterTime(OWNER); + } + + function _uris(string memory u) private pure returns (string[] memory out) { + out = new string[](1); + out[0] = u; + } + + /// @dev Uncommitted at construction: nothing to advertise until the owner sets it. + function test_owned_UncommittedOnDeploy() public { + (bytes32 digest,) = ownedTwap.descriptorCommitment(); + assertEq(digest, bytes32(0)); + assertEq(ownedTwap.descriptorURI().length, 0); + assertFalse(ownedTwap.supportsInterface(type(IOrderDescriptor).interfaceId)); + assertFalse(ownedTwap.supportsInterface(type(IOrderModule).interfaceId)); + assertEq(ownedTwap.owner(), OWNER, "deployer must not retain ownership"); + } + + function test_owned_SetDescriptorAdvertisesAndRoundTrips() public { + vm.expectEmit(true, true, true, true); + emit IOrderDescriptor.DescriptorUpdate(new string[](0), DIGEST, PackageKind.BZZ_MANIFEST); + + vm.prank(OWNER); + ownedTwap.setDescriptor( + Commitment.Data({uris: new string[](0), digest: DIGEST, kind: PackageKind.BZZ_MANIFEST}) + ); + + (bytes32 digest, PackageKind kind) = ownedTwap.descriptorCommitment(); + assertEq(digest, DIGEST); + assertEq(uint256(kind), uint256(PackageKind.BZZ_MANIFEST)); + assertTrue(ownedTwap.supportsInterface(type(IOrderDescriptor).interfaceId)); + assertFalse(ownedTwap.supportsInterface(type(IOrderModule).interfaceId)); + } + + /// @dev The two commitments are independent surfaces under one owner. + function test_owned_SetModuleIsIndependentOfDescriptor() public { + vm.prank(OWNER); + ownedStopLoss.setModule( + Commitment.Data({ + uris: _uris("https://example.invalid/module.tar.zst"), digest: DIGEST, kind: PackageKind.SHA256 + }) + ); + + (bytes32 digest, PackageKind kind) = ownedStopLoss.moduleCommitment(); + assertEq(digest, DIGEST); + assertEq(uint256(kind), uint256(PackageKind.SHA256)); + assertTrue(ownedStopLoss.supportsInterface(type(IOrderModule).interfaceId)); + assertFalse(ownedStopLoss.supportsInterface(type(IOrderDescriptor).interfaceId)); + } + + /// @dev Rotation is the whole point: a second set must replace the first. + function test_owned_RotationReplacesCommitment() public { + vm.startPrank(OWNER); + ownedGat.setDescriptor(Commitment.Data({uris: new string[](0), digest: DIGEST, kind: PackageKind.BZZ_MANIFEST})); + bytes32 next = keccak256("rotated"); + ownedGat.setDescriptor( + Commitment.Data({uris: _uris("https://example.invalid/d.json"), digest: next, kind: PackageKind.SHA256}) + ); + vm.stopPrank(); + + (bytes32 digest, PackageKind kind) = ownedGat.descriptorCommitment(); + assertEq(digest, next); + assertEq(uint256(kind), uint256(PackageKind.SHA256)); + assertEq(ownedGat.descriptorURI().length, 1); + } + + function test_owned_RevertsForStranger() public { + vm.startPrank(STRANGER); + + vm.expectRevert(Ownable.Unauthorized.selector); + ownedTwap.setDescriptor( + Commitment.Data({uris: new string[](0), digest: DIGEST, kind: PackageKind.BZZ_MANIFEST}) + ); + + vm.expectRevert(Ownable.Unauthorized.selector); + ownedTwap.setModule(Commitment.Data({uris: new string[](0), digest: DIGEST, kind: PackageKind.BZZ_MANIFEST})); + + vm.stopPrank(); + } + + /// @dev The constructor invariants of the immutable mixin, enforced on write. + function test_owned_EnforcesURIInvariants() public { + vm.startPrank(OWNER); + + vm.expectRevert(Commitment.URIRequired.selector); + ownedTwap.setDescriptor(Commitment.Data({uris: new string[](0), digest: DIGEST, kind: PackageKind.SHA256})); + + vm.expectRevert(Commitment.URINotUsed.selector); + ownedTwap.setDescriptor( + Commitment.Data({uris: _uris("bzz://x"), digest: DIGEST, kind: PackageKind.BZZ_MANIFEST}) + ); + + vm.expectRevert(Commitment.UncommittedURI.selector); + ownedTwap.setDescriptor( + Commitment.Data({uris: _uris("bzz://x"), digest: bytes32(0), kind: PackageKind.BZZ_MANIFEST}) + ); + + vm.stopPrank(); + } + + /** + * @dev Two-step handover, in the stronger direction. Solady moves control + * only to a recipient that has itself asked for it, so a mistyped + * address cannot strand the commitments: it will never have asked. + */ + function test_owned_TransferIsTwoStep() public { + // the single-step path is disabled outright: a mistyped direct + // transfer cannot strand the commitment + vm.prank(OWNER); + vm.expectRevert(TwoStepOwnable.TransferDisabled.selector); + ownedTwap.transferOwnership(STRANGER); + assertEq(ownedTwap.owner(), OWNER, "ownership moved through the disabled path"); + + // ownership cannot be pushed at an address that has not asked for it + vm.prank(OWNER); + vm.expectRevert(Ownable.NoHandoverRequest.selector); + ownedTwap.completeOwnershipHandover(STRANGER); + assertEq(ownedTwap.owner(), OWNER, "ownership moved without a request"); + + vm.prank(STRANGER); + ownedTwap.requestOwnershipHandover(); + assertEq(ownedTwap.owner(), OWNER, "ownership moved on the request alone"); + assertGt(ownedTwap.ownershipHandoverExpiresAt(STRANGER), block.timestamp); + + vm.prank(OWNER); + ownedTwap.completeOwnershipHandover(STRANGER); + assertEq(ownedTwap.owner(), STRANGER); + + vm.prank(OWNER); + vm.expectRevert(Ownable.Unauthorized.selector); + ownedTwap.setDescriptor( + Commitment.Data({uris: new string[](0), digest: DIGEST, kind: PackageKind.BZZ_MANIFEST}) + ); + } + + /// @dev `renounceOwnership` is the deliberate freeze: after it, the + /// handler is permanently as-committed - nobody can rotate + function test_owned_RenounceFreezesCommitment() public { + vm.prank(OWNER); + ownedTwap.setDescriptor( + Commitment.Data({uris: new string[](0), digest: DIGEST, kind: PackageKind.BZZ_MANIFEST}) + ); + + vm.prank(OWNER); + ownedTwap.renounceOwnership(); + assertEq(ownedTwap.owner(), address(0)); + + vm.prank(OWNER); + vm.expectRevert(Ownable.Unauthorized.selector); + ownedTwap.setDescriptor( + Commitment.Data({uris: new string[](0), digest: bytes32(uint256(1)), kind: PackageKind.BZZ_MANIFEST}) + ); + + // the frozen commitment still reads back + (bytes32 digest,) = ownedTwap.descriptorCommitment(); + assertEq(digest, DIGEST); + } + + /** + * @dev The variants exist to change the discovery surface and nothing else. + * One owner governs both commitments. + */ + function test_owned_OrderGenerationIsUnchanged() public { + StopLoss.Data memory o; // zero amounts, rejected before any oracle is consulted + + StopLoss immutableHandler = new StopLoss(Commitment.none()); + + bytes memory expected = + abi.encodeWithSelector(IConditionalOrder.OrderNotValid.selector, bytes4(keccak256("ZeroAmount()"))); + + vm.expectRevert(expected); + immutableHandler.generateOrder(address(safe1), bytes32(0), abi.encode(o), bytes("")); + + vm.expectRevert(expected); + ownedStopLoss.generateOrder(address(safe1), bytes32(0), abi.encode(o), bytes("")); + } +} diff --git a/test/ComposableCow.stoploss.t.sol b/test/ComposableCow.stoploss.t.sol index b02e076b..a37a5478 100644 --- a/test/ComposableCow.stoploss.t.sol +++ b/test/ComposableCow.stoploss.t.sol @@ -8,6 +8,7 @@ import { BaseComposableCowTest, IConditionalOrderGenerator } from "./ComposableCow.base.t.sol"; +import {Commitment} from "../src/libraries/Commitment.sol"; import {IAggregatorV3Interface} from "../src/interfaces/IAggregatorV3Interface.sol"; import { StopLoss, @@ -34,7 +35,9 @@ contract ComposableCowStopLossTest is BaseComposableCowTest { function setUp() public virtual override(BaseComposableCowTest) { super.setUp(); - stopLoss = new StopLoss(testDescriptorUris(), TEST_DESCRIPTOR_DIGEST, PackageKind.SHA256); + stopLoss = new StopLoss( + Commitment.Data({uris: testDescriptorUris(), digest: TEST_DESCRIPTOR_DIGEST, kind: PackageKind.SHA256}) + ); } function priceToAddress(int256 price) internal returns (address) { diff --git a/test/ComposableCow.twap.t.sol b/test/ComposableCow.twap.t.sol index 84133562..5f8a5da3 100644 --- a/test/ComposableCow.twap.t.sol +++ b/test/ComposableCow.twap.t.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; +import {Commitment} from "../src/libraries/Commitment.sol"; import {SafeCastLib} from "solady/utils/SafeCastLib.sol"; import {ERC1271} from "safe/handler/extensible/SignatureVerifierMuxer.sol"; @@ -56,7 +57,10 @@ contract ComposableCowTwapTest is BaseComposableCowTest { super.setUp(); // deploy the TWAP handler - twap = new TWAP(composableCow, testDescriptorUris(), TEST_DESCRIPTOR_DIGEST, PackageKind.SHA256); + twap = new TWAP( + composableCow, + Commitment.Data({uris: testDescriptorUris(), digest: TEST_DESCRIPTOR_DIGEST, kind: PackageKind.SHA256}) + ); // deploy the current block timestamp factory currentBlockTimestampFactory = new CurrentBlockTimestampFactory(); diff --git a/test/DeployStack.t.sol b/test/DeployStack.t.sol new file mode 100644 index 00000000..381cc58b --- /dev/null +++ b/test/DeployStack.t.sol @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import {Test} from "forge-std/Test.sol"; + +import {ComposableCow} from "../src/ComposableCow.sol"; +import {Commitment} from "../src/libraries/Commitment.sol"; +import {PackageKind} from "../src/interfaces/PackageKind.sol"; +import {OwnedTWAP} from "../src/types/Owned.sol"; +import {DeployOwnedStack} from "../script/deploy_OwnedStack.s.sol"; + +contract ValidateHarness is DeployOwnedStack { + function validate(uint256 expectedChain, address settlement, address admin) external view { + _validate(expectedChain, settlement, admin); + } + + function descriptorFor(string calldata uri, address deployer, address admin) + external + view + returns (bool, Commitment.Data memory) + { + return _descriptorFor(uri, deployer, admin); + } + + function isHttps(string calldata uri) external pure returns (bool) { + return _isHttps(uri); + } +} + +/** + * @dev The descriptor is committed as a sha256 over published bytes, so the + * digest going on chain has to be the digest of the document that is + * actually served. The script computes it from the repository rather than + * taking it on trust, and these check that it does. + */ +contract DescriptorPublishTest is Test { + address internal constant ADMIN = address(0xA11CE); + string internal constant URI = "https://example.invalid/twap.json"; + + ValidateHarness internal harness; + + function setUp() public { + harness = new ValidateHarness(); + } + + /** + * @dev The digest is sha256 over the document as it sits in the repo, + * checked twice on purpose. The pinned literal proves the digest + * matches what `sha256sum descriptors/TWAP.json` prints - agreement + * with the tool anyone verifying the published document will reach + * for. The `sha256(vm.readFile(...))` comparison proves the script's + * digest derives from that exact file, byte for byte: the document + * ends in a newline, and dropping it would silently change every + * digest ever published. Only the pair rules out both drift modes. + * + * Update the constant deliberately if the document changes. + */ + function test_descriptor_DigestIsTheDocumentsSha256() public view { + (bool set, Commitment.Data memory d) = harness.descriptorFor(URI, ADMIN, ADMIN); + + assertTrue(set); + assertEq( + d.digest, + 0xb499b04e292a7fe808b982113e7e931446261bbc5d702517ba89a8403536ce1a, + "digest does not match sha256sum of the document" + ); + assertEq(bytes(vm.readFile("descriptors/TWAP.json")).length, 1825, "readFile did not return the file exactly"); + assertEq(d.digest, sha256(bytes(vm.readFile("descriptors/TWAP.json"))), "digest is not the document's"); + assertEq(uint256(d.kind), uint256(PackageKind.SHA256)); + assertEq(d.uris.length, 1); + assertEq(d.uris[0], URI); + } + + /// @dev `setDescriptor` is `onlyOwner`, so publishing in the same run needs + /// the owner's key. Failing loudly beats a reverting broadcast. + function test_descriptor_RequiresTheOwnerKey() public { + vm.expectRevert( + abi.encodeWithSelector(DeployOwnedStack.DescriptorNeedsOwnerKey.selector, address(0xB0B), ADMIN) + ); + harness.descriptorFor(URI, address(0xB0B), ADMIN); + } + + function test_descriptor_RejectsANonHttpsUri() public { + vm.expectRevert( + abi.encodeWithSelector(DeployOwnedStack.DescriptorUriNotHttps.selector, "http://example.invalid/twap.json") + ); + harness.descriptorFor("http://example.invalid/twap.json", ADMIN, ADMIN); + } + + /// @dev Unset, the handler deploys uncommitted exactly as before. + function test_descriptor_OptionalWhenUriUnset() public view { + (bool set,) = harness.descriptorFor("", ADMIN, ADMIN); + assertFalse(set, "an unset URI still published"); + } + + function test_isHttps() public view { + assertTrue(harness.isHttps("https://a")); + assertFalse(harness.isHttps("http://a")); + assertFalse(harness.isHttps("https://"), "scheme alone is not a URI"); + assertFalse(harness.isHttps("bzz://a")); + assertFalse(harness.isHttps("")); + } +} + +/// @dev CREATE2 buys one address per contract across every chain. That only +/// holds while the initcode carries nothing chain-specific, so these pin +/// what does and does not reach an address. +contract DeployAddressTest is Test { + ValidateHarness internal harness; + + address internal constant SETTLEMENT = 0x9008D19f58AAbD9eD0D60971565AA8510560ab41; + address internal constant ADMIN = address(0xA11CE); + + function setUp() public { + harness = new ValidateHarness(); + } + + /// @dev The reason for CREATE2 at all: same inputs, different chain, same + /// addresses. `predict` is `pure`, so no chain state can reach it. + function test_predict_IsTheSameOnEveryChain() public { + vm.chainId(1); + (address a1, address b1, address c1, address d1) = harness.predict(SETTLEMENT, ADMIN); + + vm.chainId(100); + (address a2, address b2, address c2, address d2) = harness.predict(SETTLEMENT, ADMIN); + + vm.chainId(8453); + (address a3, address b3, address c3, address d3) = harness.predict(SETTLEMENT, ADMIN); + + assertEq(a1, a2, "registry moved"); + assertEq(a1, a3, "registry moved"); + assertEq(b1, b2, "twap moved"); + assertEq(b1, b3, "twap moved"); + assertEq(c1, c2, "stopLoss moved"); + assertEq(d1, d2, "goodAfterTime moved"); + } + + /// @dev The TWAP address is derived from the registry's, not computed + /// beside it: a different registry has to move the handler too, or + /// the second deployment would point at the wrong one. + function test_predict_TwapFollowsTheRegistry() public view { + (address regA, address twapA,,) = harness.predict(SETTLEMENT, ADMIN); + (address regB, address twapB,,) = harness.predict(address(0xBEEF), ADMIN); + + assertTrue(regA != regB, "settlement does not reach the registry address"); + assertTrue(twapA != twapB, "registry does not reach the twap address"); + } + + /// @dev The precondition worth stating loudly: a different owner is a + /// different handler address, while the registry is unaffected. + function test_predict_AdminMovesHandlersOnly() public view { + (address regA, address twapA, address slA, address gatA) = harness.predict(SETTLEMENT, ADMIN); + (address regB, address twapB, address slB, address gatB) = harness.predict(SETTLEMENT, address(0xB0B)); + + assertEq(regA, regB, "admin should not reach the registry address"); + assertTrue(twapA != twapB, "admin does not reach the twap address"); + assertTrue(slA != slB, "admin does not reach the stopLoss address"); + assertTrue(gatA != gatB, "admin does not reach the goodAfterTime address"); + } + + /** + * @dev The chaining itself: the handler's initcode must carry the registry + * address, not the settlement one. Moving the settlement moves both, so + * a test that only varies the settlement cannot tell the two apart, and + * a mutation swapping them survives it. This pins the encoding. + */ + function test_predict_TwapEncodesTheRegistryNotTheSettlement() public view { + (address registry, address twap,,) = harness.predict(SETTLEMENT, ADMIN); + + assertEq( + twap, + vm.computeCreate2Address( + bytes32(0), keccak256(abi.encodePacked(type(OwnedTWAP).creationCode, abi.encode(registry, ADMIN))) + ), + "twap initcode does not carry the registry" + ); + + assertTrue( + twap + != vm.computeCreate2Address( + bytes32(0), keccak256(abi.encodePacked(type(OwnedTWAP).creationCode, abi.encode(SETTLEMENT, ADMIN))) + ), + "twap initcode carries the settlement" + ); + } + + /// @dev Checked against the cheatcode rather than a second copy of the + /// same derivation. + function test_predict_MatchesCreate2() public view { + (address registry,,,) = harness.predict(SETTLEMENT, ADMIN); + assertEq( + registry, + vm.computeCreate2Address( + bytes32(0), keccak256(abi.encodePacked(type(ComposableCow).creationCode, abi.encode(SETTLEMENT))) + ) + ); + } +} + +/** + * @dev The preflight checks run once, on a live network, with real funds behind + * them. Each is asserted to fire rather than assumed to. + */ +contract DeployStackTest is Test { + uint256 internal constant MAINNET = 1; + + ValidateHarness internal harness; + address internal settlement; + address internal admin = address(0xA11CE); + + function setUp() public { + harness = new ValidateHarness(); + // the check is only that the address has code, so any contract serves + settlement = address(new Bytecode()); + vm.chainId(MAINNET); + } + + function test_validate_AcceptsAValidConfig() public view { + harness.validate(MAINNET, settlement, admin); + } + + /// @dev The check that catches a stale `ETH_RPC_URL`. + function test_validate_RejectsWrongChain() public { + vm.chainId(100); + vm.expectRevert(abi.encodeWithSelector(DeployOwnedStack.WrongChain.selector, MAINNET, uint256(100))); + harness.validate(MAINNET, settlement, admin); + } + + /// @dev A settlement address with no code means the wrong address or the + /// wrong chain, and every order would be unsettleable. + function test_validate_RejectsCodelessSettlement() public { + vm.expectRevert(abi.encodeWithSelector(DeployOwnedStack.SettlementHasNoCode.selector, address(0xBEEF))); + harness.validate(MAINNET, address(0xBEEF), admin); + } + + /// @dev A zero owner strands both commitments: the handler deploys + /// uncommitted and no key can ever call `setDescriptor`. + function test_validate_RejectsZeroOwner() public { + vm.expectRevert(DeployOwnedStack.OwnerIsZero.selector); + harness.validate(MAINNET, settlement, address(0)); + } +} + +/// @dev Something with a non-empty code size, and nothing else. +contract Bytecode {}