diff --git a/bindings/generated/latest/ccip/burnminttokenpool/burnminttokenpool.go b/bindings/generated/latest/ccip/burnminttokenpool/burnminttokenpool.go index eba2728da..5468f5872 100644 --- a/bindings/generated/latest/ccip/burnminttokenpool/burnminttokenpool.go +++ b/bindings/generated/latest/ccip/burnminttokenpool/burnminttokenpool.go @@ -29,7 +29,7 @@ var ( const ( PackageName = "ccip-burn-mint-token-pool" - PackageID = "5822d23b12667a5ed3522e7c47c2af7e359ab585f3eb33276c8ae9b567ae60c1" + PackageID = "37c1e5db1dcb603a607c5cd9761d1bc39a9764c7e21ad777059a055ef022ce19" SDKVersion = "3.4.11" ) diff --git a/bindings/generated/latest/ccip/ccipruntime/ccipruntime.go b/bindings/generated/latest/ccip/ccipruntime/ccipruntime.go index 5a47f941e..939748edb 100644 --- a/bindings/generated/latest/ccip/ccipruntime/ccipruntime.go +++ b/bindings/generated/latest/ccip/ccipruntime/ccipruntime.go @@ -29,7 +29,7 @@ var ( const ( PackageName = "ccip-runtime" - PackageID = "226eaf64549749a83727d42eeff2fa5d773ff3c5804203b1b1f50ab90690f829" + PackageID = "be37faa07f3b25828f65c19df1d4f0f378e75c00c76f4a6a23c962a6b6238561" SDKVersion = "3.4.11" ) diff --git a/bindings/generated/latest/ccip/committeeverifier/committeeverifier.go b/bindings/generated/latest/ccip/committeeverifier/committeeverifier.go index 33ac8eeef..4c4fe99cc 100644 --- a/bindings/generated/latest/ccip/committeeverifier/committeeverifier.go +++ b/bindings/generated/latest/ccip/committeeverifier/committeeverifier.go @@ -27,7 +27,7 @@ var ( const ( PackageName = "ccip-committee-verifier" - PackageID = "2117217749b628de3ed7dfc14a8b06adebfa6b3db90f9f9a3909fa765eefdb4d" + PackageID = "fa6aec545c2926f7137c9760cdd907bad24b45a526cc60946ad95d698d4d045a" SDKVersion = "3.4.11" ) diff --git a/bindings/generated/latest/ccip/core/core.go b/bindings/generated/latest/ccip/core/core.go index f62a3dea8..f503ca5aa 100644 --- a/bindings/generated/latest/ccip/core/core.go +++ b/bindings/generated/latest/ccip/core/core.go @@ -26,7 +26,7 @@ var ( const ( PackageName = "ccip-core" - PackageID = "e89320df31ce1ad984f46f35bf98533ff1a1405f61f610163c482e6f064a03f2" + PackageID = "4c42daa70c1b656229cce81d1e83da7072efa3ce8d26ef0e3297d4f65663d3a2" SDKVersion = "3.4.11" ) diff --git a/bindings/generated/latest/ccip/executor/executor.go b/bindings/generated/latest/ccip/executor/executor.go index da721f7d5..853212c45 100644 --- a/bindings/generated/latest/ccip/executor/executor.go +++ b/bindings/generated/latest/ccip/executor/executor.go @@ -28,7 +28,7 @@ var ( const ( PackageName = "ccip-executor" - PackageID = "bc9fd3db3a653396dc25b2c52134fa3128430041d6a7a5763677651cd513edaa" + PackageID = "bc2fb9eb13e097934e29aa9c667ea5ffd1399e3a2f16634b7fcc51c5888d7d83" SDKVersion = "3.4.11" ) diff --git a/bindings/generated/latest/ccip/extensionapi/extensionapi.go b/bindings/generated/latest/ccip/extensionapi/extensionapi.go index 9b596cde4..3be5d9852 100644 --- a/bindings/generated/latest/ccip/extensionapi/extensionapi.go +++ b/bindings/generated/latest/ccip/extensionapi/extensionapi.go @@ -27,7 +27,7 @@ var ( const ( PackageName = "ccip-extension-api" - PackageID = "1f0c88a6b98c2090ddb80ccb0f8c8fbfafd24e744dbca0426ca09344d47ba08b" + PackageID = "fd5a761c5e22e046549ae98991b3e1fa66d076a55b7fe6a11771af3ffc7279f4" SDKVersion = "3.4.11" ) diff --git a/bindings/generated/latest/ccip/factory/factory.go b/bindings/generated/latest/ccip/factory/factory.go index fdcfe0d74..a6772326c 100644 --- a/bindings/generated/latest/ccip/factory/factory.go +++ b/bindings/generated/latest/ccip/factory/factory.go @@ -34,7 +34,7 @@ var ( const ( PackageName = "ccip-factory" - PackageID = "f62dfada9ce7d447060af0217f9c3b7f84b106c25b648a4412d5113251e18fee" + PackageID = "3f1b76629c558072f86be68a9b8a42bbebca86fcb3371ee344f620e36d1ed9b3" SDKVersion = "3.4.11" ) diff --git a/bindings/generated/latest/ccip/lockreleasetokenpool/lockreleasetokenpool.go b/bindings/generated/latest/ccip/lockreleasetokenpool/lockreleasetokenpool.go index 554cb1378..7c6c2a1a9 100644 --- a/bindings/generated/latest/ccip/lockreleasetokenpool/lockreleasetokenpool.go +++ b/bindings/generated/latest/ccip/lockreleasetokenpool/lockreleasetokenpool.go @@ -29,7 +29,7 @@ var ( const ( PackageName = "ccip-lock-release-token-pool" - PackageID = "0c24e0698b6e728a654aa036b2c9f37a942f837f31b7f6d50e0f95888ffbbf5b" + PackageID = "982ca7c632be659439140a16f3ae54bb1d8a4e4130c5fc92989d503c0e6408c9" SDKVersion = "3.4.11" ) diff --git a/bindings/generated/latest/ccip/receiver/receiver.go b/bindings/generated/latest/ccip/receiver/receiver.go index 6b53e9ecf..64fe604c4 100644 --- a/bindings/generated/latest/ccip/receiver/receiver.go +++ b/bindings/generated/latest/ccip/receiver/receiver.go @@ -27,7 +27,7 @@ var ( const ( PackageName = "ccip-receiver" - PackageID = "eb89101e24a5d28be729f735d6684fa1af3122d60ca8d9a8c5c44821b1b506bf" + PackageID = "c01a146dec1226794e8afb0e04bd513ce8ceb5f092460e94ea7a87d19bff3f74" SDKVersion = "3.4.11" ) diff --git a/bindings/generated/latest/ccip/sender/sender.go b/bindings/generated/latest/ccip/sender/sender.go index 1d3650136..04019778a 100644 --- a/bindings/generated/latest/ccip/sender/sender.go +++ b/bindings/generated/latest/ccip/sender/sender.go @@ -26,7 +26,7 @@ var ( const ( PackageName = "ccip-sender" - PackageID = "218f9f0d9c784e0c4981930b0dcdda82bcac2fee8eee050c154e736224956128" + PackageID = "dae9f63f5ce2db85e68106a8adfafe1d9083cb7d3b6b8c237e7c4e5b180f7a72" SDKVersion = "3.4.11" ) diff --git a/bindings/generated/latest/mcms/api/api.go b/bindings/generated/latest/mcms/api/api.go index 8673a7847..194f6b0b9 100644 --- a/bindings/generated/latest/mcms/api/api.go +++ b/bindings/generated/latest/mcms/api/api.go @@ -23,7 +23,7 @@ var ( const ( PackageName = "mcms-api" - PackageID = "71ae0fe9f6cf1fcc23a1936caa1dda070e724636dd7aaa54bee3b49eee4ac4ce" + PackageID = "d9549bb414afd4e4b42de8ff957bc311e6ed4268c83578427799e35e5654afa7" SDKVersion = "3.4.11" ) diff --git a/bindings/generated/latest/mcms/core/core.go b/bindings/generated/latest/mcms/core/core.go index 14be70a4a..fb94b01e4 100644 --- a/bindings/generated/latest/mcms/core/core.go +++ b/bindings/generated/latest/mcms/core/core.go @@ -24,7 +24,7 @@ var ( const ( PackageName = "mcms-core" - PackageID = "cff9a7b0d8113c42610d2cdf798139d3eabb32db348f7ef33e008a9f5d0d084d" + PackageID = "3b79485f0565363dd77fbb60c379a21fa978e1cbff8ed557ccb2927c4a522d40" SDKVersion = "3.4.11" ) diff --git a/bindings/generated/latest/mcms/mcmstest/mcmstest.go b/bindings/generated/latest/mcms/mcmstest/mcmstest.go index 0b9aa2b97..7edc2170e 100644 --- a/bindings/generated/latest/mcms/mcmstest/mcmstest.go +++ b/bindings/generated/latest/mcms/mcmstest/mcmstest.go @@ -24,7 +24,7 @@ var ( const ( PackageName = "mcms-test" - PackageID = "9f6fcbe125ec6bbf891f45f5bb037bacc675d5e9c052b808f7f6f3a7136be67b" + PackageID = "874107ad63170d12635237dbddb8b0134b508d42f8d2147b288fe481d3ff65cf" SDKVersion = "3.4.11" ) @@ -35,17 +35,17 @@ type Template interface { const ( TimelockTestInstanceAddress = types.TEXT("mcms-daml-test@ccip_owner-9cefe94d") - TimelockScheduleRoot = types.TEXT("a562ea5617f1ad48ba3712119a12ca1c2f7736e1f8f02d6c7c319653a8663cd4") + TimelockScheduleRoot = types.TEXT("5f9210fbbf1a2d964e0d8e3a4bff0fcc130bdbf37bd0ca79d4263f63c39dc5ba") TimelockBypasserRoot = types.TEXT("03d506aeaffd933a56d3572797fa69aa96db825fa7c1c0bdaefc22cc40c51df7") SelfDispatchTestBaseMcmsId = types.TEXT("mcms-daml-test") - OverrideRoot = types.TEXT("d618cc847a2ef8f4b445dd8328a05e64576d637d560f4d8caf2b34d34d8ff740") + OverrideRoot = types.TEXT("d8e975a710b09604fe755f601c04c95dbee76ebe2e0f3cb160809574be932a8a") RealTestRoot = types.TEXT("e5aeef059e7037a3b83c98b67797721c3e93c9ed1c91c2629d2302939177817f") RealTestMcmsId = types.TEXT("mcms-daml-test") RealTestInstanceId = types.TEXT("mcms-daml-test@ccip_owner-9cefe94d") RealTestChainId = types.INT64(1) ExternalTestBaseMcmsId = types.TEXT("mcms-daml-test") - ExternalScheduleSalt = types.TEXT("65787465726e616c2d73616c742d31") - ExternalScheduleRoot = types.TEXT("4f91344c80e695656fef97b4c58382b66ce1b984c3bcf7d94efcb0daafa4772c") + ExternalScheduleSalt = types.TEXT("000000000000000000000000000000000065787465726e616c2d73616c742d31") + ExternalScheduleRoot = types.TEXT("a5de111064a236613fc3434e6832f8bc0d0e12a912d412705bc1730cb72b108c") ExternalBypasserRoot = types.TEXT("7d70e8ba5c202e505d587e0e8a84580ed6aee6e1fa2e5bc2de64ca24994cf7e5") ) diff --git a/contracts/dars/current/ccip-burn-mint-token-pool-current.dar b/contracts/dars/current/ccip-burn-mint-token-pool-current.dar index 406a0a554..77dd6ba04 100644 Binary files a/contracts/dars/current/ccip-burn-mint-token-pool-current.dar and b/contracts/dars/current/ccip-burn-mint-token-pool-current.dar differ diff --git a/contracts/dars/current/ccip-committee-verifier-current.dar b/contracts/dars/current/ccip-committee-verifier-current.dar index 124326fb7..2775efe87 100644 Binary files a/contracts/dars/current/ccip-committee-verifier-current.dar and b/contracts/dars/current/ccip-committee-verifier-current.dar differ diff --git a/contracts/dars/current/ccip-core-current.dar b/contracts/dars/current/ccip-core-current.dar index f6ee0be32..14ef79c90 100644 Binary files a/contracts/dars/current/ccip-core-current.dar and b/contracts/dars/current/ccip-core-current.dar differ diff --git a/contracts/dars/current/ccip-executor-current.dar b/contracts/dars/current/ccip-executor-current.dar index 4cac3ad89..4d0d58bf3 100644 Binary files a/contracts/dars/current/ccip-executor-current.dar and b/contracts/dars/current/ccip-executor-current.dar differ diff --git a/contracts/dars/current/ccip-extension-api-current.dar b/contracts/dars/current/ccip-extension-api-current.dar index 7985e379b..f8754a4a2 100644 Binary files a/contracts/dars/current/ccip-extension-api-current.dar and b/contracts/dars/current/ccip-extension-api-current.dar differ diff --git a/contracts/dars/current/ccip-factory-current.dar b/contracts/dars/current/ccip-factory-current.dar index bd8098510..0d7683bfa 100644 Binary files a/contracts/dars/current/ccip-factory-current.dar and b/contracts/dars/current/ccip-factory-current.dar differ diff --git a/contracts/dars/current/ccip-lock-release-token-pool-current.dar b/contracts/dars/current/ccip-lock-release-token-pool-current.dar index c0b49c9d1..f9f39985d 100644 Binary files a/contracts/dars/current/ccip-lock-release-token-pool-current.dar and b/contracts/dars/current/ccip-lock-release-token-pool-current.dar differ diff --git a/contracts/dars/current/ccip-receiver-current.dar b/contracts/dars/current/ccip-receiver-current.dar index edb3b7ef3..2ca066bc5 100644 Binary files a/contracts/dars/current/ccip-receiver-current.dar and b/contracts/dars/current/ccip-receiver-current.dar differ diff --git a/contracts/dars/current/ccip-runtime-current.dar b/contracts/dars/current/ccip-runtime-current.dar index e6d148a02..727ee3fb8 100644 Binary files a/contracts/dars/current/ccip-runtime-current.dar and b/contracts/dars/current/ccip-runtime-current.dar differ diff --git a/contracts/dars/current/ccip-sender-current.dar b/contracts/dars/current/ccip-sender-current.dar index bf9d2a039..9f0066e84 100644 Binary files a/contracts/dars/current/ccip-sender-current.dar and b/contracts/dars/current/ccip-sender-current.dar differ diff --git a/contracts/dars/current/ccip-test-current.dar b/contracts/dars/current/ccip-test-current.dar index 11ccb11ae..5b59712a0 100644 Binary files a/contracts/dars/current/ccip-test-current.dar and b/contracts/dars/current/ccip-test-current.dar differ diff --git a/contracts/dars/current/globalconfig-current.dar b/contracts/dars/current/globalconfig-current.dar index 8a601879b..9ef419456 100644 Binary files a/contracts/dars/current/globalconfig-current.dar and b/contracts/dars/current/globalconfig-current.dar differ diff --git a/contracts/dars/current/mcms-api-current.dar b/contracts/dars/current/mcms-api-current.dar index 668dd2acf..4bcd168a1 100644 Binary files a/contracts/dars/current/mcms-api-current.dar and b/contracts/dars/current/mcms-api-current.dar differ diff --git a/contracts/dars/current/mcms-core-current.dar b/contracts/dars/current/mcms-core-current.dar index eee1527c6..ba85c5ee8 100644 Binary files a/contracts/dars/current/mcms-core-current.dar and b/contracts/dars/current/mcms-core-current.dar differ diff --git a/contracts/dars/current/mcms-test-current.dar b/contracts/dars/current/mcms-test-current.dar index fe3fa3afe..79600dd41 100644 Binary files a/contracts/dars/current/mcms-test-current.dar and b/contracts/dars/current/mcms-test-current.dar differ diff --git a/contracts/mcms/api/daml/MCMS/Crypto.daml b/contracts/mcms/api/daml/MCMS/Crypto.daml index 4099a89ea..94dcba6f1 100644 --- a/contracts/mcms/api/daml/MCMS/Crypto.daml +++ b/contracts/mcms/api/daml/MCMS/Crypto.daml @@ -171,8 +171,10 @@ hashMetadataLeafNative meta = -- TIMELOCK HASH FUNCTIONS -- =========================================================================== --- opId = keccak256(abi.encode(calls, predecessor, salt)) --- Uses length-prefixed encoding to prevent collision attacks +-- opId = keccak256(calls, predecessor, salt) +-- Every variable-length field is length-prefixed (not raw-concatenated), so the +-- encoding is injective and immune to predecessor/salt boundary-shift collisions. +-- predecessor and salt are additionally enforced to be 32 bytes at the call sites. hashTimelockOpId : [TimelockCall] -> BytesHex -> BytesHex -> BytesHex hashTimelockOpId calls predecessor salt = let @@ -226,6 +228,14 @@ assertValidHex fieldName hex = assertMsg (fieldName <> ": invalid hex (must be even-length, 0-9a-fA-F only): " <> hex) (isValidHex hex) +-- | Validate that a field is a well-formed 32-byte value (hex-encoded). +-- Used for timelock predecessor and salt +assertValidBytes32 : Text -> BytesHex -> Update () +assertValidBytes32 fieldName hex = do + assertValidHex fieldName hex + assertMsg ("mcms: " <> fieldName <> " must be 32 bytes, got " <> show (byteCount hex)) $ + byteCount hex == 32 + -- =========================================================================== -- MERKLE PROOF VERIFICATION -- =========================================================================== diff --git a/contracts/mcms/core/daml/MCMS/Main.daml b/contracts/mcms/core/daml/MCMS/Main.daml index 96bf94d63..b5ad7c197 100644 --- a/contracts/mcms/core/daml/MCMS/Main.daml +++ b/contracts/mcms/core/daml/MCMS/Main.daml @@ -363,8 +363,8 @@ template MCMS controller submitter do -- 0. Validate BytesHex inputs - assertValidHex "predecessor" predecessor - assertValidHex "salt" salt + assertValidBytes32 "predecessor" predecessor + assertValidBytes32 "salt" salt forA_ calls $ \call -> assertValidHex "call.operationData" call.operationData now <- getTime @@ -696,6 +696,8 @@ executeSelfDispatch mcms call = forA_ params.calls $ \c -> assertMsg ("mcms: function blocked: " <> c.targetInstanceAddress <> ":" <> c.functionName) $ BlockedFunction c.targetInstanceAddress c.functionName `notElem` mcms.blockedFunctions + assertValidBytes32 "predecessor" params.predecessor + assertValidBytes32 "salt" params.salt let opId = hashTimelockOpId params.calls params.predecessor params.salt assertMsg "mcms: operation already scheduled" $ not $ Map.member opId mcms.timelockTimestamps @@ -757,7 +759,9 @@ scheduleBatchInternal now mcms rs calls predecessor salt delay = do assertMsg ("mcms: function blocked: " <> call.targetInstanceAddress <> ":" <> call.functionName) $ BlockedFunction call.targetInstanceAddress call.functionName `notElem` mcms.blockedFunctions - -- 3. Compute opId + -- 3. Validate predecessor and salt are 32-byte values, then compute opId + assertValidBytes32 "predecessor" predecessor + assertValidBytes32 "salt" salt let opId = hashTimelockOpId calls predecessor salt -- 4. Check not already scheduled (on-chain duplicate prevention) diff --git a/contracts/mcms/test/daml/MCMS/ExternalTargetTest.daml b/contracts/mcms/test/daml/MCMS/ExternalTargetTest.daml index 5b9d2b834..90e1a7c9d 100644 --- a/contracts/mcms/test/daml/MCMS/ExternalTargetTest.daml +++ b/contracts/mcms/test/daml/MCMS/ExternalTargetTest.daml @@ -108,7 +108,7 @@ externalScheduleOp = Op , nonce = 0 , targetInstanceAddress = "mcms-daml-test@ccip_owner-9cefe94d" , functionName = "ScheduleBatch" - , operationData = "011b636f756e74657240636369705f6f776e65722d396365666539346409496e6372656d656e74000000200000000000000000000000000000000000000000000000000000000000000000000f65787465726e616c2d73616c742d310000000000000000" + , operationData = "011b636f756e74657240636369705f6f776e65722d396365666539346409496e6372656d656e740000002000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000065787465726e616c2d73616c742d310000000000000000" } externalScheduleMetadata : RootMetadata @@ -121,11 +121,11 @@ externalScheduleMetadata = RootMetadata } externalScheduleRoot : Text -externalScheduleRoot = "4f91344c80e695656fef97b4c58382b66ce1b984c3bcf7d94efcb0daafa4772c" +externalScheduleRoot = "a5de111064a236613fc3434e6832f8bc0d0e12a912d412705bc1730cb72b108c" externalScheduleMetadataProof : [Text] externalScheduleMetadataProof = - [ "e0a871ad97f2400815079772600b3e09b04d0487822918cf15db61344bc396f4" + [ "5ac687c6c469d00fca89f3a6b2909416ddd500456cff668dd94bca2d621a1ccf" ] externalScheduleOpProof : [Text] @@ -138,18 +138,18 @@ externalScheduleSignatures : [RawSignature] externalScheduleSignatures = [ RawSignature { publicKey = "04c170cfd2dfedf29d6dc68f57205d5b2a182dfbf0ae5fc4f6d9cb3382e6ab194e5e236469efad820ecceb3c474be2657747ea6d947fd79cb73f1834b45911cc2e" - , r = "12b1795146cdb8c6c2ddd50aff263094a206f589e6667e2f5ea2af34f194d505" - , s = "123ddca05b3ad0a94e1bbd48b9f6b801a18e9b5dd0788480af496d2c63cfc0a0" + , r = "365ad57001ca8a19812e13f58cf6dbdc48856860c6d4e18727e758d703179751" + , s = "24b35648bbb1917913b589a91317e44ebd61287156e815f4fb1de43e5e38358f" } , RawSignature { publicKey = "04be6d6382ad269cab52671739bb27d4b3ac087c46c7956324810dee6fa311ef8eb1065e376017fe4a8d3d5ee0e86f837f9bb69f22331c1828e5521765f2cdee31" - , r = "c8f3b29c9185437668a2cdca62792c7285caaec86e39f3edb8cd6b9beacdd4b8" - , s = "4d6fdde4f1d737a933dfe760d59a45d644633a4c7dc61ded9d4c1ecc2306e969" + , r = "cf4c3ae13e7d37a905b35519209b24e05cbf4ac8597f7b9f7fd18f6466ba2720" + , s = "227a13c64283758057023e7f3ed30a4518b818b4ebba224ceaf3373e8c9fc692" } ] externalScheduleSalt : Text -externalScheduleSalt = "65787465726e616c2d73616c742d31" +externalScheduleSalt = "000000000000000000000000000000000065787465726e616c2d73616c742d31" -- =========================================================================== -- BYPASSER EXTERNAL CALL TESTS diff --git a/contracts/mcms/test/daml/MCMS/SelfDispatchTest.daml b/contracts/mcms/test/daml/MCMS/SelfDispatchTest.daml index adf906d22..e8f01dc5f 100644 --- a/contracts/mcms/test/daml/MCMS/SelfDispatchTest.daml +++ b/contracts/mcms/test/daml/MCMS/SelfDispatchTest.daml @@ -57,7 +57,7 @@ timelockScheduleOp = Op , nonce = 0 , targetInstanceAddress = "mcms-daml-test@ccip_owner-9cefe94d" , functionName = "ScheduleBatch" - , operationData = "01226d636d732d64616d6c2d7465737440636369705f6f776e65722d39636566653934640e5570646174654d696e44656c61790008000000000000007800200000000000000000000000000000000000000000000000000000000000000000000f7363686564756c652d73616c742d310000000000000000" + , operationData = "01226d636d732d64616d6c2d7465737440636369705f6f776e65722d39636566653934640e5570646174654d696e44656c61790008000000000000007800200000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000007363686564756c652d73616c742d310000000000000000" } timelockScheduleMetadata : RootMetadata @@ -70,11 +70,11 @@ timelockScheduleMetadata = RootMetadata } timelockScheduleRoot : Text -timelockScheduleRoot = "a562ea5617f1ad48ba3712119a12ca1c2f7736e1f8f02d6c7c319653a8663cd4" +timelockScheduleRoot = "5f9210fbbf1a2d964e0d8e3a4bff0fcc130bdbf37bd0ca79d4263f63c39dc5ba" timelockScheduleMetadataProof : [Text] timelockScheduleMetadataProof = - [ "9fce2a24c2898f9f6fb40e8245499f27a7fb27bab0578f6b6e457914380892f2" + [ "d7f333356f4426a21fb297b549c8609e5302328e3e25e5341e9190951090a890" ] timelockScheduleOpProof : [Text] @@ -87,13 +87,13 @@ timelockScheduleSignatures : [RawSignature] timelockScheduleSignatures = [ RawSignature { publicKey = "04c170cfd2dfedf29d6dc68f57205d5b2a182dfbf0ae5fc4f6d9cb3382e6ab194e5e236469efad820ecceb3c474be2657747ea6d947fd79cb73f1834b45911cc2e" - , r = "26e6512066c4c6b84363361cb88cc047d626f64e6270b404c684adf6d9487ea5" - , s = "7d8033840acdafe09a0ac00f812c88e720ead553152c0de7eb7a91fdfd3f6ef4" + , r = "c65ffd768c7e4642cd867bd9f05aaf8306726083a2d338aebfbc166a9092a310" + , s = "2caef64e9fb5220afa321c5f57b25146f87fcf5ed288215ec4cc9524f803c2c0" } , RawSignature { publicKey = "04be6d6382ad269cab52671739bb27d4b3ac087c46c7956324810dee6fa311ef8eb1065e376017fe4a8d3d5ee0e86f837f9bb69f22331c1828e5521765f2cdee31" - , r = "1cd9f7e256b6ef69c680f7c2b600940fcb5f220086fa55f91b2a41daaffd8566" - , s = "70e4dc39e6a3babf0c9d8061a648d6c1976029bc843c64a329403ccef2dc01d9" + , r = "f79228a7fccc47080b58b6e3c2faf42c6d8b6f392ae21273cdad08b78e82cef7" + , s = "3e358590167ac58f94ecfcdca2bf5179a7e8ff1bffaccb68106e34ec269532c1" } ] @@ -151,10 +151,10 @@ timelockTestInstanceAddress = "mcms-daml-test@ccip_owner-9cefe94d" -- overridePreviousRoot=True vectors -- Generated by TestMCMS_GenerateDamlTestValues (seed 42001/42002/42003, preOpCount=0, postOpCount=1) overrideRoot : Text -overrideRoot = "d618cc847a2ef8f4b445dd8328a05e64576d637d560f4d8caf2b34d34d8ff740" +overrideRoot = "d8e975a710b09604fe755f601c04c95dbee76ebe2e0f3cb160809574be932a8a" overrideMetadataProof : [Text] -overrideMetadataProof = [ "9fce2a24c2898f9f6fb40e8245499f27a7fb27bab0578f6b6e457914380892f2" ] +overrideMetadataProof = [ "d7f333356f4426a21fb297b549c8609e5302328e3e25e5341e9190951090a890" ] overrideMetadata : RootMetadata overrideMetadata = RootMetadata @@ -169,13 +169,13 @@ overrideSignatures : [RawSignature] overrideSignatures = [ RawSignature { publicKey = "04c170cfd2dfedf29d6dc68f57205d5b2a182dfbf0ae5fc4f6d9cb3382e6ab194e5e236469efad820ecceb3c474be2657747ea6d947fd79cb73f1834b45911cc2e" - , r = "bb4de475a56f7cdfc316df1de1f52d0b01755edafb1e2a95b1fec336302a7744" - , s = "6d61628155c3d9c1a970e33e8a656ed6d8efb7b1778a4fcfc60dc36ea9198ce0" + , r = "b5b978abcfc30995c36e139957eed2af3315389c6915c7067b2761cac5b839b9" + , s = "68d5d4fe2b53a11be1b75154515b2386180bde056643287bc3d8b7c48557a6d1" } , RawSignature { publicKey = "04be6d6382ad269cab52671739bb27d4b3ac087c46c7956324810dee6fa311ef8eb1065e376017fe4a8d3d5ee0e86f837f9bb69f22331c1828e5521765f2cdee31" - , r = "7a40d7f6fb342efd040eba22ddc207d615d87e8a95aaedcc5ed182f732af0515" - , s = "0f02a6382d87679fcfa598022c92a0de736f6f08ad57a68426a4bea4d81b3f80" + , r = "5b5691b540f63e777c27e9c0b9af2415d3722b6e6451c6252b450a4c6a5e397f" + , s = "2893ed9f1b52af52fd8556141b21c7c461448f4c31a857208d153891bc17b775" } ] @@ -215,7 +215,7 @@ testScheduleBatch = script do -- ExecuteOp with ScheduleBatch let calls = [TimelockCall timelockTestInstanceAddress "UpdateMinDelay" "0000000000000078"] - let salt = "7363686564756c652d73616c742d31" + let salt = "00000000000000000000000000000000007363686564756c652d73616c742d31" mcmsCid <- submit ccipOwner do exerciseCmd mcmsCid ExecuteOp with targetRole = Proposer @@ -288,7 +288,7 @@ testExecuteScheduledBatchRejectsMissingOpId = script do functionName = "UpdateMinDelay" operationData = "0000000000000001"] predecessor = zeroHash - salt = "73616c74" + salt = "0000000000000000000000000000000000000000000000000000000073616c74" targetCids = Map.empty timestamp <- submit ccipOwner do @@ -298,6 +298,75 @@ testExecuteScheduledBatchRejectsMissingOpId = script do assertMsg "Missing operation should remain absent after failed execution" $ isNone timestamp +testExecuteScheduledBatchRejectsShortPredecessor : Script () +testExecuteScheduledBatchRejectsShortPredecessor = script do + ccipOwner <- allocatePartyByHint (PartyIdHint "ccip_owner-short-pred") + let instanceAddress = "mcms-short-pred@" <> partyToText ccipOwner + + mcmsCid <- submit ccipOwner do + createCmd MCMS with + owner = ccipOwner + instanceId = "mcms-short-pred" + chainId = 1 + proposer = emptyRoleState + canceller = emptyRoleState + bypasser = emptyRoleState + minDelay = seconds 0 + blockedFunctions = [] + timelockTimestamps = Map.empty + + let calls = [TimelockCall with + targetInstanceAddress = instanceAddress + functionName = "UpdateMinDelay" + operationData = "0000000000000001"] + let salt = "0000000000000000000000000000000000000000000000000000000073616c74" + + -- predecessor is 1 byte ("00") instead of the required 32 bytes. + -- assertValidBytes32 runs before the opId lookup, so this fails on the + -- length check regardless of timelock state. The valid 32-byte case is + -- covered by testScheduleBatch (predecessor = zeroHash succeeds). + submitMustFail ccipOwner do + exerciseCmd mcmsCid ExecuteScheduledBatch with + submitter = ccipOwner + opId = hashTimelockOpId calls "00" salt + calls + predecessor = "00" + salt + targetCids = Map.empty + +-- | Test ExecuteScheduledBatch rejects a salt that is not exactly 32 bytes. +testExecuteScheduledBatchRejectsShortSalt : Script () +testExecuteScheduledBatchRejectsShortSalt = script do + ccipOwner <- allocatePartyByHint (PartyIdHint "ccip_owner-short-salt") + let instanceAddress = "mcms-short-salt@" <> partyToText ccipOwner + + mcmsCid <- submit ccipOwner do + createCmd MCMS with + owner = ccipOwner + instanceId = "mcms-short-salt" + chainId = 1 + proposer = emptyRoleState + canceller = emptyRoleState + bypasser = emptyRoleState + minDelay = seconds 0 + blockedFunctions = [] + timelockTimestamps = Map.empty + + let calls = [TimelockCall with + targetInstanceAddress = instanceAddress + functionName = "UpdateMinDelay" + operationData = "0000000000000001"] + + -- predecessor is a valid 32-byte hash (zeroHash), but salt is 1 byte ("00"). + submitMustFail ccipOwner do + exerciseCmd mcmsCid ExecuteScheduledBatch with + submitter = ccipOwner + opId = hashTimelockOpId calls zeroHash "00" + calls + predecessor = zeroHash + salt = "00" + targetCids = Map.empty + -- | Test bypasser_execute_batch self-dispatch (immediate update_min_delay) -- Flow: Bypasser signs bypasser_execute_batch -> ExecuteOp (immediate execution) testBypasserExecuteBatch : Script () diff --git a/integration-tests/mcms/changeset_mcms_test.go b/integration-tests/mcms/changeset_mcms_test.go index c53d0d759..71ffca5d0 100644 --- a/integration-tests/mcms/changeset_mcms_test.go +++ b/integration-tests/mcms/changeset_mcms_test.go @@ -145,7 +145,8 @@ func TestMCMS_ChangesetProposalE2E(t *testing.T) { // ======================================================================== destChainSelector := "999" - testOffRampHex := "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef" + // 64 hex chars → 32 decoded bytes; addressBytesLength must match byteCount(offRampAddress). + testOffRampHex := "00000000000000000000000000000000000000000000000000000000deadbeef" t.Log("Generating MCMS proposal via ConfigureGlobalConfig changeset...") csOut, err := changesets.ConfigureGlobalConfig{}.Apply(*env, changesets.CantonCSDeps[changesets.ConfigureGlobalConfigConfig]{ @@ -157,7 +158,7 @@ func TestMCMS_ChangesetProposalE2E(t *testing.T) { DestChainUpdates: []common.DestChainConfigArgs{{ DestChainSelector: types.NUMERIC(destChainSelector), IsEnabled: true, - AddressBytesLength: 20, + AddressBytesLength: 32, TokenReceiverAllowed: true, BaseExecutionGasCost: 21000, OffRampAddress: types.TEXT(testOffRampHex), @@ -317,7 +318,7 @@ func TestMCMS_ChangesetProposalE2E(t *testing.T) { case "isEnabled": assert.True(t, f.GetValue().GetBool(), "isEnabled") case "addressBytesLength": - assert.Equal(t, int64(20), f.GetValue().GetInt64(), "addressBytesLength") + assert.Equal(t, int64(32), f.GetValue().GetInt64(), "addressBytesLength") case "tokenReceiverAllowed": assert.True(t, f.GetValue().GetBool(), "tokenReceiverAllowed") case "baseExecutionGasCost": diff --git a/integration-tests/mcms/mcms_integration_test.go b/integration-tests/mcms/mcms_integration_test.go index 868617051..30b49353b 100644 --- a/integration-tests/mcms/mcms_integration_test.go +++ b/integration-tests/mcms/mcms_integration_test.go @@ -1554,9 +1554,9 @@ func TestMCMS_GenerateDamlTestValues(t *testing.T) { } scheduleParams := mcms.ScheduleBatchParams{ Calls: scheduleInnerCalls, - Predecessor: types.TEXT(ZeroHash), // no predecessor - Salt: types.TEXT(TextToHex("schedule-salt-1")), // Human-readable salt hex-encoded - DelaySecs: types.INT64(0), // use minimum delay + Predecessor: types.TEXT(ZeroHash), // no predecessor + Salt: types.TEXT(PadLeft32(TextToHex("schedule-salt-1"))), // 32-byte salt + DelaySecs: types.INT64(0), // use minimum delay } scheduleChoice := MustEncodeScheduleBatch(t, mcmsEncoder, scheduleParams) @@ -1931,7 +1931,7 @@ func TestMCMS_GenerateDamlTestValues(t *testing.T) { externalScheduleParams := mcms.ScheduleBatchParams{ Calls: externalScheduleCalls, Predecessor: types.TEXT(ZeroHash), - Salt: types.TEXT(TextToHex("external-salt-1")), // Human-readable salt hex-encoded + Salt: types.TEXT(PadLeft32(TextToHex("external-salt-1"))), // 32-byte salt DelaySecs: types.INT64(0), } externalScheduleChoice := MustEncodeScheduleBatch(t, mcmsEncoder, externalScheduleParams) diff --git a/integration-tests/mcms/mcms_timelock_test.go b/integration-tests/mcms/mcms_timelock_test.go index bc3a14d9c..f08ee54af 100644 --- a/integration-tests/mcms/mcms_timelock_test.go +++ b/integration-tests/mcms/mcms_timelock_test.go @@ -53,7 +53,7 @@ func TestMCMS_Timelock(t *testing.T) { FunctionName: types.TEXT("Increment"), OperationData: types.TEXT(""), }} - salt := uuid.New().String()[:8] + salt := PadLeft32(uuid.New().String()[:8]) // 32-byte salt delaySecs := 0 // Encode schedule params using encoder pattern (gets choice name + operation data) @@ -107,7 +107,7 @@ func TestMCMS_Timelock(t *testing.T) { FunctionName: types.TEXT("Increment"), OperationData: types.TEXT(""), }} - salt := uuid.New().String()[:8] + salt := PadLeft32(uuid.New().String()[:8]) // 32-byte salt opID := HashTimelockOpId(UnwrapTimelockCalls(calls), ZeroHash, salt) // Encode schedule params using encoder pattern @@ -171,7 +171,7 @@ func TestMCMS_Timelock(t *testing.T) { FunctionName: types.TEXT("dangerous_function"), OperationData: types.TEXT(""), }} - salt := uuid.New().String()[:8] + salt := PadLeft32(uuid.New().String()[:8]) // 32-byte salt delaySecs := 1 // Encode schedule params using encoder pattern @@ -955,7 +955,7 @@ func TestMCMS_SelfDispatch(t *testing.T) { FunctionName: types.TEXT("UpdateMinDelay"), OperationData: types.TEXT(EncodeMinDelay(1)), // 1 second }} - salt := uuid.New().String()[:8] + salt := PadLeft32(uuid.New().String()[:8]) // 32-byte salt delaySecs := 1 // Encode schedule params using encoder pattern @@ -1008,7 +1008,7 @@ func TestMCMS_SelfDispatch(t *testing.T) { FunctionName: types.TEXT("BlockFunction"), OperationData: types.TEXT(MustEncodeBlockedFunction(t, bf)), }} - salt := uuid.New().String()[:8] + salt := PadLeft32(uuid.New().String()[:8]) // 32-byte salt delaySecs := 1 // Encode schedule params using encoder pattern @@ -1095,7 +1095,7 @@ func TestMCMS_SelfDispatch(t *testing.T) { {TargetInstanceAddress: types.TEXT(mcmsInstanceAddr), FunctionName: types.TEXT("UpdateMinDelay"), OperationData: types.TEXT(EncodeMinDelay(1))}, {TargetInstanceAddress: types.TEXT(counterTargetInstanceAddr), FunctionName: types.TEXT("Increment"), OperationData: types.TEXT("")}, } - salt := uuid.New().String()[:8] + salt := PadLeft32(uuid.New().String()[:8]) // 32-byte salt delaySecs := 0 // Encode schedule params using encoder pattern diff --git a/integration-tests/mcms/token_admin_registry_mcms_test.go b/integration-tests/mcms/token_admin_registry_mcms_test.go index df0cc9891..dce713edc 100644 --- a/integration-tests/mcms/token_admin_registry_mcms_test.go +++ b/integration-tests/mcms/token_admin_registry_mcms_test.go @@ -82,7 +82,7 @@ func TestSetPoolViaMCMS(t *testing.T) { FunctionName: types.TEXT("SetPool"), OperationData: types.TEXT(setPoolData), }} - salt := uuid.New().String()[:8] + salt := PadLeft32(uuid.New().String()[:8]) // 32-byte salt // Encode schedule params scheduleParams := mcms.ScheduleBatchParams{ @@ -187,7 +187,7 @@ func TestTokenAdminRegistry_ClearPoolViaMCMS(t *testing.T) { FunctionName: types.TEXT("SetPool"), OperationData: types.TEXT(clearPoolData), }} - salt := uuid.New().String()[:8] + salt := PadLeft32(uuid.New().String()[:8]) // 32-byte salt scheduleParams := mcms.ScheduleBatchParams{ Calls: calls, @@ -271,7 +271,7 @@ func TestTokenAdminRegistry_ProposeAdminViaMCMS(t *testing.T) { FunctionName: types.TEXT("ProposeAdministrator"), OperationData: types.TEXT(proposeData), }} - salt := uuid.New().String()[:8] + salt := PadLeft32(uuid.New().String()[:8]) // 32-byte salt scheduleParams := mcms.ScheduleBatchParams{ Calls: calls,