diff --git a/.gitignore b/.gitignore index ee1c88c5..86c4727c 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,5 @@ testScript.sh CLAUDE.md .idea/ + +hardhat-scripts/loadTest/* \ No newline at end of file diff --git a/Errors.md b/Errors.md index ae06096c..2acd69a3 100644 --- a/Errors.md +++ b/Errors.md @@ -173,3 +173,6 @@ | `InvalidData()` | `0x5cb045db` | | `InvalidSignature()` | `0x8baa579f` | | `DeadlinePassed()` | `0x70f65caa` | +| `OnlyRequestHandlerAllowed()` | `0x5c1aa683` | +| `OnlyPromiseResolverAllowed()` | `0x2392c25e` | +| `InvalidReceiver()` | `0x1e4ec46b` | diff --git a/EventTopics.md b/EventTopics.md index 0a408806..9c39c004 100644 --- a/EventTopics.md +++ b/EventTopics.md @@ -24,6 +24,8 @@ | `AppGatewayCallRequested` | `(triggerId: bytes32, appGatewayId: bytes32, switchboardId: uint64, plug: bytes32, overrides: bytes, payload: bytes)` | `0x8ff0599581fd62c5733e52cea3abd7874731f4a9f86ebb929e5e4afe103f74d4` | | `ExecutionFailed` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x385334bc68a32c4d164625189adc7633e6074eb1b837fb4d11d768245151e4ce` | | `ExecutionSuccess` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x324d63a433b21a12b90e79cd2ba736b2a5238be6165e03b750fa4a7d5193d5d9` | +| `GasLimitBufferUpdated` | `(gasLimitBuffer: uint256)` | `0xd0e3eb5d0d212f0a08af2be98373721fc901ed26fbac645e08bd664fef818366` | +| `MaxCopyBytesUpdated` | `(maxCopyBytes: uint16)` | `0x294d0c11af52572317e5a0e1362cbf85b3b7c1f7b3f6c7b7e3e5c29c76da33e2` | | `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | | `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | | `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | @@ -64,8 +66,8 @@ | Event | Arguments | Topic | | ----------------------------- | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `Approval` | `(owner: address, spender: address, amount: uint256)` | `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925` | | `CreditsBlocked` | `(requestCount: uint40, consumeFrom: address, amount: uint256)` | `0xf037c15aef41440aa823cf1fdeaea332105d8b23d52557f6670189b5d76f1eed` | -| `CreditsTransferred` | `(from: address, to: address, amount: uint256)` | `0xed198cadddd93e734cbf04cb1c3226d9bafaeb504cedbd8ee36b830b0cb9e7a5` | | `CreditsUnblocked` | `(requestCount: uint40, consumeFrom: address)` | `0x45db29ef2701319155cac058aa2f56ce1f73e0e238161d3db9f8c9a47655210d` | | `CreditsUnblockedAndAssigned` | `(requestCount: uint40, consumeFrom: address, transmitter: address, amount: uint256)` | `0x38fd327622576a468e1b2818b00f50c8854703633ef8e583e1f31662888ffac2` | | `CreditsUnwrapped` | `(consumeFrom: address, amount: uint256)` | `0xdcc9473b722b4c953617ab373840b365298a520bc7f20ce94fa7314f4a857774` | @@ -74,9 +76,13 @@ | `FeesPlugSet` | `(chainSlug: uint32, feesPlug: bytes32)` | `0x677a00737c8099aa9e6c554104ca7941deb59125335cfb3d0d9f604f178db59c` | | `FeesPoolSet` | `(feesPool: address)` | `0xd07af3fd70b48ab3c077a8d45c3a288498d905d0e3d1e65bc171f6c2e890d8ef` | | `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `MaxFeesPerChainSlugSet` | `(chainSlug: uint32, fees: uint256)` | `0x555c0e83b1803127d009074a9b66632defb06a95449961404b3d454d6181b137` | | `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | | `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | | `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `SusdcTokenSet` | `(chainSlug: uint32, susdcToken: bytes32)` | `0xa268c0ce0f78082ba676c10a8a79a2785e196d85b3e883f8368f663536189525` | +| `Transfer` | `(from: address, to: address, amount: uint256)` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | +| `WhitelistedReceiverSet` | `(receiver: address, isWhitelisted: bool)` | `0x1fc608eb6791d1ef5d49904b6fc17867efb0319743013f69d29403e20741e53b` | | `WithdrawFailed` | `(payloadId: bytes32)` | `0xea147eb2109f71b4bda9e57528ba08b84821087a31cb43a7851dc6ff743d9be7` | ## FeesPool @@ -168,25 +174,40 @@ ## FeesPlug -| Event | Arguments | Topic | -| ---------------------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | -| `FeesDeposited` | `(token: address, receiver: address, creditAmount: uint256, nativeAmount: uint256)` | `0xeb4e1b24b7fe377de69f80f7380bda5ba4b43176c6a4d300a3be9009c49f4228` | -| `FeesWithdrawn` | `(token: address, receiver: address, amount: uint256)` | `0x5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa8` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -| `TokenRemovedFromWhitelist` | `(token: address)` | `0xdd2e6d9f52cbe8f695939d018b7d4a216dc613a669876163ac548b916489d917` | -| `TokenWhitelisted` | `(token: address)` | `0x6a65f90b1a644d2faac467a21e07e50e3f8fa5846e26231d30ae79a417d3d262` | +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- | +| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | +| `FeesDeposited` | `(token: address, receiver: address, creditAmount: uint256, nativeAmount: uint256, data: bytes)` | `0x91f985f17a8632ae2e0a009d65ae250f373d82359d2389b58ea50ada6436682a` | +| `FeesWithdrawn` | `(token: address, receiver: address, amount: uint256)` | `0x5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa8` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `TokenRemovedFromWhitelist` | `(token: address)` | `0xdd2e6d9f52cbe8f695939d018b7d4a216dc613a669876163ac548b916489d917` | +| `TokenWhitelisted` | `(token: address)` | `0x6a65f90b1a644d2faac467a21e07e50e3f8fa5846e26231d30ae79a417d3d262` | + +## SUSDC + +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------- | +| `Approval` | `(owner: address, spender: address, amount: uint256)` | `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925` | +| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `TokensBurned` | `(from: address, to: address, amount: uint256, data: bytes)` | `0x568ab03f32147bb501e2805da5910cb00bfca97231507d615ce5326dcf93eae6` | +| `TokensMinted` | `(to: address, amount: uint256)` | `0x3f2c9d57c068687834f0de942a9babb9e5acab57d516d3480a3c16ee165a4273` | +| `Transfer` | `(from: address, to: address, amount: uint256)` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | ## Configurations | Event | Arguments | Topic | | ---------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------- | | `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `IsValidPlugSet` | `(appGateway: address, chainSlug: uint32, plug: bytes32, isValid: bool)` | `0xd7a90efd60960a8435ef282822190655f6bd2ffa14bb350dc23d6f6956056d7e` | +| `IsValidPlugSet` | `(isValid: bool, chainSlug: uint32, plug: bytes32, appGateway: address)` | `0xdd99f9f3d0179d3845b6c9b5e020d80c32ca46007e43c43c6ab6a86cb259ed28` | | `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | | `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | | `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | @@ -204,31 +225,34 @@ ## RequestHandler -| Event | Arguments | Topic | -| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `FeesIncreased` | `(requestCount: uint40, newMaxFees: uint256)` | `0xf258fca4e49b803ee2a4c2e33b6fcf18bc3982df21f111c00677025bf1ccbb6a` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RequestCancelled` | `(requestCount: uint40)` | `0xff191657769be72fc08def44c645014c60d18cb24b9ca05c9a33406a28253245` | -| `RequestCompletedWithErrors` | `(requestCount: uint40)` | `0xd8d9915dc14b5a29b66cb263e1ea1e99e60418fc21d97f0fbf09cae1281291e2` | -| `RequestSettled` | `(requestCount: uint40, winner: address)` | `0x1234f98acbe1548b214f4528461a5377f1e2349569c04caa59325e488e7d2aa4` | -| `RequestSubmitted` | `(hasWrite: bool, requestCount: uint40, totalEstimatedWatcherFees: uint256, requestParams: tuple, payloadParamsArray: tuple[])` | `0xb730ca5523e3f80e88b4bb71e1e78d447553069cd9a7143bb0032b957135b530` | +| Event | Arguments | Topic | +| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `FeesIncreased` | `(requestCount: uint40, newMaxFees: uint256)` | `0xf258fca4e49b803ee2a4c2e33b6fcf18bc3982df21f111c00677025bf1ccbb6a` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PrecompileSet` | `(callType: bytes4, precompile: address)` | `0x5254189aca1b416c09dad7fb656bf0ed2c07e03ccd240bd95dfbfbaeb5e10e7b` | +| `RequestCancelled` | `(requestCount: uint40)` | `0xff191657769be72fc08def44c645014c60d18cb24b9ca05c9a33406a28253245` | +| `RequestCompletedWithErrors` | `(requestCount: uint40)` | `0xd8d9915dc14b5a29b66cb263e1ea1e99e60418fc21d97f0fbf09cae1281291e2` | +| `RequestPayloadCountLimitSet` | `(requestPayloadCountLimit: uint128)` | `0x67f58095e99ad7f9519f3b80372f6bab373a6217d08c9479fe58b80dcd5b4b7d` | +| `RequestSettled` | `(requestCount: uint40, winner: address)` | `0x1234f98acbe1548b214f4528461a5377f1e2349569c04caa59325e488e7d2aa4` | +| `RequestSubmitted` | `(hasWrite: bool, requestCount: uint40, totalEstimatedWatcherFees: uint256, requestParams: tuple, payloadParamsArray: tuple[])` | `0xb730ca5523e3f80e88b4bb71e1e78d447553069cd9a7143bb0032b957135b530` | ## Watcher -| Event | Arguments | Topic | -| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | -| `AppGatewayCallFailed` | `(triggerId: bytes32)` | `0xcaf8475fdade8465ea31672463949e6cf1797fdcdd11eeddbbaf857e1e5907b7` | -| `CalledAppGateway` | `(triggerId: bytes32)` | `0xf659ffb3875368f54fb4ab8f5412ac4518af79701a48076f7a58d4448e4bdd0b` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `TriggerFailed` | `(triggerId: bytes32)` | `0x4386783bb0f7cad4ba12f033dbec03dc3441e7757a122f3097a7a4d945c98040` | -| `TriggerFeesSet` | `(triggerFees: uint256)` | `0x7df3967b7c8727af5ac0ee9825d88aafeb899d769bc428b91f8967fa0b623084` | -| `TriggerSucceeded` | `(triggerId: bytes32)` | `0x92d20fbcbf31370b8218e10ed00c5aad0e689022da30a08905ba5ced053219eb` | +| Event | Arguments | Topic | +| ---------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `AppGatewayCallFailed` | `(triggerId: bytes32)` | `0xcaf8475fdade8465ea31672463949e6cf1797fdcdd11eeddbbaf857e1e5907b7` | +| `CalledAppGateway` | `(triggerId: bytes32)` | `0xf659ffb3875368f54fb4ab8f5412ac4518af79701a48076f7a58d4448e4bdd0b` | +| `CoreContractsSet` | `(requestHandler: address, configManager: address, promiseResolver: address)` | `0x32f3480588270473dc6418270d922a820dd9e914739e09a98241457dca2fd560` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `TriggerFailed` | `(triggerId: bytes32)` | `0x4386783bb0f7cad4ba12f033dbec03dc3441e7757a122f3097a7a4d945c98040` | +| `TriggerFeesSet` | `(triggerFees: uint256)` | `0x7df3967b7c8727af5ac0ee9825d88aafeb899d769bc428b91f8967fa0b623084` | +| `TriggerSucceeded` | `(triggerId: bytes32)` | `0x92d20fbcbf31370b8218e10ed00c5aad0e689022da30a08905ba5ced053219eb` | ## IMessageSwitchboard @@ -287,14 +311,14 @@ ## SchedulePrecompile -| Event | Arguments | Topic | -| ------------------------------ | ---------------------------------------------------------------- | -------------------------------------------------------------------- | -| `ExpiryTimeSet` | `(expiryTime_: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | -| `MaxScheduleDelayInSecondsSet` | `(maxScheduleDelayInSeconds_: uint256)` | `0xfd5e4f0e96753ffb08a583390c2f151c51001d8e560625ab93b7fa7b4dac6d75` | -| `ScheduleCallbackFeesSet` | `(scheduleCallbackFees_: uint256)` | `0x82a2f41efc81ce7bfabc0affda7354dae42a3d09bd74a6196e8904b223138a52` | -| `ScheduleFeesPerSecondSet` | `(scheduleFeesPerSecond_: uint256)` | `0x7901a21229f6d2543d8676f53e21214d15f42513e7d46e0dcb510357222bdc7c` | -| `ScheduleRequested` | `(payloadId: bytes32, executeAfter: uint256, deadline: uint256)` | `0xd099d3e3d0f0e2c9c40e0066affeea125aab71d763b7ab0a279ccec3dff70b64` | -| `ScheduleResolved` | `(payloadId: bytes32)` | `0x925dc6c3ebffa07cac89d6e9675f1a5d04e045f2ed9a4fa442665935cb73e26b` | +| Event | Arguments | Topic | +| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `ExpiryTimeSet` | `(expiryTime_: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `MaxScheduleDelayInSecondsSet` | `(maxScheduleDelayInSeconds_: uint256)` | `0xfd5e4f0e96753ffb08a583390c2f151c51001d8e560625ab93b7fa7b4dac6d75` | +| `ScheduleCallbackFeesSet` | `(scheduleCallbackFees_: uint256)` | `0x82a2f41efc81ce7bfabc0affda7354dae42a3d09bd74a6196e8904b223138a52` | +| `ScheduleFeesPerSecondSet` | `(scheduleFeesPerSecond_: uint256)` | `0x7901a21229f6d2543d8676f53e21214d15f42513e7d46e0dcb510357222bdc7c` | +| `ScheduleRequested` | `(payloadId: bytes32, executeAfter: uint256, deadline: uint256, localInvoker: address, callbackSelector: bytes4, callbackData: bytes)` | `0xbeceaccdb128631e58b881241d4fb46e53d8b2b2aa3f1ce77ba6fb80af038e30` | +| `ScheduleResolved` | `(payloadId: bytes32)` | `0x925dc6c3ebffa07cac89d6e9675f1a5d04e045f2ed9a4fa442665935cb73e26b` | ## WritePrecompile diff --git a/FunctionSignatures.md b/FunctionSignatures.md index fc6866b7..be7db21c 100644 --- a/FunctionSignatures.md +++ b/FunctionSignatures.md @@ -16,9 +16,9 @@ | `consumeFrom` | `0x40dd78be` | | `creationCodeWithArgs` | `0xc126dcc4` | | `deployForwarder__` | `0xd4e3b034` | -| `endAuction` | `0x1212e653` | +| `endAuction` | `0x7426f0f6` | | `evmxSlug` | `0x8bae77c2` | -| `expireBid` | `0x1dd5022c` | +| `expireBid` | `0x33b5b234` | | `feesManager__` | `0x70568b58` | | `forwarderAddresses` | `0x5390fdcb` | | `getOnChainAddress` | `0xb6abffd7` | @@ -113,62 +113,62 @@ ## FeesManager -| Function | Signature | -| -------------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `approveAppGateway` | `0xa3b53d8b` | -| `approveAppGatewayWithSignature` | `0x94b649ec` | -| `approveAppGateways` | `0x86d23ab2` | -| `asyncDeployer__` | `0x2a39e801` | -| `auctionManager` | `0xb0192f9a` | -| `blockCredits` | `0x9e434307` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `consumeFrom` | `0x40dd78be` | -| `creationCodeWithArgs` | `0xc126dcc4` | -| `deployForwarder__` | `0xd4e3b034` | -| `deposit` | `0x5671d329` | -| `deprecatedSbType` | `0x5a783900` | -| `evmxSlug` | `0x8bae77c2` | -| `feesManager__` | `0x70568b58` | -| `feesPlugs` | `0x23f5ee8a` | -| `feesPool` | `0x6b259690` | -| `forwarderAddresses` | `0x5390fdcb` | -| `getAvailableCredits` | `0xb065a8e5` | -| `getOnChainAddress` | `0xb6abffd7` | -| `getOverrideParams` | `0x54f0a866` | -| `handleRevert` | `0x44792f25` | -| `initialize` | `0xbf2c8539` | -| `initializeOnChain` | `0x86f01739` | -| `isApproved` | `0xa389783e` | -| `isAsyncModifierSet` | `0xb69e0c4a` | -| `isCreditSpendable` | `0x4f8990fd` | -| `isNonceUsed` | `0xcab7e8eb` | -| `isValidPromise` | `0xb690b962` | -| `maxFees` | `0xe83e34b1` | -| `onCompleteData` | `0xb52fa926` | -| `onDeployComplete` | `0xfa3dbd1e` | -| `overrideParams` | `0xec5490fe` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestBlockedCredits` | `0xb62d25ac` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `sbType` | `0x745de344` | -| `setAddress` | `0x85bf312c` | -| `setFeesPlug` | `0xd6a9a8b7` | -| `setFeesPool` | `0xd6684588` | -| `tokenOnChainBalances` | `0x3b27866d` | -| `transferCredits` | `0xf1686c89` | -| `transferOwnership` | `0xf2fde38b` | -| `unblockAndAssignCredits` | `0x01958181` | -| `unblockCredits` | `0xa0b32314` | -| `unwrap` | `0x7647691d` | -| `userCredits` | `0x20babb92` | -| `watcher__` | `0x300bb063` | -| `withdrawCredits` | `0xcfc6dbd9` | -| `wrap` | `0x023276f0` | +| Function | Signature | +| ---------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `approve` | `0xa3b53d8b` | +| `approveWithSignature` | `0x94b649ec` | +| `approveAppGateways` | `0x86d23ab2` | +| `asyncDeployer__` | `0x2a39e801` | +| `auctionManager` | `0xb0192f9a` | +| `blockCredits` | `0x9e434307` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `consumeFrom` | `0x40dd78be` | +| `creationCodeWithArgs` | `0xc126dcc4` | +| `deployForwarder__` | `0xd4e3b034` | +| `deposit` | `0x5671d329` | +| `deprecatedSbType` | `0x5a783900` | +| `evmxSlug` | `0x8bae77c2` | +| `feesManager__` | `0x70568b58` | +| `feesPlugs` | `0x23f5ee8a` | +| `feesPool` | `0x6b259690` | +| `forwarderAddresses` | `0x5390fdcb` | +| `balanceOf` | `0xb065a8e5` | +| `getOnChainAddress` | `0xb6abffd7` | +| `getOverrideParams` | `0x54f0a866` | +| `handleRevert` | `0x44792f25` | +| `initialize` | `0xbf2c8539` | +| `initializeOnChain` | `0x86f01739` | +| `isApproved` | `0xa389783e` | +| `isAsyncModifierSet` | `0xb69e0c4a` | +| `isCreditSpendable` | `0x4f8990fd` | +| `isNonceUsed` | `0xcab7e8eb` | +| `isValidPromise` | `0xb690b962` | +| `maxFees` | `0xe83e34b1` | +| `onCompleteData` | `0xb52fa926` | +| `onDeployComplete` | `0xfa3dbd1e` | +| `overrideParams` | `0xec5490fe` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestBlockedCredits` | `0xb62d25ac` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `sbType` | `0x745de344` | +| `setAddress` | `0x85bf312c` | +| `setFeesPlug` | `0xd6a9a8b7` | +| `setFeesPool` | `0xd6684588` | +| `tokenOnChainBalances` | `0x3b27866d` | +| `transferFrom` | `0xf1686c89` | +| `transferOwnership` | `0xf2fde38b` | +| `unblockAndAssignCredits` | `0x01958181` | +| `unblockCredits` | `0xa0b32314` | +| `unwrap` | `0x7647691d` | +| `userCredits` | `0x20babb92` | +| `watcher__` | `0x300bb063` | +| `withdrawCredits` | `0xcfc6dbd9` | +| `wrap` | `0x023276f0` | ## FeesPool diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index 1c4b0a9f..2694b821 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -5,7 +5,6 @@ import {ECDSA} from "solady/utils/ECDSA.sol"; import "solady/utils/Initializable.sol"; import "./interfaces/IPromise.sol"; import "./interfaces/IAuctionManager.sol"; - import "../utils/AccessControl.sol"; import "../utils/RescueFundsLib.sol"; import {AuctionNotOpen, AuctionClosed, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter, MaxReAuctionCountReached, InvalidBid} from "../utils/common/Errors.sol"; @@ -13,6 +12,7 @@ import {SCHEDULE} from "../utils/common/Constants.sol"; import {TRANSMITTER_ROLE} from "../utils/common/AccessRoles.sol"; import {AppGatewayBase} from "./base/AppGatewayBase.sol"; +import "./interfaces/IERC20.sol"; /// @title AuctionManagerStorage /// @notice Storage for the AuctionManager contract @@ -169,8 +169,10 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AppGatewayBase, } /// @notice Ends an auction - /// @param requestCount_ The ID of the auction - function endAuction(uint40 requestCount_) external override onlyPromises { + /// @param data The encoded request count + function endAuction(bytes memory data, bytes memory) external onlyPromises { + uint40 requestCount_ = abi.decode(data, (uint40)); + if (requestCount_ == 0) revert InvalidBid(); if ( auctionStatus[requestCount_] == AuctionStatus.CLOSED || auctionStatus[requestCount_] == AuctionStatus.NOT_STARTED @@ -207,10 +209,11 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AppGatewayBase, /// @notice Expires a bid and restarts an auction in case a request is not fully executed. /// @dev Auction can be restarted only for `maxReAuctionCount` times. /// @dev It also unblocks the fees from last transmitter to be assigned to the new winner. - /// @param requestCount_ The request id - function expireBid(uint40 requestCount_) external override onlyPromises { - if (reAuctionCount[requestCount_] >= maxReAuctionCount) revert MaxReAuctionCountReached(); - RequestParams memory requestParams = watcher__().getRequestParams(requestCount_); + /// @param data The encoded request count + function expireBid(bytes memory data, bytes memory) external override onlyPromises { + uint40 requestCount = abi.decode(data, (uint40)); + if (reAuctionCount[requestCount] >= maxReAuctionCount) revert MaxReAuctionCountReached(); + RequestParams memory requestParams = watcher__().getRequestParams(requestCount); // if executed or cancelled, bid is not expired if ( @@ -218,15 +221,15 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AppGatewayBase, requestParams.requestTrackingParams.isRequestCancelled ) return; - delete winningBids[requestCount_]; - auctionStatus[requestCount_] = AuctionStatus.RESTARTED; - reAuctionCount[requestCount_]++; + delete winningBids[requestCount]; + auctionStatus[requestCount] = AuctionStatus.RESTARTED; + reAuctionCount[requestCount]++; watcher__().requestHandler__().assignTransmitter( - requestCount_, + requestCount, Bid({fee: 0, transmitter: address(0), extraData: ""}) ); - emit AuctionRestarted(requestCount_); + emit AuctionRestarted(requestCount); } function _createRequest( @@ -260,7 +263,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AppGatewayBase, uint256 delayInSeconds_ ) internal returns (uint256 watcherFees) { watcherFees = watcher__().getPrecompileFees(SCHEDULE, abi.encode(delayInSeconds_)); - feesManager__().transferCredits(from_, to_, watcherFees); + IERC20(address(feesManager__())).transferFrom(from_, to_, watcherFees); } /// @notice Recovers the signer of a message diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 58c78652..2a931237 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -228,7 +228,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { function _approveFeesWithSignature(bytes memory feesApprovalData_) internal { if (feesApprovalData_.length == 0) return; - (consumeFrom, , ) = feesManager__().approveAppGatewayWithSignature(feesApprovalData_); + (consumeFrom, , ) = feesManager__().approveWithSignature(feesApprovalData_); } /// @notice Withdraws fee tokens @@ -242,7 +242,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { uint256 amount_, address receiver_ ) internal { - feesManager__().approveAppGateway(address(feesManager__()), true); + feesManager__().approve(address(feesManager__()), true); feesManager__().withdrawCredits(chainSlug_, token_, amount_, maxFees, receiver_); } diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index fd001d24..c9234141 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -5,18 +5,24 @@ import "solady/utils/Initializable.sol"; import "solady/utils/ECDSA.sol"; import "solady/utils/SafeTransferLib.sol"; import "solady/auth/Ownable.sol"; +import "solady/tokens/ERC20.sol"; import "../interfaces/IFeesManager.sol"; import "../interfaces/IFeesPlug.sol"; import "../interfaces/IFeesPool.sol"; +import "../interfaces/IReceiver.sol"; import {AddressResolverUtil} from "../helpers/AddressResolverUtil.sol"; -import {NonceUsed, InvalidAmount, InsufficientCreditsAvailable, InsufficientBalance, InvalidChainSlug, NotRequestHandler} from "../../utils/common/Errors.sol"; +import {NonceUsed, InvalidAmount, InsufficientCreditsAvailable, InsufficientBalance, InvalidChainSlug, NotRequestHandler, InvalidReceiver} from "../../utils/common/Errors.sol"; import {WRITE} from "../../utils/common/Constants.sol"; import "../../utils/RescueFundsLib.sol"; import "../base/AppGatewayBase.sol"; import {toBytes32Format} from "../../utils/common/Converters.sol"; +interface ISUSDCPlug { + function mint(address receiver_, uint256 amount_) external; +} + abstract contract FeesManagerStorage is IFeesManager { // slots [0-49] reserved for gap uint256[50] _gap_before; @@ -32,8 +38,9 @@ abstract contract FeesManagerStorage is IFeesManager { bytes32 public deprecatedSbType; // slot 52 - /// @notice user credits => stores fees for user, app gateway, transmitters and watcher precompile - mapping(address => UserCredits) public userCredits; + /// @notice Mapping to track blocked credits for each user + /// @dev address => userBlockedCredits + mapping(address => uint256) public userBlockedCredits; // slot 53 /// @notice Mapping to track request credits details for each request count @@ -41,9 +48,7 @@ abstract contract FeesManagerStorage is IFeesManager { mapping(uint40 => uint256) public requestBlockedCredits; // slot 54 - // user approved app gateways - // userAddress => appGateway => isApproved - mapping(address => mapping(address => bool)) public isApproved; + mapping(address => mapping(address => bool)) public deprecated2; // slot 55 // token pool balances @@ -61,16 +66,30 @@ abstract contract FeesManagerStorage is IFeesManager { /// @dev chainSlug => fees plug address mapping(uint32 => bytes32) public feesPlugs; - // slots [58-107] reserved for gap - uint256[50] _gap_after; + // slot 58 + /// @notice Mapping to track token for each chain slug + /// @dev chainSlug => token address + bytes32 public susdcToken; + + // slot 59 + /// @notice Mapping to track whitelisted receivers + /// @dev receiver address => bool + mapping(address => bool) public whitelistedReceivers; + + /// @notice Mapping to track max fees per chain slug + /// @dev chainSlug => max fees + mapping(uint32 => uint256) public maxFeesPerChainSlug; + + // slots [60-107] reserved for gap + uint256[47] _gap_after; // slots [108-157] 50 slots reserved for address resolver util // 9 slots for app gateway base } -/// @title UserUtils -/// @notice Contract for managing user utils -abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatewayBase { +/// @title SocketUSDC +/// @notice ERC20 token for managing credits with blocking/unblocking functionality +abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatewayBase, ERC20 { /// @notice Emitted when fees deposited are updated /// @param chainSlug The chain identifier /// @param token The token address @@ -91,9 +110,6 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatew /// @notice Emitted when credits are unwrapped event CreditsUnwrapped(address indexed consumeFrom, uint256 amount); - /// @notice Emitted when credits are transferred - event CreditsTransferred(address indexed from, address indexed to, uint256 amount); - /// @notice Emitted when fees plug is set event FeesPlugSet(uint32 indexed chainSlug, bytes32 indexed feesPlug); @@ -103,6 +119,12 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatew /// @notice Emitted when withdraw fails event WithdrawFailed(bytes32 indexed payloadId); + /// @notice Emitted when susdc token is set + event SusdcTokenSet(uint32 indexed chainSlug, bytes32 indexed susdcToken); + + /// @notice Emitted when whitelisted receiver is set + event WhitelistedReceiverSet(address indexed receiver, bool isWhitelisted); + function setFeesPlug(uint32 chainSlug_, bytes32 feesPlug_) external onlyOwner { feesPlugs[chainSlug_] = feesPlug_; emit FeesPlugSet(chainSlug_, feesPlug_); @@ -113,6 +135,31 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatew emit FeesPoolSet(feesPool_); } + function setSusdcToken(uint32 chainSlug_, bytes32 susdcToken_) external onlyOwner { + forwarderAddresses[susdcToken][chainSlug_] = asyncDeployer__().getOrDeployForwarderContract( + susdcToken_, + chainSlug_ + ); + _setValidPlug(true, chainSlug_, susdcToken); + emit SusdcTokenSet(chainSlug_, susdcToken_); + } + + function setWhitelistedReceiver(address receiver_, bool isWhitelisted_) external onlyOwner { + whitelistedReceivers[receiver_] = isWhitelisted_; + emit WhitelistedReceiverSet(receiver_, isWhitelisted_); + } + + function getMaxFees(uint32 chainSlug_) public view returns (uint256) { + return + maxFeesPerChainSlug[chainSlug_] == 0 + ? maxFeesPerChainSlug[evmxSlug] + : maxFeesPerChainSlug[chainSlug_]; + } + + function isApproved(address user_, address appGateway_) public view returns (bool) { + return allowance(user_, appGateway_) > 0; + } + /// @notice Deposits credits and native tokens to a user /// @param depositTo_ The address to deposit the credits to /// @param chainSlug_ The chain slug @@ -124,33 +171,44 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatew address token_, address depositTo_, uint256 nativeAmount_, - uint256 creditAmount_ + uint256 creditAmount_, + bytes memory data_ ) external override onlyWatcher { + if (!whitelistedReceivers[depositTo_]) revert InvalidReceiver(); tokenOnChainBalances[chainSlug_][token_] += creditAmount_ + nativeAmount_; - UserCredits storage userCredit = userCredits[depositTo_]; - userCredit.totalCredits += creditAmount_; + // Mint tokens to the user + _mint(depositTo_, creditAmount_); if (nativeAmount_ > 0) { // if native transfer fails, add to credit bool success = feesPool.withdraw(depositTo_, nativeAmount_); if (!success) { - userCredit.totalCredits += nativeAmount_; + _mint(depositTo_, creditAmount_); nativeAmount_ = 0; creditAmount_ += nativeAmount_; } } + if (data_.length > 0) + IReceiver(depositTo_).onTransfer( + chainSlug_, + token_, + creditAmount_, + nativeAmount_, + data_ + ); + emit Deposited(chainSlug_, token_, depositTo_, creditAmount_, nativeAmount_); } function wrap(address receiver_) external payable override { - UserCredits storage userCredit = userCredits[receiver_]; - uint256 amount = msg.value; if (amount == 0) revert InvalidAmount(); - userCredit.totalCredits += amount; + + // Mint tokens to receiver + _mint(receiver_, amount); // reverts if transfer fails SafeTransferLib.safeTransferETH(address(feesPool), amount); @@ -158,9 +216,10 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatew } function unwrap(uint256 amount_, address receiver_) external { - UserCredits storage userCredit = userCredits[msg.sender]; - if (userCredit.totalCredits < amount_) revert InsufficientCreditsAvailable(); - userCredit.totalCredits -= amount_; + if (balanceOf(msg.sender) < amount_) revert InsufficientCreditsAvailable(); + + // Burn tokens from sender + _burn(msg.sender, amount_); bool success = feesPool.withdraw(receiver_, amount_); if (!success) revert InsufficientBalance(); @@ -168,12 +227,36 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatew emit CreditsUnwrapped(receiver_, amount_); } - /// @notice Returns available (unblocked) credits for a gateway - /// @param consumeFrom_ The app gateway address - /// @return The available credit amount - function getAvailableCredits(address consumeFrom_) public view override returns (uint256) { - UserCredits memory userCredit = userCredits[consumeFrom_]; - return userCredit.totalCredits - userCredit.blockedCredits; + function mint(address to, uint256 amount, bytes memory data_) external onlyWatcher { + _mintWithData(to, amount, data_); + } + + function _mintWithData(address to, uint256 amount, bytes memory data_) internal { + _mint(to, amount); + if (data_.length > 0) { + IReceiver(to).onTransfer(evmxSlug, address(this), amount, 0, data_); + } + } + + function burn(uint32 chainSlug_, address receiver_, uint256 amount_) external async { + _setMaxFees(getMaxFees(chainSlug_)); + _burn(msg.sender, amount_); + ISUSDCPlug(forwarderAddresses[susdcToken][chainSlug_]).mint(receiver_, amount_); + } + + /// @notice Override balanceOf to return available (unblocked) credits + function balanceOf(address account) public view override returns (uint256) { + return super.balanceOf(account) - userBlockedCredits[account]; + } + + /// @notice Get total balance including blocked credits + function totalBalanceOf(address account) public view returns (uint256) { + return super.balanceOf(account); + } + + /// @notice Get blocked credits for an account + function getBlockedCredits(address account) public view returns (uint256) { + return userBlockedCredits[account]; } /// @notice Checks if the user has enough credits @@ -188,32 +271,52 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatew ) public view override returns (bool) { // If consumeFrom_ is not same as spender_ or spender_ is not watcher, check if it is approved if (!_isWatcher(spender_) && consumeFrom_ != spender_) { - if (!isApproved[consumeFrom_][spender_]) return false; + if (allowance(consumeFrom_, spender_) == 0) return false; } - return getAvailableCredits(consumeFrom_) >= amount_; + return balanceOf(consumeFrom_) >= amount_; + } + + // ERC20 Overrides to handle blocked credits + + /// @notice Override transfer to check for blocked credits + function transfer(address to, uint256 amount) public override returns (bool) { + if (balanceOf(msg.sender) < amount) revert InsufficientCreditsAvailable(); + return super.transfer(to, amount); } - function transferCredits(address from_, address to_, uint256 amount_) external override { + /// @notice Override transferFrom to check for blocked credits + function transferFrom( + address from_, + address to_, + uint256 amount_ + ) public override returns (bool) { if (!isCreditSpendable(from_, msg.sender, amount_)) revert InsufficientCreditsAvailable(); - userCredits[from_].totalCredits -= amount_; - userCredits[to_].totalCredits += amount_; - emit CreditsTransferred(from_, to_, amount_); + if (_isWatcher(msg.sender)) _approve(from_, msg.sender, amount_); + return super.transferFrom(from_, to_, amount_); } /// @notice Approves app gateway for the caller /// @param appGateway_ app gateway address /// @param approval_ approval - function approveAppGateway(address appGateway_, bool approval_) external override { - isApproved[msg.sender][appGateway_] = approval_; + function approve(address appGateway_, bool approval_) external override { + _approve(msg.sender, appGateway_, approval_ ? type(uint256).max : 0); + } + + function approve(address spender, uint256 amount) public override returns (bool) { + return super.approve(spender, amount > 0 ? type(uint256).max : 0); } /// @notice Approves multiple app gateways for the caller /// @param params_ Array of app gateway addresses to approve - function approveAppGateways(AppGatewayApprovals[] calldata params_) external override { + function batchApprove(AppGatewayApprovals[] calldata params_) external override { for (uint256 i = 0; i < params_.length; i++) { - isApproved[msg.sender][params_[i].appGateway] = params_[i].approval; + _approve( + msg.sender, + params_[i].appGateway, + params_[i].approval ? type(uint256).max : 0 + ); } } @@ -223,7 +326,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatew /// @return consumeFrom The consume from address /// @return spender The app gateway address /// @return approval The approval status - function approveAppGatewayWithSignature( + function approveWithSignature( bytes memory feeApprovalData_ ) external returns (address consumeFrom, address spender, bool approval) { uint256 nonce; @@ -237,7 +340,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatew if (isNonceUsed[consumeFrom][nonce]) revert NonceUsed(); isNonceUsed[consumeFrom][nonce] = true; - isApproved[consumeFrom][spender] = approval; + _approve(consumeFrom, spender, approval ? type(uint256).max : 0); return (consumeFrom, spender, approval); } @@ -259,10 +362,11 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatew address consumeFrom = msg.sender; // Check if amount is available in fees plug - uint256 availableCredits = getAvailableCredits(consumeFrom); + uint256 availableCredits = balanceOf(consumeFrom); if (availableCredits < credits_ + maxFees_) revert InsufficientCreditsAvailable(); - userCredits[consumeFrom].totalCredits -= credits_; + // Burn tokens from sender + _burn(consumeFrom, credits_); tokenOnChainBalances[chainSlug_][token_] -= credits_; // Add it to the queue and submit request @@ -280,7 +384,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatew uint256 maxFees_, bytes memory payload_ ) internal async { - _setMaxFees(maxFees_); + _setMaxFees(getMaxFees(chainSlug_)); _setOverrides(consumeFrom_); QueueParams memory queueParams; @@ -294,6 +398,10 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatew watcher__().queue(queueParams, address(this)); } + function increaseFees(uint40 requestCount_, uint256 newMaxFees_) public { + _increaseFees(requestCount_, newMaxFees_); + } + function _getFeesPlugAddress(uint32 chainSlug_) internal view returns (bytes32) { if (feesPlugs[chainSlug_] == bytes32(0)) revert InvalidChainSlug(); return feesPlugs[chainSlug_]; @@ -312,10 +420,28 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AppGatew signer = ECDSA.recover(digest, signature_); } - /// @notice hook to handle the revert while withdrawing credits - /// @param payloadId_ The payload ID - function handleRevert(bytes32 payloadId_) external override { - if (watcher__().getPayloadParams(payloadId_).asyncPromise != msg.sender) return; - emit WithdrawFailed(payloadId_); + // ERC20 metadata + function name() public pure override returns (string memory) { + return "Socket USDC"; + } + + function symbol() public pure override returns (string memory) { + return "sUSDC"; + } + + function decimals() public pure override returns (uint8) { + return 18; + } + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public override { + // todo: implement permit } } diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index da3b29b9..8b26e810 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -24,6 +24,11 @@ contract FeesManager is Credit { uint256 amount ); + /// @notice Emitted when max fees per chain slug is set + /// @param chainSlug The chain slug + /// @param fees The max fees + event MaxFeesPerChainSlugSet(uint32 indexed chainSlug, uint256 fees); + /// @notice Emitted when fees are unblocked /// @param requestCount The batch identifier /// @param consumeFrom The consume from address @@ -47,16 +52,46 @@ contract FeesManager is Credit { address addressResolver_, address feesPool_, address owner_, + uint256 fees_, bytes32 sbType_ ) public reinitializer(2) { evmxSlug = evmxSlug_; sbType = sbType_; feesPool = IFeesPool(feesPool_); + susdcToken = _createContractId("susdc token"); + maxFeesPerChainSlug[evmxSlug_] = fees_; + _setMaxFees(fees_); _initializeOwner(owner_); _initializeAppGateway(addressResolver_); } + function setChainMaxFees( + uint32[] calldata chainSlugs_, + uint256[] calldata maxFees_ + ) external onlyOwner { + if (chainSlugs_.length != maxFees_.length) revert("Array length mismatch"); + + for (uint256 i = 0; i < chainSlugs_.length; i++) { + maxFeesPerChainSlug[chainSlugs_[i]] = maxFees_[i]; + emit MaxFeesPerChainSlugSet(chainSlugs_[i], maxFees_[i]); + } + } + + function getChainMaxFees( + uint32[] calldata chainSlugs_ + ) external view returns (uint256[] memory) { + uint256[] memory maxFeesArray = new uint256[](chainSlugs_.length); + for (uint256 i = 0; i < chainSlugs_.length; i++) { + maxFeesArray[i] = maxFeesPerChainSlug[chainSlugs_[i]]; + } + return maxFeesArray; + } + + function setMaxFees(uint256 fees_) external onlyOwner { + _setMaxFees(fees_); + } + /////////////////////// FEES MANAGEMENT /////////////////////// /// @notice Blocks fees for a request count @@ -69,10 +104,9 @@ contract FeesManager is Credit { address consumeFrom_, uint256 credits_ ) external override onlyRequestHandler { - if (getAvailableCredits(consumeFrom_) < credits_) revert InsufficientCreditsAvailable(); + if (balanceOf(consumeFrom_) < credits_) revert InsufficientCreditsAvailable(); - UserCredits storage userCredit = userCredits[consumeFrom_]; - userCredit.blockedCredits += credits_; + userBlockedCredits[consumeFrom_] += credits_; requestBlockedCredits[requestCount_] = credits_; emit CreditsBlocked(requestCount_, consumeFrom_, credits_); } @@ -88,13 +122,15 @@ contract FeesManager is Credit { if (blockedCredits == 0) return; address consumeFrom = _getRequestParams(requestCount_).requestFeesDetails.consumeFrom; - // Unblock fees from deposit - UserCredits storage userCredit = userCredits[consumeFrom]; - userCredit.blockedCredits -= blockedCredits; - userCredit.totalCredits -= blockedCredits; - // Assign fees to transmitter - userCredits[assignTo_].totalCredits += blockedCredits; + // Unblock credits from the original user + userBlockedCredits[consumeFrom] -= blockedCredits; + + // Burn tokens from the original user + _burn(consumeFrom, blockedCredits); + + // Mint tokens to the transmitter + _mint(assignTo_, blockedCredits); // Clean up storage delete requestBlockedCredits[requestCount_]; @@ -105,10 +141,9 @@ contract FeesManager is Credit { uint256 blockedCredits = requestBlockedCredits[requestCount_]; if (blockedCredits == 0) return; - // Unblock fees from deposit + // Unblock credits from the original user address consumeFrom = _getRequestParams(requestCount_).requestFeesDetails.consumeFrom; - UserCredits storage userCredit = userCredits[consumeFrom]; - userCredit.blockedCredits -= blockedCredits; + userBlockedCredits[consumeFrom] -= blockedCredits; delete requestBlockedCredits[requestCount_]; emit CreditsUnblocked(requestCount_, consumeFrom); diff --git a/contracts/evmx/interfaces/IAuctionManager.sol b/contracts/evmx/interfaces/IAuctionManager.sol index 5bacbf3a..af867f81 100644 --- a/contracts/evmx/interfaces/IAuctionManager.sol +++ b/contracts/evmx/interfaces/IAuctionManager.sol @@ -25,14 +25,15 @@ interface IAuctionManager { ) external; /// @notice Ends an auction - /// @param requestCount_ The request count - function endAuction(uint40 requestCount_) external; + /// @param data The encoded request count + function endAuction(bytes memory data, bytes memory) external; /// @notice Expires a bid and restarts an auction in case a request is not fully executed. /// @dev Auction can be restarted only for `maxReAuctionCount` times. /// @dev It also unblocks the fees from last transmitter to be assigned to the new winner. - /// @param requestCount_ The request id - function expireBid(uint40 requestCount_) external; + /// @param data The encoded request count + /// @param returnData The return data from the bid + function expireBid(bytes memory data, bytes memory returnData) external; /// @notice Checks if an auction is closed /// @param requestCount_ The request count diff --git a/contracts/evmx/interfaces/IERC20.sol b/contracts/evmx/interfaces/IERC20.sol new file mode 100644 index 00000000..a77315e8 --- /dev/null +++ b/contracts/evmx/interfaces/IERC20.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +interface IERC20 { + function totalSupply() external view returns (uint256); + + function balanceOf(address account) external view returns (uint256); + + function transfer(address to, uint256 amount) external returns (bool); + + function allowance(address owner, address spender) external view returns (uint256); + + function approve(address spender, uint256 amount) external returns (bool); + + function transferFrom(address from, address to, uint256 amount) external returns (bool); + + function decimals() external view returns (uint8); + + event Transfer(address indexed from, address indexed to, uint256 value); + + event Approval(address indexed owner, address indexed spender, uint256 value); +} diff --git a/contracts/evmx/interfaces/IFeesManager.sol b/contracts/evmx/interfaces/IFeesManager.sol index ea81aad6..01555b26 100644 --- a/contracts/evmx/interfaces/IFeesManager.sol +++ b/contracts/evmx/interfaces/IFeesManager.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {WriteFinality, UserCredits, AppGatewayApprovals, OverrideParams, Transaction, QueueParams, RequestParams} from "../../utils/common/Structs.sol"; +import {WriteFinality, AppGatewayApprovals, OverrideParams, Transaction, QueueParams, RequestParams} from "../../utils/common/Structs.sol"; interface IFeesManager { function deposit( @@ -8,28 +8,25 @@ interface IFeesManager { address token_, address depositTo_, uint256 nativeAmount_, - uint256 creditAmount_ + uint256 creditAmount_, + bytes memory data_ ) external; function wrap(address receiver_) external payable; function unwrap(uint256 amount_, address receiver_) external; - function getAvailableCredits(address consumeFrom_) external view returns (uint256); - function isCreditSpendable( address consumeFrom_, address spender_, uint256 amount_ ) external view returns (bool); - function transferCredits(address from_, address to_, uint256 amount_) external; - - function approveAppGateway(address appGateway_, bool approval_) external; + function approve(address appGateway_, bool approval_) external; - function approveAppGateways(AppGatewayApprovals[] calldata params_) external; + function batchApprove(AppGatewayApprovals[] calldata params_) external; - function approveAppGatewayWithSignature( + function approveWithSignature( bytes memory feeApprovalData_ ) external returns (address consumeFrom, address spender, bool approval); @@ -46,4 +43,12 @@ interface IFeesManager { function unblockAndAssignCredits(uint40 requestCount_, address assignTo_) external; function unblockCredits(uint40 requestCount_) external; + + function isApproved(address appGateway_, address user_) external view returns (bool); + + function burn(uint32 chainSlug_, address receiver_, uint256 amount_) external; + + function mint(address to, uint256 amount, bytes memory data_) external; + + function setMaxFees(uint256 fees_) external; } diff --git a/contracts/evmx/interfaces/IFeesPlug.sol b/contracts/evmx/interfaces/IFeesPlug.sol index 24cc719a..85cf0c25 100644 --- a/contracts/evmx/interfaces/IFeesPlug.sol +++ b/contracts/evmx/interfaces/IFeesPlug.sol @@ -7,7 +7,8 @@ interface IFeesPlug { address token, address receiver, uint256 creditAmount, - uint256 nativeAmount + uint256 nativeAmount, + bytes data ); /// @notice Event emitted when fees are withdrawn event FeesWithdrawn(address token, address receiver, uint256 amount); @@ -16,11 +17,26 @@ interface IFeesPlug { /// @notice Event emitted when a token is removed from whitelist event TokenRemovedFromWhitelist(address token); - function depositCredit(address token_, address receiver_, uint256 amount_) external; + function depositCredit( + address token_, + address receiver_, + uint256 amount_, + bytes memory data_ + ) external; - function depositCreditAndNative(address token_, address receiver_, uint256 amount_) external; + function depositCreditAndNative( + address token_, + address receiver_, + uint256 amount_, + bytes memory data_ + ) external; - function depositToNative(address token_, address receiver_, uint256 amount_) external; + function depositToNative( + address token_, + address receiver_, + uint256 amount_, + bytes memory data_ + ) external; function withdrawFees(address token_, address receiver_, uint256 amount_) external; } diff --git a/contracts/evmx/interfaces/IPromise.sol b/contracts/evmx/interfaces/IPromise.sol index 9809d549..f323ae69 100644 --- a/contracts/evmx/interfaces/IPromise.sol +++ b/contracts/evmx/interfaces/IPromise.sol @@ -12,6 +12,12 @@ interface IPromise { /// @dev The callback will be executed on this address function localInvoker() external view returns (address); + /// @notice The callback selector of the promise + function callbackSelector() external view returns (bytes4); + + /// @notice The callback data of the promise + function callbackData() external view returns (bytes memory); + /// @notice The request count of the promise function requestCount() external view returns (uint40); diff --git a/contracts/evmx/interfaces/IReceiver.sol b/contracts/evmx/interfaces/IReceiver.sol new file mode 100644 index 00000000..398ab04b --- /dev/null +++ b/contracts/evmx/interfaces/IReceiver.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +/// @title IReceiver +/// @notice Interface for receiving transfers +interface IReceiver { + function onTransfer( + uint32 chainSlug_, + address token_, + uint256 creditAmount_, + uint256 nativeAmount_, + bytes memory data_ + ) external; +} diff --git a/contracts/evmx/interfaces/ISUSDC.sol b/contracts/evmx/interfaces/ISUSDC.sol new file mode 100644 index 00000000..985dedbc --- /dev/null +++ b/contracts/evmx/interfaces/ISUSDC.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +interface ISUSDC { + function mint(address to, uint256 amount) external; + + function burn(address receiver_, uint256 amount, bytes memory data_) external; +} diff --git a/contracts/evmx/plugs/FeesPlug.sol b/contracts/evmx/plugs/FeesPlug.sol index b07942c8..b46baab1 100644 --- a/contracts/evmx/plugs/FeesPlug.sol +++ b/contracts/evmx/plugs/FeesPlug.sol @@ -8,12 +8,7 @@ import {RESCUE_ROLE} from "../../utils/common/AccessRoles.sol"; import {IFeesPlug} from "../interfaces/IFeesPlug.sol"; import "../../utils/RescueFundsLib.sol"; import {InvalidTokenAddress} from "../../utils/common/Errors.sol"; - -interface IERC20 { - function balanceOf(address account) external view returns (uint256); - - function decimals() external view returns (uint8); -} +import "../interfaces/IERC20.sol"; /// @title FeesPlug /// @notice Contract for managing fees on a network @@ -43,21 +38,32 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { } /////////////////////// DEPOSIT AND WITHDRAWAL /////////////////////// - function depositCredit(address token_, address receiver_, uint256 amount_) external override { - _deposit(token_, receiver_, amount_, 0); + function depositCredit( + address token_, + address receiver_, + uint256 amount_, + bytes memory data_ + ) external override { + _deposit(token_, receiver_, amount_, 0, data_); } function depositCreditAndNative( address token_, address receiver_, - uint256 amount_ + uint256 amount_, + bytes memory data_ ) external override { uint256 nativeAmount_ = amount_ / 10; - _deposit(token_, receiver_, amount_ - nativeAmount_, nativeAmount_); + _deposit(token_, receiver_, amount_ - nativeAmount_, nativeAmount_, data_); } - function depositToNative(address token_, address receiver_, uint256 amount_) external override { - _deposit(token_, receiver_, 0, amount_); + function depositToNative( + address token_, + address receiver_, + uint256 amount_, + bytes memory data_ + ) external override { + _deposit(token_, receiver_, 0, amount_, data_); } /// @notice Deposits funds @@ -69,11 +75,12 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { address token_, address receiver_, uint256 creditAmount_, - uint256 nativeAmount_ + uint256 nativeAmount_, + bytes memory data_ ) internal { if (!whitelistedTokens[token_]) revert TokenNotWhitelisted(token_); token_.safeTransferFrom(msg.sender, address(this), creditAmount_ + nativeAmount_); - emit FeesDeposited(token_, receiver_, creditAmount_, nativeAmount_); + emit FeesDeposited(token_, receiver_, creditAmount_, nativeAmount_, data_); } /// @notice Withdraws fees diff --git a/contracts/evmx/plugs/SUSDC.sol b/contracts/evmx/plugs/SUSDC.sol new file mode 100644 index 00000000..7272d775 --- /dev/null +++ b/contracts/evmx/plugs/SUSDC.sol @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import "solady/tokens/ERC20.sol"; +import "../../utils/AccessControl.sol"; +import "../../utils/RescueFundsLib.sol"; + +import "../../protocol/base/PlugBase.sol"; +import {RESCUE_ROLE} from "../../utils/common/AccessRoles.sol"; + +import "../interfaces/IFeesManager.sol"; + +/// @title AdvancedToken +/// @notice An advanced ERC20 token with minting, burning, and pausing capabilities +/// @author Your Name +contract SUSDC is ERC20, AccessControl, PlugBase { + /// @notice The name of the token + string private _name; + + /// @notice The symbol of the token + string private _symbol; + + /// @notice The number of decimals for the token + uint8 private _decimals; + + /// @notice Emitted when tokens are minted + event TokensMinted(address indexed to, uint256 amount); + + /// @notice Emitted when tokens are burned + event TokensBurned(address indexed from, address indexed to, uint256 amount, bytes data); + + /// @notice Constructor that sets token metadata and mints initial supply + /// @param initialOwner The address to receive the initial supply and ownership + /// @param tokenName The name of the token + /// @param tokenSymbol The symbol of the token + /// @param tokenDecimals The number of decimals for the token + constructor( + uint8 tokenDecimals, + address initialOwner, + address socket, + string memory tokenName, + string memory tokenSymbol + ) { + isSocketInitialized = 1; + _decimals = tokenDecimals; + _name = tokenName; + _symbol = tokenSymbol; + + _setSocket(socket); + _initializeOwner(initialOwner); + } + + /// @notice Returns the name of the token + /// @return The name of the token + function name() public view override returns (string memory) { + return _name; + } + + /// @notice Returns the symbol of the token + /// @return The symbol of the token + function symbol() public view override returns (string memory) { + return _symbol; + } + + /// @notice Returns the number of decimals used to get its user representation + /// @return The number of decimals + function decimals() public view override returns (uint8) { + return _decimals; + } + + /// @notice Mints new tokens (only owner) + /// @param to The address to mint tokens to + /// @param amount The amount of tokens to mint + function mint(address to, uint256 amount) external onlySocket { + require(to != address(0), "Cannot mint to zero address"); + require(amount > 0, "Amount must be greater than 0"); + + _mint(to, amount); + emit TokensMinted(to, amount); + } + + /// @notice Burns tokens from the caller's balance + /// @param amount The amount of tokens to burn + function burn(address receiver_, uint256 amount, bytes memory data_) external { + require(amount > 0, "Amount must be greater than 0"); + require(balanceOf(msg.sender) >= amount, "Insufficient balance"); + + _burn(msg.sender, amount); + IFeesManager(address(socket__)).mint(receiver_, amount, data_); + emit TokensBurned(msg.sender, receiver_, amount, data_); + } + + /// @notice Override transfer function to check for paused state + /// @param to The address to transfer tokens to + /// @param amount The amount of tokens to transfer + /// @return True if the transfer was successful + function transfer(address to, uint256 amount) public override returns (bool) { + return super.transfer(to, amount); + } + + /// @notice Override transferFrom function to check for paused state + /// @param from The address to transfer tokens from + /// @param to The address to transfer tokens to + /// @param amount The amount of tokens to transfer + /// @return True if the transfer was successful + function transferFrom(address from, address to, uint256 amount) public override returns (bool) { + return super.transferFrom(from, to, amount); + } + + function connectSocket( + bytes32 appGatewayId_, + address socket_, + uint64 switchboardId_ + ) external onlyOwner { + _connectSocket(appGatewayId_, socket_, switchboardId_); + } + + function disconnectSocket() external onlyOwner { + socket__.disconnect(); + } + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds( + address token_, + address rescueTo_, + uint256 amount_ + ) external onlyRole(RESCUE_ROLE) { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } +} diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 33d239ca..50bb0999 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -66,7 +66,7 @@ contract Configurations is ConfigurationsStorage, Initializable, Ownable, Watche /// @param chainSlug The identifier of the network /// @param plug The address of the plug /// @param isValid Whether the plug is valid - event IsValidPlugSet(address appGateway, uint32 chainSlug, bytes32 plug, bool isValid); + event IsValidPlugSet(bool isValid, uint32 chainSlug, bytes32 plug, address appGateway); constructor() { _disableInitializers(); // disable for implementation @@ -128,7 +128,7 @@ contract Configurations is ConfigurationsStorage, Initializable, Ownable, Watche address appGateway_ ) external onlyWatcher { isValidPlug[appGateway_][chainSlug_][plug_] = isValid_; - emit IsValidPlugSet(appGateway_, chainSlug_, plug_, isValid_); + emit IsValidPlugSet(isValid_, chainSlug_, plug_, appGateway_); } /// @notice Retrieves the configuration for a specific plug on a network diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index 82367c13..7f014671 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -6,11 +6,15 @@ import "../interfaces/IPromise.sol"; import "../interfaces/IPromiseResolver.sol"; import {DeadlineNotPassedForOnChainRevert} from "../../utils/common/Errors.sol"; import "../../utils/RescueFundsLib.sol"; +import "solady/utils/Initializable.sol"; /// @title PromiseResolver /// @notice Contract that handles promise resolution and revert marking logic /// @dev This contract interacts with the Watcher for storage access -contract PromiseResolver is IPromiseResolver, WatcherBase { +contract PromiseResolver is IPromiseResolver, WatcherBase, Initializable { + // slots [0-49] reserved for gap + uint256[50] _gap_before; + /// @notice Emitted when a promise is resolved /// @param payloadId The unique identifier for the resolved promise event PromiseResolved(bytes32 indexed payloadId, address asyncPromise); @@ -24,9 +28,13 @@ contract PromiseResolver is IPromiseResolver, WatcherBase { /// @param isRevertingOnchain Whether the payload is reverting onchain event MarkedRevert(bytes32 indexed payloadId, bool isRevertingOnchain); + constructor() { + _disableInitializers(); // disable for implementation + } + /// @notice Sets the Watcher address /// @param watcher_ The address of the Watcher contract - constructor(address watcher_) { + function initialize(address watcher_) external reinitializer(1) { _initializeWatcher(watcher_); } @@ -82,7 +90,7 @@ contract PromiseResolver is IPromiseResolver, WatcherBase { // Get payload params from Watcher bytes32 payloadId = resolvedPromise_.payloadId; PayloadParams memory payloadParams = watcher__.getPayloadParams(payloadId); - if (payloadParams.deadline > block.timestamp) revert DeadlineNotPassedForOnChainRevert(); + // if (payloadParams.deadline > block.timestamp) revert DeadlineNotPassedForOnChainRevert(); // marks the request as cancelled and settles the fees requestHandler__().cancelRequestForReverts(uint40(payloadParams.payloadPointer >> 120)); diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index b6f53d4c..a5d793e0 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -12,6 +12,7 @@ import "../interfaces/IPromise.sol"; import "../interfaces/IRequestHandler.sol"; import "../../utils/RescueFundsLib.sol"; import "solady/utils/LibCall.sol"; +import "../interfaces/IERC20.sol"; abstract contract RequestHandlerStorage is IRequestHandler { // slots [0-49] reserved for gap @@ -77,6 +78,8 @@ contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, Addres event RequestSettled(uint40 requestCount, address winner); event RequestCompletedWithErrors(uint40 requestCount); event RequestCancelled(uint40 requestCount); + event PrecompileSet(bytes4 callType, IPrecompile precompile); + event RequestPayloadCountLimitSet(uint128 requestPayloadCountLimit); modifier isRequestCancelled(uint40 requestCount_) { if (_requests[requestCount_].requestTrackingParams.isRequestCancelled) @@ -101,10 +104,12 @@ contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, Addres function setPrecompile(bytes4 callType_, IPrecompile precompile_) external onlyOwner { precompiles[callType_] = precompile_; + emit PrecompileSet(callType_, precompile_); } function setRequestPayloadCountLimit(uint128 requestPayloadCountLimit_) external onlyOwner { requestPayloadCountLimit = requestPayloadCountLimit_; + emit RequestPayloadCountLimitSet(requestPayloadCountLimit_); } function getPrecompileFees( @@ -189,8 +194,11 @@ contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, Addres if (r.writeCount == 0) revert NoWriteRequest(); // If same transmitter is reassigned, revert - if (r.requestFeesDetails.winningBid.transmitter == bid_.transmitter) - revert AlreadyAssigned(); + // todo: remove after game + // also this overrides a payload deadline hence an unexecuted payload can + // be executed by new added transmitters. need to fix this by marking req deadline or something. + // if (r.requestFeesDetails.winningBid.transmitter == bid_.transmitter) + // revert AlreadyAssigned(); // If a transmitter was already assigned previously, unblock the credits if (r.requestFeesDetails.winningBid.transmitter != address(0)) { @@ -316,7 +324,7 @@ contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, Addres address watcherFeesPayer = r.requestFeesDetails.winningBid.transmitter == address(0) ? r.requestFeesDetails.consumeFrom : r.requestFeesDetails.winningBid.transmitter; - feesManager__().transferCredits(watcherFeesPayer, address(this), totalFees); + IERC20(address(feesManager__())).transferFrom(watcherFeesPayer, address(this), totalFees); } /// @notice Increases the fees for a request if no bid is placed diff --git a/contracts/evmx/watcher/Trigger.sol b/contracts/evmx/watcher/Trigger.sol index 72e7dfcd..181c2367 100644 --- a/contracts/evmx/watcher/Trigger.sol +++ b/contracts/evmx/watcher/Trigger.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.21; import {LibCall} from "solady/utils/LibCall.sol"; import "./WatcherStorage.sol"; import {fromBytes32Format} from "../../utils/common/Converters.sol"; +import "../interfaces/IERC20.sol"; /// @title Trigger /// @notice Contract that handles trigger validation and execution logic @@ -33,11 +34,10 @@ abstract contract Trigger is WatcherStorage, AddressResolverUtil { if (!configurations__.isValidPlug(appGateway, params_.chainSlug, params_.plug)) revert InvalidCallerTriggered(); - feesManager__().transferCredits(appGateway, address(this), triggerFees); + IERC20(address(feesManager__())).transferFrom(appGateway, address(this), triggerFees); triggerFromChainSlug = params_.chainSlug; triggerFromPlug = params_.plug; - isAppGatewayCalled[params_.triggerId] = true; (bool success, , ) = appGateway.tryCall( 0, gasleft(), @@ -48,10 +48,16 @@ abstract contract Trigger is WatcherStorage, AddressResolverUtil { if (!success) { emit TriggerFailed(params_.triggerId); } else { + isAppGatewayCalled[params_.triggerId] = true; emit TriggerSucceeded(params_.triggerId); } triggerFromChainSlug = 0; triggerFromPlug = bytes32(0); } + + // todo: add onlyWatcher modifier + function resetIsAppGatewayCalled(bytes32 triggerId_) external { + isAppGatewayCalled[triggerId_] = false; + } } diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 18c0380d..0c714c3f 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -7,6 +7,8 @@ import "../interfaces/IPromise.sol"; contract Watcher is Trigger { using LibCall for address; + event CoreContractsSet(address requestHandler, address configManager, address promiseResolver); + constructor() { _disableInitializers(); // disable for implementation } @@ -31,6 +33,8 @@ contract Watcher is Trigger { requestHandler__ = IRequestHandler(requestHandler_); configurations__ = IConfigurations(configManager_); promiseResolver__ = IPromiseResolver(promiseResolver_); + + emit CoreContractsSet(requestHandler_, configManager_, promiseResolver_); } function isWatcher(address account_) public view override returns (bool) { diff --git a/contracts/evmx/watcher/WatcherBase.sol b/contracts/evmx/watcher/WatcherBase.sol index 468dcbcf..c661c288 100644 --- a/contracts/evmx/watcher/WatcherBase.sol +++ b/contracts/evmx/watcher/WatcherBase.sol @@ -5,6 +5,7 @@ import "../interfaces/IWatcher.sol"; import "../interfaces/IConfigurations.sol"; import "../interfaces/IPromiseResolver.sol"; import "../interfaces/IRequestHandler.sol"; +import "../../utils/common/Errors.sol"; /// @title WatcherBase /// @notice Base contract for the Watcher contract @@ -13,19 +14,18 @@ contract WatcherBase { // The address of the Watcher contract IWatcher public watcher__; - // Only Watcher can call functions modifier onlyWatcher() { - require(msg.sender == address(watcher__), "Only Watcher can call"); + if (msg.sender != address(watcher__)) revert OnlyWatcherAllowed(); _; } modifier onlyRequestHandler() { - require(msg.sender == address(requestHandler__()), "Only RequestHandler can call"); + if (msg.sender != address(requestHandler__())) revert OnlyRequestHandlerAllowed(); _; } modifier onlyPromiseResolver() { - require(msg.sender == address(promiseResolver__()), "Only PromiseResolver can call"); + if (msg.sender != address(promiseResolver__())) revert OnlyPromiseResolverAllowed(); _; } diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index 597928c7..186c9b42 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -2,6 +2,8 @@ pragma solidity ^0.8.21; import "../../interfaces/IPrecompile.sol"; +import "../../interfaces/IPromise.sol"; + import "../../../utils/common/Structs.sol"; import {InvalidScheduleDelay, ResolvingScheduleTooEarly} from "../../../utils/common/Errors.sol"; import "../../../utils/RescueFundsLib.sol"; @@ -32,7 +34,14 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { /// @notice Emitted when the expiry time for a schedule is set event ExpiryTimeSet(uint256 expiryTime_); /// @notice Emitted when a schedule is requested - event ScheduleRequested(bytes32 payloadId, uint256 executeAfter, uint256 deadline); + event ScheduleRequested( + bytes32 payloadId, + uint256 executeAfter, + uint256 deadline, + address localInvoker, + bytes4 callbackSelector, + bytes callbackData + ); /// @notice Emitted when a schedule is resolved event ScheduleResolved(bytes32 payloadId); @@ -128,8 +137,17 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { precompileData = abi.encode(delayInSeconds, executeAfter); fees = getPrecompileFees(precompileData); + IPromise promise_ = IPromise(payloadParams.asyncPromise); + // emits event for watcher to track schedule and resolve when deadline is reached - emit ScheduleRequested(payloadParams.payloadId, executeAfter, deadline); + emit ScheduleRequested( + payloadParams.payloadId, + executeAfter, + deadline, + promise_.localInvoker(), + promise_.callbackSelector(), + promise_.callbackData() + ); } function resolvePayload(PayloadParams calldata payloadParams_) external onlyRequestHandler { diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 2eea6870..49409261 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -122,7 +122,18 @@ contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, Watc // todo: can be changed to set the default gas limit for each chain if (queueParams_.overrideParams.gasLimit == 0) { - queueParams_.overrideParams.gasLimit = 10000000; + if (queueParams_.transaction.chainSlug == 5000) { + // Mantle default gas limit + queueParams_.overrideParams.gasLimit = 8_000_000_000; + } else if (queueParams_.transaction.chainSlug == 1329) { + // Sei default gas limit + queueParams_.overrideParams.gasLimit = 8_000_000; + } else if (queueParams_.transaction.chainSlug == 999) { + // HyperEVM default gas limit + queueParams_.overrideParams.gasLimit = 1_500_000; + } else { + queueParams_.overrideParams.gasLimit = 10_000_000; // other chains default gas limit + } } // For write precompile, encode the payload parameters diff --git a/contracts/protocol/Socket.sol b/contracts/protocol/Socket.sol index ad3f97dd..4d4b2257 100644 --- a/contracts/protocol/Socket.sol +++ b/contracts/protocol/Socket.sol @@ -14,30 +14,22 @@ import {createPayloadId} from "../utils/common/IdUtils.sol"; contract Socket is SocketUtils { using LibCall for address; - // @notice mapping of payload id to execution status + // mapping of payload id to execution status mapping(bytes32 => ExecutionStatus) public payloadExecuted; - // @notice mapping of payload id to execution status + // mapping of payload id to digest mapping(bytes32 => bytes32) public payloadIdToDigest; //////////////////////////////////////////////////////// ////////////////////// ERRORS ////////////////////////// //////////////////////////////////////////////////////// - /** - * @dev Error emitted when a payload has already been executed - */ + /// @notice Thrown when a payload has already been executed error PayloadAlreadyExecuted(ExecutionStatus status); - /** - * @dev Error emitted when verification fails - */ + /// @notice Thrown when verification fails error VerificationFailed(); - /** - * @dev Error emitted when less gas limit is provided for execution than expected - */ + /// @notice Thrown when less gas limit is provided for execution than expected error LowGasLimit(); - /** - * @dev Error emitted when the message value is insufficient - */ + /// @notice Thrown when the message value is insufficient error InsufficientMsgValue(); /** @@ -56,6 +48,10 @@ contract Socket is SocketUtils { /** * @notice Executes a payload that has been delivered by transmitters and authenticated by switchboards + * @param executeParams_ The execution parameters + * @param transmissionParams_ The transmission parameters + * @return success True if the payload was executed successfully + * @return returnData The return data from the execution */ function execute( ExecuteParams calldata executeParams_, @@ -67,10 +63,11 @@ contract Socket is SocketUtils { // check if the call type is valid if (executeParams_.callType != WRITE) revert InvalidCallType(); - PlugConfigEvm memory plugConfig = _plugConfigs[executeParams_.target]; - // check if the plug is disconnected + // check if the plug is connected + PlugConfigEvm storage plugConfig = _plugConfigs[executeParams_.target]; if (plugConfig.appGatewayId == bytes32(0)) revert PlugNotFound(); + // check if the message value is sufficient if (msg.value < executeParams_.value + transmissionParams_.socketFees) revert InsufficientMsgValue(); @@ -86,12 +83,20 @@ contract Socket is SocketUtils { // verify the digest _verify(payloadId, plugConfig, executeParams_, transmissionParams_.transmitterProof); + // execute the payload return _execute(payloadId, executeParams_, transmissionParams_); } //////////////////////////////////////////////////////// ////////////////// INTERNAL FUNCS ////////////////////// //////////////////////////////////////////////////////// + /** + * @notice Verifies the digest of the payload + * @param payloadId_ The id of the payload + * @param plugConfig_ The plug configuration + * @param executeParams_ The execution parameters (appGatewayId, value, payloadPointer, callType, gasLimit) + * @param transmitterProof_ The transmitter proof + */ function _verify( bytes32 payloadId_, PlugConfigEvm memory plugConfig_, @@ -101,6 +106,7 @@ contract Socket is SocketUtils { if (isValidSwitchboard[plugConfig_.switchboardId] != SwitchboardStatus.REGISTERED) revert InvalidSwitchboard(); + // NOTE: the first un-trusted call in the system address transmitter = ISwitchboard(switchboardAddresses[plugConfig_.switchboardId]) .getTransmitter(msg.sender, payloadId_, transmitterProof_); @@ -114,7 +120,6 @@ contract Socket is SocketUtils { ); payloadIdToDigest[payloadId_] = digest; - // NOTE: is the the first un-trusted call in the system, another one is Plug.call if ( !ISwitchboard(switchboardAddresses[plugConfig_.switchboardId]).allowPayload( digest, @@ -124,9 +129,10 @@ contract Socket is SocketUtils { } /** - * This function assumes localPlug_ will have code while executing. As the payload - * execution failure is not blocking the system, it is not necessary to check if - * code exists in the given address. + * @notice Executes the payload + * @param payloadId_ The id of the payload + * @param executeParams_ The execution parameters (appGatewayId, value, payloadPointer, callType, gasLimit) + * @param transmissionParams_ The transmission parameters (socketFees, transmitterProof, refundAddress) */ function _execute( bytes32 payloadId_, @@ -149,6 +155,7 @@ contract Socket is SocketUtils { if (success) { emit ExecutionSuccess(payloadId_, exceededMaxCopy, returnData); + // pay and check fees if (address(socketFeeManager) != address(0)) { socketFeeManager.payAndCheckFees{value: transmissionParams_.socketFees}( executeParams_, @@ -158,17 +165,20 @@ contract Socket is SocketUtils { } else { payloadExecuted[payloadId_] = ExecutionStatus.Reverted; - address receiver = transmissionParams_.refundAddress == address(0) - ? msg.sender - : transmissionParams_.refundAddress; + // refund the fees + address receiver = transmissionParams_.refundAddress; + if (receiver == address(0)) receiver = msg.sender; SafeTransferLib.forceSafeTransferETH(receiver, msg.value); emit ExecutionFailed(payloadId_, exceededMaxCopy, returnData); } return (success, returnData); } - /// @notice Validates the execution status of a payload - /// @dev This function can be retried till execution status is executed + /** + * @notice Validates the execution status of a payload + * @dev This function can be retried till execution status is executed + * @param payloadId_ The id of the payload + */ function _validateExecutionStatus(bytes32 payloadId_) internal { if (payloadExecuted[payloadId_] == ExecutionStatus.Executed) revert PayloadAlreadyExecuted(payloadExecuted[payloadId_]); @@ -180,13 +190,21 @@ contract Socket is SocketUtils { ////////////////////// Trigger ////////////////////// //////////////////////////////////////////////////////// - /// @notice To trigger to a connected remote chain. Should only be called by a plug. + /** + * @notice To trigger to a connected remote chain. Should only be called by a plug. + * @param data_ The data to trigger the app gateway + * @return triggerId The id of the trigger + */ function triggerAppGateway(bytes calldata data_) external payable returns (bytes32 triggerId) { triggerId = _triggerAppGateway(msg.sender, msg.value, data_); } /** * @notice To trigger to a connected remote chain. Should only be called by a plug. + * @param plug_ The address of the plug + * @param value_ The value to trigger the app gateway + * @param data_ The data to trigger the app gateway + * @return triggerId The id of the trigger */ function _triggerAppGateway( address plug_, @@ -221,16 +239,20 @@ contract Socket is SocketUtils { ); } - /// @notice Fallback function that forwards all calls to Socket's callAppGateway - /// @dev The calldata is passed as-is to the gateways + /** + * @notice Fallback function that forwards all calls to Socket's callAppGateway + * @dev The calldata is passed as-is to the gateways + * @return The trigger id + */ fallback(bytes calldata) external payable returns (bytes memory) { // return the trigger id return abi.encode(_triggerAppGateway(msg.sender, msg.value, msg.data)); } - /// @notice Receive function that forwards all calls to Socket's callAppGateway + /** + * @notice Sending ETH to the socket will revert + */ receive() external payable { - // todo: need a fn to increase trigger fees revert("Socket does not accept ETH"); } } diff --git a/contracts/protocol/SocketBatcher.sol b/contracts/protocol/SocketBatcher.sol index 85710e77..1ed5a359 100644 --- a/contracts/protocol/SocketBatcher.sol +++ b/contracts/protocol/SocketBatcher.sol @@ -10,13 +10,17 @@ import "../utils/RescueFundsLib.sol"; import {ExecuteParams, TransmissionParams, CCTPBatchParams, CCTPExecutionParams} from "../utils/common/Structs.sol"; import {createPayloadId} from "../utils/common/IdUtils.sol"; +/** + * @title IFastSwitchboard + * @notice Interface for the fast switchboard + */ interface IFastSwitchboard is ISwitchboard { function attest(bytes32 digest_, bytes calldata proof_) external; } /** * @title SocketBatcher - * @notice The SocketBatcher contract is responsible for batching payloads and transmitting them to the destination chain + * @notice The SocketBatcher contract is responsible for batching payloads and executing them on the socket */ contract SocketBatcher is ISocketBatcher, Ownable { // socket contract @@ -61,6 +65,14 @@ contract SocketBatcher is ISocketBatcher, Ownable { ); } + /** + * @notice Attests a CCTP payload and proves and executes it + * @param execParams_ The execution parameters + * @param cctpParams_ The CCTP parameters + * @param switchboardId_ The switchboard id + * @return success True if the payload was executed successfully + * @return returnData The return data from the execution + */ function attestCCTPAndProveAndExecute( CCTPExecutionParams calldata execParams_, CCTPBatchParams calldata cctpParams_, diff --git a/contracts/protocol/SocketConfig.sol b/contracts/protocol/SocketConfig.sol index 2a701b4a..990003f4 100644 --- a/contracts/protocol/SocketConfig.sol +++ b/contracts/protocol/SocketConfig.sol @@ -55,23 +55,38 @@ abstract contract SocketConfig is ISocket, AccessControl { event SwitchboardEnabled(uint64 switchboardId); // @notice event triggered when a socket fee manager is updated event SocketFeeManagerUpdated(address oldSocketFeeManager, address newSocketFeeManager); + // @notice event triggered when the gas limit buffer is updated + event GasLimitBufferUpdated(uint256 gasLimitBuffer); + // @notice event triggered when the max copy bytes is updated + event MaxCopyBytesUpdated(uint16 maxCopyBytes); - // @notice function to register a switchboard - // @dev only callable by switchboards + /** + * @notice Registers a switchboard on the socket + * @dev This function is called by the switchboard to register itself on the socket + * @dev This function will revert if the switchboard already exists + * @return switchboardId The id of the switchboard + */ function registerSwitchboard() external returns (uint64 switchboardId) { switchboardId = switchboardIds[msg.sender]; if (switchboardId != 0) revert SwitchboardExists(); + // increment the switchboard id counter switchboardId = switchboardIdCounter++; + + // set the switchboard id and address switchboardIds[msg.sender] = switchboardId; switchboardAddresses[switchboardId] = msg.sender; - isValidSwitchboard[switchboardId] = SwitchboardStatus.REGISTERED; + // set the switchboard status to registered + isValidSwitchboard[switchboardId] = SwitchboardStatus.REGISTERED; emit SwitchboardAdded(msg.sender, switchboardId); } - // @notice function to disable a switchboard - // @dev only callable by governance role + /** + * @notice Disables a switchboard + * @dev This function is called by the governance role to disable a switchboard + * @param switchboardId_ The id of the switchboard to disable + */ function disableSwitchboard( uint64 switchboardId_ ) external onlyRole(SWITCHBOARD_DISABLER_ROLE) { @@ -79,20 +94,31 @@ abstract contract SocketConfig is ISocket, AccessControl { emit SwitchboardDisabled(switchboardId_); } - // @notice function to enable a switchboard - // @dev only callable by governance role + /** + * @notice Enables a switchboard if disabled + * @dev This function is called by the governance role to enable a switchboard + * @param switchboardId_ The id of the switchboard to enable + */ function enableSwitchboard(uint64 switchboardId_) external onlyRole(GOVERNANCE_ROLE) { isValidSwitchboard[switchboardId_] = SwitchboardStatus.REGISTERED; emit SwitchboardEnabled(switchboardId_); } + /** + * @notice Sets the socket fee manager + * @dev This function is called by the governance role to set the socket fee manager + * @param socketFeeManager_ The address of the socket fee manager + */ function setSocketFeeManager(address socketFeeManager_) external onlyRole(GOVERNANCE_ROLE) { - emit SocketFeeManagerUpdated(address(socketFeeManager), socketFeeManager_); socketFeeManager = ISocketFeeManager(socketFeeManager_); + emit SocketFeeManagerUpdated(address(socketFeeManager), socketFeeManager_); } /** - * @notice connects Plug to Socket and sets the config for given `siblingChainSlug_` + * @notice Connects a plug to socket + * @dev This function is called by the plug to connect itself to the socket + * @param appGatewayId_ The app gateway id + * @param switchboardId_ The switchboard id */ function connect(bytes32 appGatewayId_, uint64 switchboardId_) external override { if (isValidSwitchboard[switchboardId_] != SwitchboardStatus.REGISTERED) @@ -106,7 +132,8 @@ abstract contract SocketConfig is ISocket, AccessControl { } /** - * @notice disconnects Plug from Socket + * @notice Disconnects a plug from socket + * @dev This function is called by the plug to disconnect itself from the socket */ function disconnect() external override { PlugConfigEvm storage _plugConfig = _plugConfigs[msg.sender]; @@ -117,23 +144,29 @@ abstract contract SocketConfig is ISocket, AccessControl { emit PlugDisconnected(msg.sender); } - // @notice function to set the gas limit buffer for socket - // @dev only callable by governance role - // @param gasLimitBuffer_ gas limit buffer for socket + /** + * @notice Sets the gas limit buffer for socket + * @dev This function is called by the governance role to set the gas limit buffer for socket + * @param gasLimitBuffer_ The gas limit buffer for socket + */ function setGasLimitBuffer(uint256 gasLimitBuffer_) external onlyRole(GOVERNANCE_ROLE) { gasLimitBuffer = gasLimitBuffer_; + emit GasLimitBufferUpdated(gasLimitBuffer_); } - // @notice function to set the max copy bytes for socket - // @dev only callable by governance role - // @param maxCopyBytes_ max copy bytes for socket + /** + * @notice Sets the max copy bytes for socket + * @dev This function is called by the governance role to set the max copy bytes for socket + * @param maxCopyBytes_ The max copy bytes for socket + */ function setMaxCopyBytes(uint16 maxCopyBytes_) external onlyRole(GOVERNANCE_ROLE) { maxCopyBytes = maxCopyBytes_; + emit MaxCopyBytesUpdated(maxCopyBytes_); } /** - * @notice returns the config for given `plugAddress_` - * @param plugAddress_ address of plug present at current chain + * @notice Returns the config for given `plugAddress_` + * @param plugAddress_ The address of the plug present at current chain * @return appGatewayId The app gateway id * @return switchboardId The switchboard id */ diff --git a/contracts/protocol/SocketFeeManager.sol b/contracts/protocol/SocketFeeManager.sol index 3e3bfa8e..c0b7b946 100644 --- a/contracts/protocol/SocketFeeManager.sol +++ b/contracts/protocol/SocketFeeManager.sol @@ -12,12 +12,28 @@ import "../utils/RescueFundsLib.sol"; * @notice The SocketFeeManager contract is responsible for managing socket fees */ contract SocketFeeManager is ISocketFeeManager, AccessControl { - // Current socket fees in native tokens + // current socket fees in native tokens uint256 public socketFees; + //////////////////////////////////////////////////////////// + ////////////////////// ERRORS ////////////////////////// + //////////////////////////////////////////////////////////// + + /// @notice Thrown when the fees are insufficient error InsufficientFees(); + + /// @notice Thrown when the fees are too low error FeeTooLow(); + //////////////////////////////////////////////////////////// + ////////////////////// EVENTS ////////////////////////// + //////////////////////////////////////////////////////////// + + /** + * @notice Emitted when the socket fees are updated + * @param oldFees The old socket fees + * @param newFees The new socket fees + */ event SocketFeesUpdated(uint256 oldFees, uint256 newFees); /** @@ -26,14 +42,16 @@ contract SocketFeeManager is ISocketFeeManager, AccessControl { * @param socketFees_ Initial socket fees amount */ constructor(address owner_, uint256 socketFees_) { - emit SocketFeesUpdated(0, socketFees_); - socketFees = socketFees_; _grantRole(GOVERNANCE_ROLE, owner_); _grantRole(RESCUE_ROLE, owner_); + + socketFees = socketFees_; + emit SocketFeesUpdated(0, socketFees_); } /** * @notice Pays and validates fees for execution + * @dev This function is payable and will revert if the fees are insufficient */ function payAndCheckFees(ExecuteParams memory, TransmissionParams memory) external payable { if (msg.value < socketFees) revert InsufficientFees(); diff --git a/contracts/protocol/SocketUtils.sol b/contracts/protocol/SocketUtils.sol index 3e23ede4..303d67ab 100644 --- a/contracts/protocol/SocketUtils.sol +++ b/contracts/protocol/SocketUtils.sol @@ -25,30 +25,35 @@ abstract contract SocketUtils is SocketConfig { bytes payload; } + // address of the off-chain caller address public constant OFF_CHAIN_CALLER = address(0xDEAD); - // Prefix for trigger ID containing chain slug and address bits + // prefix for trigger ID containing chain slug and address bits uint256 private immutable triggerPrefix; - // Version string for this socket instance + // version string for this socket instance bytes32 public immutable version; - // ChainSlug for this deployed socket instance + // chain slug for this deployed socket instance uint32 public immutable chainSlug; - // @notice counter for trigger id + // counter for trigger id uint64 public triggerCounter; + /// @notice Thrown when the caller is not off-chain error OnlyOffChain(); + + /// @notice Thrown when the simulation fails error SimulationFailed(); + /// @notice Modifier to check if the caller is off-chain modifier onlyOffChain() { if (msg.sender != OFF_CHAIN_CALLER) revert OnlyOffChain(); _; } - /* - * @notice constructor for creating a new Socket contract instance. - * @param chainSlug_ The unique identifier of the chain this socket is deployed on. - * @param owner_ The address of the owner who has the initial admin role. - * @param version_ The version string which is hashed and stored in socket. + /** + * @notice constructor for creating a new Socket contract instance + * @param chainSlug_ The unique identifier of the chain this socket is deployed on + * @param owner_ The address of the owner who has the initial admin role + * @param version_ The version string which is hashed and stored in socket */ constructor(uint32 chainSlug_, address owner_, string memory version_) { chainSlug = chainSlug_; @@ -59,12 +64,13 @@ abstract contract SocketUtils is SocketConfig { } /** - * @notice creates the digest for the payload + * @notice Creates the digest for the payload * @param transmitter_ The address of the transmitter * @param payloadId_ The ID of the payload * @param appGatewayId_ The id of the app gateway * @param executeParams_ The parameters of the payload * @return The packed payload as a bytes32 hash + * @dev This function is used to create the digest for the payload */ function _createDigest( address transmitter_, @@ -91,35 +97,33 @@ abstract contract SocketUtils is SocketConfig { ); } - /** - * @notice recovers the signer from the signature - * @param digest_ The digest of the payload - * @param signature_ The signature of the payload - * @return signer The address of the signer - */ - function _recoverSigner( - bytes32 digest_, - bytes calldata signature_ - ) internal view returns (address signer) { - bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest_)); - // recovered signer is checked for the valid roles later - signer = ECDSA.recover(digest, signature_); - } - /** * @notice Encodes the trigger ID with the chain slug, socket address and nonce * @return The trigger ID + * @dev This function is used to encode the trigger ID with the chain slug, socket address and nonce */ function _encodeTriggerId() internal returns (bytes32) { return bytes32(triggerPrefix | triggerCounter++); } + /** + * @notice Simulation result + * @param success True if the simulation was successful + * @param returnData The return data from the simulation + * @param exceededMaxCopy True if the simulation exceeded the max copy bytes + */ struct SimulationResult { bool success; bytes returnData; bool exceededMaxCopy; } + /** + * @notice Simulates the payload + * @dev This function is used to simulate the payload offchain for gas estimation and checking reverts + * @param params The parameters of the simulation + * @return The simulation results + */ function simulate( SimulateParams[] calldata params ) external payable onlyOffChain returns (SimulationResult[] memory) { @@ -142,9 +146,9 @@ abstract contract SocketUtils is SocketConfig { /** * @notice Rescues funds from the contract if they are locked by mistake. This contract does not * theoretically need this function but it is added for safety. - * @param token_ The address of the token contract. - * @param rescueTo_ The address where rescued tokens need to be sent. - * @param amount_ The amount of tokens to be rescued. + * @param token_ The address of the token contract + * @param rescueTo_ The address where rescued tokens need to be sent + * @param amount_ The amount of tokens to be rescued */ function rescueFunds( address token_, diff --git a/contracts/protocol/base/PlugBase.sol b/contracts/protocol/base/PlugBase.sol index 46c9bf9b..a6eda992 100644 --- a/contracts/protocol/base/PlugBase.sol +++ b/contracts/protocol/base/PlugBase.sol @@ -9,11 +9,19 @@ import {NotSocket, SocketAlreadyInitialized} from "../../utils/common/Errors.sol /// @notice Abstract contract for plugs /// @dev This contract contains helpers for socket connection, disconnection, and overrides abstract contract PlugBase is IPlug { + // socket instance ISocket public socket__; + + // app gateway id connected to this plug bytes32 public appGatewayId; + + // tracks if socket is initialized uint256 public isSocketInitialized; + + // overrides encoded in bytes bytes public overrides; + // event emitted when plug is disconnected event ConnectorPlugDisconnected(); /// @notice Modifier to ensure only the socket can call the function @@ -41,6 +49,8 @@ abstract contract PlugBase is IPlug { ) internal { _setSocket(socket_); appGatewayId = appGatewayId_; + + // connect to the app gateway and switchboard socket__.connect(appGatewayId_, switchboardId_); } @@ -57,11 +67,18 @@ abstract contract PlugBase is IPlug { } /// @notice Sets the overrides needed for the trigger + /// @dev encoding format depends on the watcher system /// @param overrides_ The overrides function _setOverrides(bytes memory overrides_) internal { overrides = overrides_; } + /// @notice Initializes the socket + /// @dev this function should be called even if deployed independently + /// to avoid ownership and permission exploit + /// @param appGatewayId_ The app gateway id + /// @param socket_ The socket address + /// @param switchboardId_ The switchboard id function initSocket( bytes32 appGatewayId_, address socket_, diff --git a/contracts/protocol/interfaces/ICCTPSwitchboard.sol b/contracts/protocol/interfaces/ICCTPSwitchboard.sol index 796ee602..cbf8894d 100644 --- a/contracts/protocol/interfaces/ICCTPSwitchboard.sol +++ b/contracts/protocol/interfaces/ICCTPSwitchboard.sol @@ -45,14 +45,20 @@ interface ICCTPSwitchboard is ISwitchboard { /** * @notice Verifies the attestations - * @param messages_ The messages - * @param attestations_ The attestations + * @param messages_ The list of messages + * @param attestations_ The list of attestations */ function verifyAttestations( bytes[] calldata messages_, bytes[] calldata attestations_ ) external; + /** + * @notice Attests, verifies and proves the executions + * @param execParams_ The execution parameters + * @param cctpParams_ The CCTP parameters + * @param payloadId_ The payload id + */ function attestVerifyAndProveExecutions( CCTPExecutionParams calldata execParams_, CCTPBatchParams calldata cctpParams_, diff --git a/contracts/protocol/interfaces/IMessageHandler.sol b/contracts/protocol/interfaces/IMessageHandler.sol index c6c29b10..cdc4764e 100644 --- a/contracts/protocol/interfaces/IMessageHandler.sol +++ b/contracts/protocol/interfaces/IMessageHandler.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; + /** * @title IMessageHandler - * @notice Handles messages on destination domain forwarded from - * an IReceiver + * @notice Handles messages on destination forwarded from IReceiver */ interface IMessageHandler { /** - * @notice handles an incoming message from a Receiver - * @param sourceDomain the source domain of the message - * @param sender the sender of the message + * @notice Handles an incoming message from a Receiver + * @param sourceDomain The source chain slug of the message + * @param sender The sender of the message * @param messageBody The message raw bytes * @return success bool, true if successful */ diff --git a/contracts/protocol/interfaces/IMessageTransmitter.sol b/contracts/protocol/interfaces/IMessageTransmitter.sol index 427f2813..a00626f0 100644 --- a/contracts/protocol/interfaces/IMessageTransmitter.sol +++ b/contracts/protocol/interfaces/IMessageTransmitter.sol @@ -1,19 +1,44 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; +/** + * @title IMessageTransmitter + * @notice Transmits messages to a destination domain + */ interface IMessageTransmitter { + /** + * @notice Sends a message to a destination domain + * @param destinationDomain The destination domain + * @param recipient The recipient of the message + * @param messageBody The message body + * @return nonce The nonce of the message + */ function sendMessage( uint32 destinationDomain, bytes32 recipient, bytes calldata messageBody ) external returns (uint64 nonce); + /** + * @notice Receives a message from a source domain + * @param message The message body + * @param attestation The attestation + * @return success True if the message was received successfully + */ function receiveMessage( bytes calldata message, bytes calldata attestation ) external returns (bool success); + /** + * @notice Returns the local domain + * @return localDomain The local domain + */ function localDomain() external view returns (uint32); + /** + * @notice Returns the attestation manager + * @return attestationManager The attestation manager address + */ function attestationManager() external view returns (address); } diff --git a/contracts/protocol/interfaces/IPlug.sol b/contracts/protocol/interfaces/IPlug.sol index 2eb70721..f67160a4 100644 --- a/contracts/protocol/interfaces/IPlug.sol +++ b/contracts/protocol/interfaces/IPlug.sol @@ -13,6 +13,7 @@ interface IPlug { function initSocket(bytes32 appGatewayId_, address socket_, uint64 switchboardId_) external; /// @notice Gets the overrides + /// @dev encoding format depends on the watcher system /// @return overrides_ The overrides function overrides() external view returns (bytes memory overrides_); } diff --git a/contracts/protocol/interfaces/ISocket.sol b/contracts/protocol/interfaces/ISocket.sol index 04bc8d85..166c0f88 100644 --- a/contracts/protocol/interfaces/ISocket.sol +++ b/contracts/protocol/interfaces/ISocket.sol @@ -26,15 +26,15 @@ interface ISocket { /** * @notice emits the config set by a plug for a remoteChainSlug - * @param plug address of plug on current chain - * @param appGatewayId address of plug on sibling chain - * @param switchboardId outbound switchboard (select from registered options) + * @param plug The address of plug on current chain + * @param appGatewayId The address of plug on sibling chain + * @param switchboardId The outbound switchboard (select from registered options) */ event PlugConnected(address plug, bytes32 appGatewayId, uint64 switchboardId); /** * @notice emits the config set by a plug for a remoteChainSlug - * @param plug address of plug on current chain + * @param plug The address of plug on current chain */ event PlugDisconnected(address plug); @@ -56,7 +56,11 @@ interface ISocket { ); /** - * @notice executes a payload + * @notice Executes a payload + * @param executeParams_ The execution parameters + * @param transmissionParams_ The transmission parameters + * @return success True if the payload was executed successfully + * @return returnData The return data from the execution */ function execute( ExecuteParams calldata executeParams_, @@ -65,36 +69,62 @@ interface ISocket { /** * @notice sets the config specific to the plug - * @param appGatewayId_ address of plug present at sibling chain - * @param switchboardId_ the id of switchboard to use for executing payloads + * @param appGatewayId_ The address of plug present at sibling chain + * @param switchboardId_ The id of switchboard to use for executing payloads */ function connect(bytes32 appGatewayId_, uint64 switchboardId_) external; /** - * @notice disconnects Plug from Socket + * @notice Disconnects Plug from Socket */ function disconnect() external; /** - * @notice registers a switchboard for the socket + * @notice Registers a switchboard for the socket + * @return switchboardId The id of the switchboard */ function registerSwitchboard() external returns (uint64); /** - * @notice returns the config for given `plugAddress_` and `siblingChainSlug_` - * @param plugAddress_ address of plug present at current chain + * @notice Returns the config for given `plugAddress_` and `siblingChainSlug_` + * @param plugAddress_ The address of plug present at current chain + * @return appGatewayId The address of plug on sibling chain + * @return switchboardId The id of the switchboard */ function getPlugConfig( address plugAddress_ ) external view returns (bytes32 appGatewayId, uint64 switchboardId); + /** + * @notice Returns the execution status of a payload + * @param payloadId_ The payload id + * @return executionStatus The execution status + */ function payloadExecuted(bytes32 payloadId_) external view returns (ExecutionStatus); + /** + * @notice Returns the chain slug + * @return chainSlug The chain slug + */ function chainSlug() external view returns (uint32); + /** + * @notice Returns the digest of a payload + * @param payloadId_ The payload id + * @return digest The digest + */ function payloadIdToDigest(bytes32 payloadId_) external view returns (bytes32); + /** + * @notice Returns the current trigger counter + * @return triggerCounter The trigger counter + */ function triggerCounter() external view returns (uint64); + /** + * @notice Returns the switchboard address for a given switchboard id + * @param switchboardId_ The switchboard id + * @return switchboardAddress The switchboard address + */ function switchboardAddresses(uint64 switchboardId_) external view returns (address); } diff --git a/contracts/protocol/interfaces/ISocketBatcher.sol b/contracts/protocol/interfaces/ISocketBatcher.sol index 662a477e..f31782b1 100644 --- a/contracts/protocol/interfaces/ISocketBatcher.sol +++ b/contracts/protocol/interfaces/ISocketBatcher.sol @@ -5,7 +5,8 @@ import {ExecuteParams} from "../../utils/common/Structs.sol"; /** * @title ISocketBatcher - * @notice Interface for a helper contract for socket which batches attest (on sb) and execute calls (on socket). + * @notice Interface for a helper contract for socket which batches attest (on sb) + * and execute calls (on socket) */ interface ISocketBatcher { /** @@ -14,6 +15,7 @@ interface ISocketBatcher { * @param digest_ The digest of the payload * @param proof_ The proof of the payload * @param transmitterSignature_ The signature of the transmitter + * @param refundAddress_ The address to refund the fees to * @return The return data after execution */ function attestAndExecute( diff --git a/contracts/protocol/interfaces/ISocketFeeManager.sol b/contracts/protocol/interfaces/ISocketFeeManager.sol index b1029300..029379e5 100644 --- a/contracts/protocol/interfaces/ISocketFeeManager.sol +++ b/contracts/protocol/interfaces/ISocketFeeManager.sol @@ -3,11 +3,15 @@ pragma solidity ^0.8.21; import {ExecuteParams, TransmissionParams} from "../../utils/common/Structs.sol"; +/** + * @title ISocketFeeManager + * @notice Interface for the socket fee manager + */ interface ISocketFeeManager { /** * @notice Pays and validates fees for execution - * @param executeParams_ Execute params - * @param transmissionParams_ Transmission params + * @param executeParams_ The execution parameters + * @param transmissionParams_ The transmission parameters */ function payAndCheckFees( ExecuteParams memory executeParams_, @@ -16,19 +20,19 @@ interface ISocketFeeManager { /** * @notice Gets minimum fees required for execution - * @return nativeFees Minimum native token fees required + * @return nativeFees The minimum native token fees required */ function getMinSocketFees() external view returns (uint256 nativeFees); /** * @notice Sets socket fees - * @param socketFees_ New socket fees amount + * @param socketFees_ The new socket fees amount */ function setSocketFees(uint256 socketFees_) external; /** * @notice Gets current socket fees - * @return Current socket fees amount + * @return socketFees The current socket fees amount */ function socketFees() external view returns (uint256); } diff --git a/contracts/protocol/interfaces/ISwitchboard.sol b/contracts/protocol/interfaces/ISwitchboard.sol index e8518d64..f462cd18 100644 --- a/contracts/protocol/interfaces/ISwitchboard.sol +++ b/contracts/protocol/interfaces/ISwitchboard.sol @@ -17,6 +17,8 @@ interface ISwitchboard { /** * @notice Processes a trigger and creates payload + * @dev This function is called by the socket to process a trigger + * @dev sb can override this function to add additional logic * @param triggerId_ Trigger ID from socket * @param plug_ Source plug address * @param payload_ Payload data diff --git a/contracts/protocol/switchboard/FastSwitchboard.sol b/contracts/protocol/switchboard/FastSwitchboard.sol index 95a41629..3995a380 100644 --- a/contracts/protocol/switchboard/FastSwitchboard.sol +++ b/contracts/protocol/switchboard/FastSwitchboard.sol @@ -61,10 +61,13 @@ contract FastSwitchboard is SwitchboardBase { return isAttested[digest_]; } + /** + * @inheritdoc ISwitchboard + */ function processTrigger( address plug_, bytes32 triggerId_, bytes calldata payload_, bytes calldata overrides_ - ) external payable {} + ) external payable virtual {} } diff --git a/contracts/protocol/switchboard/SwitchboardBase.sol b/contracts/protocol/switchboard/SwitchboardBase.sol index a6ae97cb..43d5cf52 100644 --- a/contracts/protocol/switchboard/SwitchboardBase.sol +++ b/contracts/protocol/switchboard/SwitchboardBase.sol @@ -11,11 +11,13 @@ import {RESCUE_ROLE} from "../../utils/common/AccessRoles.sol"; /// @title SwitchboardBase /// @notice Base contract for switchboards, contains common and util functions for all switchboards abstract contract SwitchboardBase is ISwitchboard, AccessControl { + // socket contract ISocket public immutable socket__; // chain slug of deployed chain uint32 public immutable chainSlug; + // switchboard id uint64 public switchboardId; /** @@ -29,12 +31,23 @@ abstract contract SwitchboardBase is ISwitchboard, AccessControl { _initializeOwner(owner_); } + /** + * @notice Registers a switchboard on the socket + * @dev This function is called by the owner of the switchboard + */ function registerSwitchboard() external onlyOwner { switchboardId = socket__.registerSwitchboard(); } + /** + * @notice Returns the transmitter for a given payload + * @dev If the transmitter signature is provided, the function will return the signer of the signature + * @param payloadId_ The payload id + * @param transmitterSignature_ The transmitter signature (optional) + * @return transmitter The transmitter address + */ function getTransmitter( - address sender_, + address, bytes32 payloadId_, bytes calldata transmitterSignature_ ) external view returns (address transmitter) { diff --git a/contracts/utils/RescueFundsLib.sol b/contracts/utils/RescueFundsLib.sol index 738ec796..d2921df9 100644 --- a/contracts/utils/RescueFundsLib.sol +++ b/contracts/utils/RescueFundsLib.sol @@ -5,6 +5,19 @@ import "solady/utils/SafeTransferLib.sol"; import {ZeroAddress, InvalidTokenAddress} from "./common/Errors.sol"; import {ETH_ADDRESS} from "./common/Constants.sol"; +interface IERC721 { + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; +} + +interface IERC165 { + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + /** * @title RescueFundsLib * @dev A library that provides a function to rescue funds from a contract. @@ -23,7 +36,17 @@ library RescueFundsLib { SafeTransferLib.forceSafeTransferETH(rescueTo_, amount_); } else { if (token_.code.length == 0) revert InvalidTokenAddress(); - SafeTransferLib.safeTransfer(token_, rescueTo_, amount_); + + // Identify if a token is an NFT (ERC721) by checking if it supports the ERC721 interface + try IERC165(token_).supportsInterface(0x80ac58cd) returns (bool isERC721) { + if (isERC721) + IERC721(token_).safeTransferFrom(address(this), rescueTo_, amount_, ""); + else { + SafeTransferLib.safeTransfer(token_, rescueTo_, amount_); + } + } catch { + SafeTransferLib.safeTransfer(token_, rescueTo_, amount_); + } } } } diff --git a/contracts/utils/common/Errors.sol b/contracts/utils/common/Errors.sol index 40cfcf80..6b286d08 100644 --- a/contracts/utils/common/Errors.sol +++ b/contracts/utils/common/Errors.sol @@ -74,3 +74,7 @@ error InvalidData(); error InvalidSignature(); error DeadlinePassed(); +// Only Watcher can call functions +error OnlyRequestHandlerAllowed(); +error OnlyPromiseResolverAllowed(); +error InvalidReceiver(); diff --git a/deployments/dev_addresses.json b/deployments/dev_addresses.json index 800d41be..fb778f77 100644 --- a/deployments/dev_addresses.json +++ b/deployments/dev_addresses.json @@ -1,64 +1,317 @@ { + "1": { + "ContractFactoryPlug": "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", + "FastSwitchboard": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FastSwitchboardId": "1", + "FeesPlug": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "Socket": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SocketBatcher": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "startBlock": 23368199, + "SUSDC": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "SwitchboardIdToAddressMap": { + "1": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d" + } + }, + "56": { + "ContractFactoryPlug": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FastSwitchboard": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboardId": "1", + "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket": "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SocketBatcher": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "startBlock": 60248517, + "SUSDC": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SwitchboardIdToAddressMap": { + "1": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124" + } + }, + "100": { + "ContractFactoryPlug": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FastSwitchboard": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboardId": "1", + "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket": "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SocketBatcher": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "startBlock": 41989627, + "SUSDC": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SwitchboardIdToAddressMap": { + "1": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124" + } + }, + "130": { + "ContractFactoryPlug": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FastSwitchboard": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboardId": "1", + "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "startBlock": 27026358, + "SUSDC": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SwitchboardIdToAddressMap": { + "1": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450" + } + }, + "137": { + "ContractFactoryPlug": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FastSwitchboard": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboardId": "1", + "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "startBlock": 76135057, + "SUSDC": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SwitchboardIdToAddressMap": { + "1": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450" + } + }, + "146": { + "ContractFactoryPlug": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FastSwitchboard": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboardId": "1", + "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket": "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SocketBatcher": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "startBlock": 45976634, + "SUSDC": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SwitchboardIdToAddressMap": { + "1": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124" + } + }, + "169": { + "ContractFactoryPlug": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FastSwitchboard": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboardId": "1", + "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "startBlock": 6381187, + "SUSDC": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SwitchboardIdToAddressMap": { + "1": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450" + } + }, + "484": { + "ContractFactoryPlug": "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", + "FastSwitchboard": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FastSwitchboardId": "1", + "FeesPlug": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "Socket": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SocketBatcher": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "startBlock": 6540991, + "SUSDC": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "SwitchboardIdToAddressMap": { + "1": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d" + } + }, + "747": { + "ContractFactoryPlug": "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", + "FastSwitchboard": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FastSwitchboardId": "1", + "FeesPlug": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "Socket": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SocketBatcher": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "startBlock": 40319172, + "SUSDC": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "SwitchboardIdToAddressMap": { + "1": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d" + } + }, + "999": { + "ContractFactoryPlug": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FastSwitchboard": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboardId": "1", + "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "startBlock": 13754196, + "SUSDC": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SwitchboardIdToAddressMap": { + "1": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450" + } + }, + "1329": { + "ContractFactoryPlug": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FastSwitchboard": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboardId": "1", + "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "startBlock": 167855363, + "SUSDC": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SwitchboardIdToAddressMap": { + "1": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450" + } + }, + "5000": { + "ContractFactoryPlug": "0xcFb68baF734daA2b5df3eE18F1fb45c99230A2A5", + "FastSwitchboard": "0x72e8aba972EEe812d6a5C6Ab13197e884C7D8FA9", + "FastSwitchboardId": "1", + "FeesPlug": "0x0D85b9835bD1E82baeFcdb12C4D171294c64Afd2", + "Socket": "0xd8afBbB32706E7544f075151D4666D5B0B1F22CA", + "SocketBatcher": "0xb5763dC91FD626786E17b43E8808062a87b037aF", + "startBlock": 84961430, + "SUSDC": "0x6C1d46856dc8e1Fe16B1A8d0caEc720F9A58A193", + "SwitchboardIdToAddressMap": { + "1": "0x72e8aba972EEe812d6a5C6Ab13197e884C7D8FA9" + } + }, + "8453": { + "CCTPSwitchboard": "0xae59BA0Bd0D92232B3B6304185448C9Fe5445f4d", + "ContractFactoryPlug": "0xfE555AD869ac24305471F0755976c556425E8D23", + "FastSwitchboard": "0x0c17822dcC44F8202F176a4960EAC8da8FDbfCA5", + "FastSwitchboardId": "1", + "FeesPlug": "0x1eFD3AF2317B9E6E7492718878f69De747C9e7c3", + "MessageSwitchboard": "0xdaE4538FbbEf41B2Feb5c79DD2fFC9720AF13d7b", + "Socket": "0x7E33B305e12aD0E73B3aedBE67A53B7818732d7d", + "SocketBatcher": "0xfaf8a3f8f4221398F3eC765836e8BF4A3d975962", + "startBlock": 35196561, + "SUSDC": "0xbcaDE56f86a819994d0F66b98e921C484bE6FE4e", + "SwitchboardIdToAddressMap": { + "1": "0x0c17822dcC44F8202F176a4960EAC8da8FDbfCA5" + } + }, "14323": { - "AddressResolver": "0x774f608eD8fc03B05a9da51588F8571ced4c2eb2", - "AddressResolverImpl": "0x9c58dAABeBE7D6DfD8F70097c6f9c87FEC9b83DE", - "AsyncDeployer": "0xF1D3ebDF91Cf4b1bc7C9A1D78413CD1Ed2d3123d", - "AsyncDeployerImpl": "0x8daf174Be9Bb708c04b708A92b88Cc89bd223498", - "AuctionManager": "0xE4243383566fcA32aA6815dE83e8EA86b2027b8b", - "AuctionManagerImpl": "0x122beAFCfc2E99D825322a78EAFD8a11fa2d9E0b", - "Configurations": "0x6a6697A2AD51DB9a41BaEE78e194335c1aD7369d", - "ConfigurationsImpl": "0x8A9256F31b0bb85863c253F8CAE800A32Cb2d595", - "DeployForwarder": "0xE986bCd19b8725ea3417C2A7728158ecABA6C8bE", - "DeployForwarderImpl": "0xfBe803842B50d8A2a91DA3dD88B67E92D5C0bd97", + "AddressResolver": "0xcA99D298B5290558660b4D5C1019Be145FaB6020", + "AddressResolverImpl": "0x39b5D3FBBa1BC28438e25955aaB412C7576eCd61", + "AsyncDeployer": "0xd608e1345281dE0675e2Cc1E8D0B31aD167618Ad", + "AsyncDeployerImpl": "0x2F0E83Fcd03A191D280598c33d278AF8A7e9076a", + "AsyncPromiseImpl": "0x6562a549cf5545E74D5D98e5E453d4aD1516Af01", + "AuctionManager": "0xED848E9e0CCA0868484353B529E04861Fd8F04Bd", + "AuctionManagerImpl": "0x2752caa4060bC744216515c247C54Ae5bB873DF2", + "Configurations": "0xf50A9785aef5ADeA0659609e9FF1de8578aF0b4f", + "ConfigurationsImpl": "0xa1780f9F81090737267ccd3A5663E058AfE73A49", + "DeployForwarder": "0xffF606007317cb7a1CC4C701d62C38c7734dfb15", + "DeployForwarderImpl": "0x69e3Dc5667f7413039fE3bFd335660A99DA869A9", "ERC1967Factory": "0x4f1Cd0CdBc7EA445b8B34Af8844fA4D4B5f48b79", - "FeesManager": "0xa6D93e7B2cde3C8d318f45890dE3dB0a2E54058B", - "FeesManagerImpl": "0x38A7558D2C3b4097c2098444a46D625D51E7336F", + "FeesManager": "0xbCFf8224d89f0b4e9B14c4356720439111BAC2bC", + "FeesManagerImpl": "0x62FB943442E577901Ad42Da5c64aaf850B43049c", "FeesPool": "0x13A3018920c7b56B20dd34E29C298121025E6de4", - "PromiseResolver": "0x40834274ee715B1748e450A67cFf2B52b0388eC3", - "ReadPrecompile": "0xE693bEc40e39223749AC351156E713b7256541B0", - "RequestHandler": "0xE785Fdbd049D0647e8B2Bd28C75a679dEBaD9D6f", - "RequestHandlerImpl": "0x5332d341cd7B423C2f75AF7Ca295455e5F08fAcb", - "SchedulePrecompile": "0x99af65efe676C4899F6e500DF18d4fD84dbe0A1D", - "startBlock": 10904, - "Watcher": "0x96ACe2d4a36a1Fd6e3eeE1cD3FeDA36eA62E3064", - "WatcherImpl": "0xE5542FAB56B652A95aBD05a08E920687d1ef3849", - "WritePrecompile": "0x27794dd1166ED0c6A70c655C297BB79bF06bf44A", - "WritePrecompileImpl": "0xc2Ca571f4d4C2008Da4Bd750BaD3d50A5705ffF8" + "ForwarderImpl": "0x7910516d549ade46Fdc4165a0BFD0cFC631e2b02", + "PromiseResolver": "0xed318668898303141EA6B9c2a9F97D0622b0a530", + "ReadPrecompile": "0x7C82C3d2aE1bFB4b1D294e5181bCd7489EF554d1", + "RequestHandler": "0xf053AB14323FF52e7e65D6Fb12f86896F0865a36", + "RequestHandlerImpl": "0x4904A0f8E054f2cd6594a0e1BAB4583DF43d2e49", + "SchedulePrecompile": "0x4660c5fF2762E688f8D0def828ad161AE4940F57", + "startBlock": 46937, + "Watcher": "0xCeEc354B7784C667Bd661483Ae30C8d4eBA96e1d", + "WatcherImpl": "0xce594728977675546d5da6152a076179982F1D39", + "WritePrecompile": "0x9a580f1A4AE6A37CCEe73261B796F85EFbE55B15", + "WritePrecompileImpl": "0x41882aff9F7575473e5B6E613B371d04bdCCC728" + }, + "43114": { + "CCTPSwitchboard": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug": "0x302E258fe375A1da4d6B3F4Dd5208638A29bc409", + "FastSwitchboard": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "FastSwitchboardId": "1", + "FeesPlug": "0x3aac37DC85C522c09A3DDdA44D181E6aCCD2f9F0", + "MessageSwitchboard": "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", + "Socket": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "SocketBatcher": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "startBlock": 68322256, + "SUSDC": "0x313397aE9B6c22AC0e00d039543AE425b1F1c039", + "SwitchboardIdToAddressMap": { + "1": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD" + } + }, + "57073": { + "ContractFactoryPlug": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FastSwitchboard": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboardId": "1", + "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "startBlock": 24276129, + "SUSDC": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SwitchboardIdToAddressMap": { + "1": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450" + } + }, + "59144": { + "ContractFactoryPlug": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FastSwitchboard": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboardId": "1", + "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket": "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SocketBatcher": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "startBlock": 23003201, + "SUSDC": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SwitchboardIdToAddressMap": { + "1": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124" + } + }, + "80094": { + "ContractFactoryPlug": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FastSwitchboard": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboardId": "1", + "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "startBlock": 10433014, + "SUSDC": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SwitchboardIdToAddressMap": { + "1": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450" + } + }, + "84532": { + "CCTPSwitchboard": "0x9175d90706a2b17f0aE025ce5A6C76e64850c2f5", + "ContractFactoryPlug": "0xf8a9d637cd6fAf3d4C17277DceadbEE69d7752f0", + "FastSwitchboard": "0xE09CC429e77EE5DBeF68f3796b2A33BBDF39C03C", + "FastSwitchboardId": "1", + "FeesPlug": "0x3D7515519beab77B541497626CFB7E764F6887CD", + "MessageSwitchboard": "0xe7858f1dc202f5E9C9B3ee6db052F45164a88534", + "Socket": "0x22B521c3610D373Ea29698215eB78907Ad98B644", + "SocketBatcher": "0x26565cAeA64c78Dc7cB4158e7612451Db436A0c6", + "startBlock": 30707073, + "SUSDC": "0x01bDCAB43c423D08BaCe87ED716280536dAB3eF3", + "SwitchboardIdToAddressMap": { + "1": "0xE09CC429e77EE5DBeF68f3796b2A33BBDF39C03C" + } }, "421614": { - "CCTPSwitchboard": "0xaF912b7eaD59f5d8c8179f8606A3fa93459a612C", + "CCTPSwitchboard": "0x0355064bBb553A3765af498004749fB2e19284c0", "CCTPSwitchboardId": "2", - "ContractFactoryPlug": "0x2784a207d51DD8c1A5323C05Fb868B68a854326C", - "FastSwitchboard": "0xd8DDEA0c49C0bcbFD31272c262a4b31FfB44a8Bc", + "ContractFactoryPlug": "0x106A3205827D94d804CF7823B82E6742ED38D863", + "FastSwitchboard": "0x36620137587b544A8235C080067B3c439ae1c7d7", "FastSwitchboardId": "1", - "FeesPlug": "0x3CFe3e7eCc62232B3d29454DCABeE4f2B921e3a2", - "MessageSwitchboard": "0x0C049f6Dd92eA5dA05058b9B309755Cb347587C9", + "FeesPlug": "0x9Fd89116E514142C04aE72824E2A7dC26F311655", + "MessageSwitchboard": "0x060493ac77c630f4d307Df9bb9bF32cE7462eb70", "MessageSwitchboardId": "3", - "Socket": "0x90c5210fcFbFF7DA5753F3ddAEBee4102b8d6A9B", - "SocketBatcher": "0xd726FeF96aD21AAD24443FAE933DDa9c79716a93", - "startBlock": 178158322, + "Socket": "0x0da062CDB868A30CbB6314074202d67e4eAaBa51", + "SocketBatcher": "0x18433B14d10Ee05D007e00f897B40696d6fC56f6", + "startBlock": 185630714, + "SUSDC": "0x7F7ad06B15cFe9ebE45b01C694205CdB64e8F56d", + "SwitchboardIdToAddressMap": { + "1": "0x36620137587b544A8235C080067B3c439ae1c7d7" + } + }, + "747474": { + "ContractFactoryPlug": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FastSwitchboard": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboardId": "1", + "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket": "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SocketBatcher": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "startBlock": 10442238, + "SUSDC": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", "SwitchboardIdToAddressMap": { - "1": "0xd8DDEA0c49C0bcbFD31272c262a4b31FfB44a8Bc", - "2": "0xaF912b7eaD59f5d8c8179f8606A3fa93459a612C", - "3": "0x0C049f6Dd92eA5dA05058b9B309755Cb347587C9" + "1": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124" } }, "11155420": { - "CCTPSwitchboard": "0x1801b7e2E553c7233c2fd7c9e8647f6b91ff7a76", + "CCTPSwitchboard": "0x56EaDAC97B54C0c7979Bd620cad389eC3476dB43", "CCTPSwitchboardId": "2", - "ContractFactoryPlug": "0xC5B314127DFa001f00e5773EA55765A9007320a6", - "FastSwitchboard": "0x9f1DE81ff3274eD6678a5A1644F430b06EF0992D", + "ContractFactoryPlug": "0x253be2E93EadAD9D2802D83A26eE62E911F1E3fe", + "FastSwitchboard": "0x2cC155961F225AbFF5e64F4a8f9C4f59b2339172", "FastSwitchboardId": "1", - "FeesPlug": "0x72708A701Fa94B8a1746c2ED1A1dd41C56dA7b33", - "MessageSwitchboard": "0xE3756057aEd63488Acbfa6DC31a3E99bFBcf0d4A", + "FeesPlug": "0x83Ad3d17493Bdc31C60344021CA93E8dD3666A2A", + "MessageSwitchboard": "0x9efC6D7050eF4F5b12205A32ceE49F456FFB6FA8", "MessageSwitchboardId": "3", - "Socket": "0xbc47b9BeBBf72Cf5a08c3b0381acFc2c754dA073", - "SocketBatcher": "0x87C9a09e05D0D2A885eb7B2644c3CBB8E70763b6", - "startBlock": 30946234, + "Socket": "0x631f1E974442d6d51B626cE27d0D7629F1C0aB38", + "SocketBatcher": "0x4b2942C43579C3a9405887CDFA2F2048a5bE91EE", + "startBlock": 32643803, + "SUSDC": "0x40F2CfE35134141F809582ad121BF23522b5Dd22", "SwitchboardIdToAddressMap": { - "1": "0x9f1DE81ff3274eD6678a5A1644F430b06EF0992D", - "2": "0x1801b7e2E553c7233c2fd7c9e8647f6b91ff7a76", - "3": "0xE3756057aEd63488Acbfa6DC31a3E99bFBcf0d4A" + "1": "0x2cC155961F225AbFF5e64F4a8f9C4f59b2339172" } } } diff --git a/deployments/dev_verification.json b/deployments/dev_verification.json index 3b3f4600..3b1f2c3b 100644 --- a/deployments/dev_verification.json +++ b/deployments/dev_verification.json @@ -1,121 +1,1131 @@ { - "14323": [], - "421614": [], - "7625382": [ + "1": [ [ - "0x8DA71DE564096Ea4A43E794E1dEcA8F1692B69D7", - "FeesManager", - "contracts/evmx/fees/FeesManager.sol", - [] + "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x13A3018920c7b56B20dd34E29C298121025E6de4", - "FeesPool", - "contracts/evmx/fees/FeesPool.sol", - ["0xb62505feacC486e809392c65614Ce4d7b051923b"] + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SUSDC", + "SUSDC" + ] ], [ - "0xC3f93140EF2f57a87FDdCe7DdADB544873b67C7D", - "FeesManager", - "contracts/evmx/fees/FeesManager.sol", - [] + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 1, + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "Socket", + "contracts/protocol/Socket.sol", + [1, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "56": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 56, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" + ] + ], + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "Socket", + "contracts/protocol/Socket.sol", + [56, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "100": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 100, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" + ] + ], + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "Socket", + "contracts/protocol/Socket.sol", + [100, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "130": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 130, + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "Socket", + "contracts/protocol/Socket.sol", + [130, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "137": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 137, + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "Socket", + "contracts/protocol/Socket.sol", + [137, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "146": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 146, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" + ] + ], + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "Socket", + "contracts/protocol/Socket.sol", + [146, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "169": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 169, + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "Socket", + "contracts/protocol/Socket.sol", + [169, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "484": [ + [ + "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SUSDC", + "SUSDC" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 484, + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "Socket", + "contracts/protocol/Socket.sol", + [484, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "747": [ + [ + "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SUSDC", + "SUSDC" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 747, + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "Socket", + "contracts/protocol/Socket.sol", + [747, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "999": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 999, + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "Socket", + "contracts/protocol/Socket.sol", + [999, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "1329": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 1329, + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "Socket", + "contracts/protocol/Socket.sol", + [1329, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "5000": [ + [ + "0xcFb68baF734daA2b5df3eE18F1fb45c99230A2A5", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xd8afBbB32706E7544f075151D4666D5B0B1F22CA", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x6C1d46856dc8e1Fe16B1A8d0caEc720F9A58A193", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xd8afBbB32706E7544f075151D4666D5B0B1F22CA", + "SUSDC", + "SUSDC" + ] + ], + [ + "0x0D85b9835bD1E82baeFcdb12C4D171294c64Afd2", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xd8afBbB32706E7544f075151D4666D5B0B1F22CA", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x72e8aba972EEe812d6a5C6Ab13197e884C7D8FA9", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 5000, + "0xd8afBbB32706E7544f075151D4666D5B0B1F22CA", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xb5763dC91FD626786E17b43E8808062a87b037aF", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xd8afBbB32706E7544f075151D4666D5B0B1F22CA" + ] + ], + [ + "0xd8afBbB32706E7544f075151D4666D5B0B1F22CA", + "Socket", + "contracts/protocol/Socket.sol", + [5000, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ], + [ + "0xeAb2e310A53FD3Fb34C2944690a79DFB2e834F20", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x1D530df25aE08F7A440CA155c9d53540C2c50A82", - "SchedulePrecompile", - "contracts/evmx/watcher/precompiles/SchedulePrecompile.sol", + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", [ - "0x90B2f8766F47E0A108D85DC43Ddb45A1d5e486FB", - 86400, - { - "type": "BigNumber", - "hex": "0x02540be400" - }, - { - "type": "BigNumber", - "hex": "0xe8d4a51000" - }, - 3600 + 5000, + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0x8D8770876e587300828Bc2B235C89F06CE473170", - "ReadPrecompile", - "contracts/evmx/watcher/precompiles/ReadPrecompile.sol", + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", [ - "0x90B2f8766F47E0A108D85DC43Ddb45A1d5e486FB", - { - "type": "BigNumber", - "hex": "0xe8d4a51000" - }, - 3600 + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38" ] ], [ - "0x4F1FB4E9169f4A604e3eb9833987338D48B8Dd77", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "Socket", + "contracts/protocol/Socket.sol", + [5000, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "8453": [], + "14323": [ + [ + "0x41882aff9F7575473e5B6E613B371d04bdCCC728", "WritePrecompile", "contracts/evmx/watcher/precompiles/WritePrecompile.sol", [] ], [ - "0xe0047f9b97c4C73948fe23F1bA807FE7906040C0", - "PromiseResolver", - "contracts/evmx/watcher/PromiseResolver.sol", - ["0x90B2f8766F47E0A108D85DC43Ddb45A1d5e486FB"] + "0xdBDA5D873b120f1C5E0966BFA3C588dDBECc9072", + + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + [] + ], + [ + "0x2Bc1E6d31B1eabe4a11286c08aa67eCA29A55cc3", + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + [] ], [ - "0x95aB9c53FDa2ad009B6698d814735D0030796805", + "0x751085cA028D2BCfC58Cee2514DeF1ed72c843cd", "RequestHandler", "contracts/evmx/watcher/RequestHandler.sol", + "0x2996bD0DCB7C349340715472518E76342AC31b1a", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", [] ], [ - "0xbb163A49239260a5BE19f6aD9B5839f11F6aC24F", - "Configurations", - "contracts/evmx/watcher/Configurations.sol", + "0xEd2a3cd034D873096E40C7E2EfB0e5BE99bBbF7a", + "PromiseResolver", + "contracts/evmx/watcher/PromiseResolver.sol", + ["0xCeEc354B7784C667Bd661483Ae30C8d4eBA96e1d"] + ], + [ + "0x2ECF118De0d747980c5d934E78a5746B6b6fD441", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", [] ], [ - "0x2682de36DFBf618dBEdFa4d18c265bdc04F7C9bb", - "DeployForwarder", - "contracts/evmx/helpers/DeployForwarder.sol", + "0x751085cA028D2BCfC58Cee2514DeF1ed72c843cd", + "RequestHandler", + "contracts/evmx/watcher/RequestHandler.sol", [] ], [ - "0x32a6E6F8c09823d8F8ddB285346b2c61Ed1F03b8", - "AuctionManager", - "contracts/evmx/AuctionManager.sol", + "0x9b962E99fbc77aF1733CdE3bC65F1Cd621d4FDEF", + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", [] ], [ - "0x26d5DFaaB493292c7d2Cc8C1eD447bd944127935", + "0x52fEa0aBEe0CC6CBf46099a9886Ed0C123241fDc", "Watcher", "contracts/evmx/watcher/Watcher.sol", [] ], [ - "0xcdbA9Ad5Da86d61a69ea94a52210C1f2008A849f", - "AsyncDeployer", - "contracts/evmx/helpers/AsyncDeployer.sol", + "0x0f832af23F7fc3332396f73caAB2Fa44A6d3aFFC", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", [] + ] + ], + "43114": [ + [ + "0x302E258fe375A1da4d6B3F4Dd5208638A29bc409", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0xBD3d78023FAf3590fFcF65013b5cC058Efeb13C8", - "FeesManager", - "contracts/evmx/fees/FeesManager.sol", - [] + "0x313397aE9B6c22AC0e00d039543AE425b1F1c039", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "SUSDC", + "SUSDC" + ] ], [ - "0x8fa6EF5A80E4Eca1302d2dfB85ae151275a4eA6A", - "AddressResolver", - "contracts/evmx/helpers/AddressResolver.sol", - [] + "0x3aac37DC85C522c09A3DDdA44D181E6aCCD2f9F0", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x32767D5390C2CD3619799c66f9F4E426c317Cd2F", - "ERC1967Factory", - "lib/solady/src/utils/ERC1967Factory.sol", - [] + "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", + "MessageSwitchboard", + "contracts/protocol/switchboard/MessageSwitchboard.sol", + [ + 43114, + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "CCTPSwitchboard", + "contracts/protocol/switchboard/CCTPSwitchboard.sol", + [ + 43114, + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x8186359aF5F57FbB40c6b14A588d2A59C0C29880" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 43114, + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "Socket", + "contracts/protocol/Socket.sol", + [43114, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" + ] + ], + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "Socket", + "contracts/protocol/Socket.sol", + [43114, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "57073": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 57073, + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "Socket", + "contracts/protocol/Socket.sol", + [57073, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "59144": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 59144, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" + ] + ], + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "Socket", + "contracts/protocol/Socket.sol", + [59144, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "80094": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 80094, + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "Socket", + "contracts/protocol/Socket.sol", + [80094, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "84532": [], + "421614": [], + "747474": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 747474, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" + ] + ], + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "Socket", + "contracts/protocol/Socket.sol", + [747474, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ] ], "11155420": [] diff --git a/deployments/prod_addresses.json b/deployments/prod_addresses.json new file mode 100644 index 00000000..7fa6d2c2 --- /dev/null +++ b/deployments/prod_addresses.json @@ -0,0 +1,290 @@ +{ + "1": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 23384432, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "10": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 141266670, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "56": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 61510453, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "100": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 42253473, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "130": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 27383897, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "137": { + "ContractFactoryPlug": "0x9e95545a13351aA79096839738d0B09434804D03", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 76569494, + "SUSDC": "0xdb6d9dB6e4190a63FD3c50Af51785a9c3BB4080b", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "146": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 47181499, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "169": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 6390809, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "484": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 6737511, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "747": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 40559259, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "999": { + "ContractFactoryPlug": "0xdb6d9dB6e4190a63FD3c50Af51785a9c3BB4080b", + "FastSwitchboard": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "FastSwitchboardId": "1", + "FeesPlug": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "Socket": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "SocketBatcher": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "startBlock": 14120257, + "SUSDC": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "SwitchboardIdToAddressMap": { + "1": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15" + } + }, + "1329": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 168597971, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "5000": { + "ContractFactoryPlug": "0xaeCC411d7230e4dAFa6dB9931a3bEf37764476a1", + "FastSwitchboard": "0x2277CF90Ce1cfE33b9576Ec06D9C4d053ee5f882", + "FastSwitchboardId": "1", + "FeesPlug": "0xFB349dcc5A1cB87Ff3A2b91C343814647AE820FC", + "Socket": "0xb8Bd628646BFfE5632B462F213F97DE038dBD8b2", + "SocketBatcher": "0x334A27A9aBe4413CD3fE7EF777196eE0568b29D4", + "startBlock": 85006520, + "SUSDC": "0xe03f198c6Abee720b1a344d6624f7014c0F663E1", + "SwitchboardIdToAddressMap": { + "1": "0x2277CF90Ce1cfE33b9576Ec06D9C4d053ee5f882" + } + }, + "8453": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 35670115, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "12921": { + "AddressResolver": "0x3d6EB76db49BF4b9aAf01DBB79fCEC2Ee71e44e2", + "AddressResolverImpl": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "AsyncDeployer": "0xFA19dDA03A79f8Aef83C0505BF70ECa0Ac42608E", + "AsyncDeployerImpl": "0xb3A5132Df72F1597ab474d73d387ecF8647af669", + "AsyncPromiseImpl": "0xe2B1A11E8473095581DEF8d9D11eC63BBdd62ceE", + "AuctionManager": "0xcd5e9029a73890A5A3146bAddd272D65ac11521c", + "AuctionManagerImpl": "0xB604FBcA01897315D2d62A346DBf29796A4825D9", + "Configurations": "0x71B89bA78B9431d4E984893cD6885d39AD6c3c7A", + "ConfigurationsImpl": "0x117c63A8c9a980ddC60B2bF2b4701C9267f66394", + "DeployForwarder": "0xb6E6e6FCd2636B83C443628f3f5e42cB5Fcd44fD", + "DeployForwarderImpl": "0xf05f680E0611b81eD0255A1Cd829540504765711", + "ERC1967Factory": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FeesManager": "0xB63ab15c208A16a0480036C06e8828A4682E0B34", + "FeesManagerImpl": "0x9f3CDba2262DF94e415E092A4228ee7E6846ea1b", + "FeesPool": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "ForwarderImpl": "0xB1a504eC5C2d8206Fc73a46EeF5E5018585Eb240", + "PromiseResolver": "0xFB349dcc5A1cB87Ff3A2b91C343814647AE820FC", + "ReadPrecompile": "0x74D52027137a450b68315478AAE4528Ba839ea13", + "RequestHandler": "0x3C183Ad26A11A6691d43D031Fae3D51DaDC643Df", + "RequestHandlerImpl": "0x0303B6f54afA36B0808FDE6aaE9c3eD271b01119", + "SchedulePrecompile": "0xEE7b72D53FeC4Bed9F56CcEaD49217d152A22aC5", + "startBlock": 41, + "Watcher": "0x2566Bef2e914c7482d6FCB4955403fb0865951A5", + "WatcherImpl": "0x03029500B038980745c5a671f271340CF9AF5830", + "WritePrecompile": "0xc6506b1C3f34297B4de32f08d8d50CB0E9e64842", + "WritePrecompileImpl": "0xcd460687fe2a74ddEE8f2E3d791e1df306713353" + }, + "42161": { + "ContractFactoryPlug": "0x176C18F871b9b0F363cBDF3b5a1872F6069CF538", + "FastSwitchboard": "0xb3A5132Df72F1597ab474d73d387ecF8647af669", + "FastSwitchboardId": "1", + "FeesPlug": "0x168d7bAb883a6430F0200bcaaFAf080371477B3D", + "Socket": "0xdb6d9dB6e4190a63FD3c50Af51785a9c3BB4080b", + "SocketBatcher": "0x9e95545a13351aA79096839738d0B09434804D03", + "startBlock": 380165474, + "SUSDC": "0x6d5B9B5aeC995F0CeE2dfbba3bdCc70698F2600d", + "SwitchboardIdToAddressMap": { + "1": "0xb3A5132Df72F1597ab474d73d387ecF8647af669" + } + }, + "43114": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 68887506, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "57073": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 24633467, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "59144": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 23661748, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + }, + "80094": { + "ContractFactoryPlug": "0xdb6d9dB6e4190a63FD3c50Af51785a9c3BB4080b", + "FastSwitchboard": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "FastSwitchboardId": "1", + "FeesPlug": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "startBlock": 10646345, + "SUSDC": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "SwitchboardIdToAddressMap": { + "1": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15" + } + }, + "747474": { + "ContractFactoryPlug": "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "FastSwitchboard": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboardId": "1", + "FeesPlug": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "Socket": "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SocketBatcher": "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "startBlock": 11389173, + "SUSDC": "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SwitchboardIdToAddressMap": { + "1": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA" + } + } +} diff --git a/deployments/prod_verification.json b/deployments/prod_verification.json new file mode 100644 index 00000000..d644ddec --- /dev/null +++ b/deployments/prod_verification.json @@ -0,0 +1,149 @@ +{ + "1": [], + "10": [], + "56": [], + "100": [], + "130": [], + "137": [], + "146": [], + "169": [ + [ + "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C" + ] + ], + [ + "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C", + "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SUSDC", + "SUSDC" + ] + ], + [ + "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C" + ] + ], + [ + "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 169, + "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C" + ] + ], + [ + "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C", + "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb" + ] + ], + [ + "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "Socket", + "contracts/protocol/Socket.sol", + [169, "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C", "EVMX"] + ] + ], + "484": [], + "747": [ + [ + "0xd90a33b0414F5C0De5F315428190598945BbEde2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C" + ] + ], + [ + "0xe37aFa3Aa95E153B8dD0FE8456CBF345cB4C51F7", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C", + "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "SUSDC", + "SUSDC" + ] + ], + [ + "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C" + ] + ], + [ + "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 747, + "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C" + ] + ], + [ + "0x20BB708875C3E99cbBD7239CeeB2670b795F4829", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C", + "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb" + ] + ], + [ + "0xB94742B094f89A8D53e15A45CdBf9810a5B090Eb", + "Socket", + "contracts/protocol/Socket.sol", + [747, "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C", "EVMX"] + ] + ], + "999": [], + "1329": [], + "5000": [ + [ + "0xb8Bd628646BFfE5632B462F213F97DE038dBD8b2", + "Socket", + "contracts/protocol/Socket.sol", + [5000, "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C", "EVMX"] + ] + ], + "8453": [], + "12921": [ + [ + "0xb8613c3BfF759Bd4596DBf4e7a57195f08454EFB", + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + [] + ] + ], + "42161": [], + "43114": [], + "57073": [], + "59144": [], + "80094": [], + "747474": [] +} diff --git a/deployments/stage_addresses.json b/deployments/stage_addresses.json index ffd2c9e3..fcab9ac1 100644 --- a/deployments/stage_addresses.json +++ b/deployments/stage_addresses.json @@ -1,133 +1,108 @@ { "10": { - "CCTPSwitchboard": "0x8d1aAf3c24D221aE30E069136C8B1e305d7668Dc", - "CCTPSwitchboardId": "2", - "ContractFactoryPlug": "0xd8afBbB32706E7544f075151D4666D5B0B1F22CA", - "FastSwitchboard": "0xDa17184a5DE13B731C7F06ED147a6048eD6f9EEA", + "ContractFactoryPlug": "0xC559BABEbcD92278E91a545308190E4761efc347", + "FastSwitchboard": "0xD78f99D62BeaF0918bB0601C68EB537b6703Ce63", "FastSwitchboardId": "1", - "FeesPlug": "0x375b8c18b57DbAA5146cdCb4a8154Ff2eCc238D6", - "MessageSwitchboard": "0xD9803F3A7F2b7Ce185daAaC94EFE00B30F0f9fab", - "MessageSwitchboardId": "3", - "Socket": "0x79EB309890F4A797816478dB7D9d57A1e63CeeC2", - "SocketBatcher": "0xe31C4265Cb0E22663164172B055Ac25281adfb66", - "startBlock": 139061413, + "FeesPlug": "0xA557EBE094F939ae6eE8F18c8F88D06182168786", + "Socket": "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", + "SocketBatcher": "0x06234dB2D69Ac158793a3ce59c3764422028E964", + "startBlock": 141180188, + "SUSDC": "0x6D54668ba18B425a1DbFC0BD720145c0aeE97f65", "SwitchboardIdToAddressMap": { - "1": "0xDa17184a5DE13B731C7F06ED147a6048eD6f9EEA", - "2": "0x8d1aAf3c24D221aE30E069136C8B1e305d7668Dc", - "3": "0xD9803F3A7F2b7Ce185daAaC94EFE00B30F0f9fab" + "1": "0xD78f99D62BeaF0918bB0601C68EB537b6703Ce63" } }, "8453": { - "CCTPSwitchboard": "0x72e8aba972EEe812d6a5C6Ab13197e884C7D8FA9", - "CCTPSwitchboardId": "2", - "ContractFactoryPlug": "0xcFb68baF734daA2b5df3eE18F1fb45c99230A2A5", - "FastSwitchboard": "0xb5763dC91FD626786E17b43E8808062a87b037aF", + "ContractFactoryPlug": "0x2e531e37FdccA3CFd427a593f53f326bd24b8142", + "FastSwitchboard": "0xd3009795fFDc64Ee0d23198772a58ca9e53EEd25", "FastSwitchboardId": "1", - "FeesPlug": "0x6C1d46856dc8e1Fe16B1A8d0caEc720F9A58A193", - "MessageSwitchboard": "0x0D85b9835bD1E82baeFcdb12C4D171294c64Afd2", - "MessageSwitchboardId": "3", - "Socket": "0x375b8c18b57DbAA5146cdCb4a8154Ff2eCc238D6", - "SocketBatcher": "0xd8afBbB32706E7544f075151D4666D5B0B1F22CA", - "startBlock": 33466371, + "FeesPlug": "0xFAF76924169cf58f239d02EC40a2a1eA9eaeb62E", + "Socket": "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9", + "SocketBatcher": "0x356DBc19C69832010f92c963a8Ded6b5f9deeaCe", + "startBlock": 35584928, + "SUSDC": "0x900Cf1914Adcee43Cb1A69c042ded801Cd5051Ef", "SwitchboardIdToAddressMap": { - "1": "0xb5763dC91FD626786E17b43E8808062a87b037aF", - "2": "0x72e8aba972EEe812d6a5C6Ab13197e884C7D8FA9", - "3": "0x0D85b9835bD1E82baeFcdb12C4D171294c64Afd2" + "1": "0xd3009795fFDc64Ee0d23198772a58ca9e53EEd25" } }, "14323": { - "AddressResolver": "0xAA77c2dE14CfFF4244a127deED6b53ce79481e14", - "AddressResolverImpl": "0xe857a826D330Fc0429c67FaBEB8B66C26ea1DD5f", - "AsyncDeployer": "0x24c3f774c231ADFeb5e22Ad826a666A0FF9742C8", - "AsyncDeployerImpl": "0xB7Bf09935108753491E59114dc0B713cDa6F703F", - "AuctionManager": "0xd5853f69f5dE728AEF7d1cF029cB3bF1581A4ED4", - "AuctionManagerImpl": "0x89A0D4550D5aFa809B74856624D4595188641BCe", - "Configurations": "0x0f2801ee741A3BdeA2245d97AB54B1C4d7734534", - "ConfigurationsImpl": "0xD41d93042Dd1aB8c712C212A6907d4dC0718D021", - "DeployForwarder": "0x54676a772aEe69E3F87178F2b5E4414dcE9A9720", - "DeployForwarderImpl": "0x9882ce57b618175Bd9d3a4eC50ebD682B39bc467", - "ERC1967Factory": "0x61788F19CA1b098cE8437f8eb13B1Ad68f4FcD77", - "FeesManager": "0x9339e8D915Aaf467d2fC01a4e694c8FE85621e94", - "FeesManagerImpl": "0x27b763c5410E83c02F21D97B33555729B77B2Ce1", + "AddressResolver": "0xE4C438c46b9dB51e298A1F65151eDe8418be009A", + "AddressResolverImpl": "0x241532190C8b549Ebb4CE7624454A47c1cC97171", + "AsyncDeployer": "0x08c2DFE559288e9fBfB440E68033BE9BB666142E", + "AsyncDeployerImpl": "0x148182E16aaf2Fd6137D0eb335c3f6c8266e0936", + "AsyncPromiseImpl": "0x5D073b79a9eC87dB8846eB2891594D5A26d88b0E", + "AuctionManager": "0xa6610D1bFb6F791eDaeBAdFc43e2415f16844929", + "AuctionManagerImpl": "0x4B8B34e439EBAB00116B1b4C642923b6A227AdCa", + "Configurations": "0x6c289e8b8A8Ac6965440Cd23f2Db8C810f2336F9", + "ConfigurationsImpl": "0x30240731147d217Bf228EC68104eb8664A377c33", + "DeployForwarder": "0x015BB35B075FACBED756C9403c4A6BAfF37328D7", + "DeployForwarderImpl": "0xD4DB3AB70EBA19586132686fBD4928809c3e42B4", + "ERC1967Factory": "0x945300e92aA450A9aEf1d9FBA7b7Aee45622a082", + "FeesManager": "0xB3a34AB69B538d48311656a4b5df56A1423C0075", + "FeesManagerImpl": "0xF31EF92126D4f20799dEb3b2F17Cc64B3272DEc8", "FeesPool": "0xC8d803B7c1719cdF21392405879D1B56398045C4", - "PromiseResolver": "0x9BE3513a5d32E74935a54e5516b4daa198da5574", - "ReadPrecompile": "0x784730D5e5D2F64eA63BfafeDC759317438c9186", - "RequestHandler": "0x22FaddfD47B9E0B545f83a2E7Cd05c12889c7a57", - "RequestHandlerImpl": "0xAA6EfF8dbd53B8d95a02c59Fe5C8A8422B08F5AA", - "SchedulePrecompile": "0x074118aB15e54A84b42Ff3de5233721434cF9f55", - "startBlock": 11040, - "Watcher": "0xdd25a87AeB5bCEeBAc0EB27aFfaBB6eB5a2857ca", - "WatcherImpl": "0xb143810f13fDF66F7a9B973252AEC80ec47FF0cb", - "WritePrecompile": "0x66ce424303EC8499C5cdC4F6437A0434D8bd9b81", - "WritePrecompileImpl": "0x962E1db23f6C5879A5c9D58CcB8c67CD282F1000" + "ForwarderImpl": "0x639b0f7101B525f3e88208f703F7D4Bba67c39ff", + "PromiseResolver": "0xD5225A5BC7ef3eAc6eb5255776fF5F007C95D03E", + "ReadPrecompile": "0xD059D6D64B9dbAE2e56F70CBEc9Af03fd41DaE35", + "RequestHandler": "0xEd8f50ddf6ba832c699b019Ed62f86e511b72d53", + "RequestHandlerImpl": "0x4f4655Bf2aDf5Ce1b58205942c77C9549bafbEd7", + "SchedulePrecompile": "0x62Be6a0eabce7Efb1B9BB065e36b85C63B2101c6", + "startBlock": 50623, + "Watcher": "0xdd4B3431472573dB6dB988E8746a118005328589", + "WatcherImpl": "0x8BB97CaF2B6C94d4f3988cdBC2db6e9eeF12D857", + "WritePrecompile": "0xE786f01425718D52F7C0753FbDF743b56704D31f", + "WritePrecompileImpl": "0xD3E77f10D63031111599CB32C957CA703ec479b8" }, "42161": { - "CCTPSwitchboard": "0xd8afBbB32706E7544f075151D4666D5B0B1F22CA", - "CCTPSwitchboardId": "2", - "ContractFactoryPlug": "0x0D85b9835bD1E82baeFcdb12C4D171294c64Afd2", - "FastSwitchboard": "0x375b8c18b57DbAA5146cdCb4a8154Ff2eCc238D6", + "ContractFactoryPlug": "0xae59BA0Bd0D92232B3B6304185448C9Fe5445f4d", + "FastSwitchboard": "0x7E33B305e12aD0E73B3aedBE67A53B7818732d7d", "FastSwitchboardId": "1", - "FeesPlug": "0x72e8aba972EEe812d6a5C6Ab13197e884C7D8FA9", - "MessageSwitchboard": "0xb5763dC91FD626786E17b43E8808062a87b037aF", - "MessageSwitchboardId": "3", - "Socket": "0x8d1aAf3c24D221aE30E069136C8B1e305d7668Dc", - "SocketBatcher": "0xD9803F3A7F2b7Ce185daAaC94EFE00B30F0f9fab", - "startBlock": 362517265, + "FeesPlug": "0xfaf8a3f8f4221398F3eC765836e8BF4A3d975962", + "Socket": "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", + "SocketBatcher": "0x0d7994B4aAc7cbdFAFEAED0B9B51E7de0586ec6f", + "startBlock": 379484006, + "SUSDC": "0x0c17822dcC44F8202F176a4960EAC8da8FDbfCA5", "SwitchboardIdToAddressMap": { - "1": "0x375b8c18b57DbAA5146cdCb4a8154Ff2eCc238D6", - "2": "0xd8afBbB32706E7544f075151D4666D5B0B1F22CA", - "3": "0xb5763dC91FD626786E17b43E8808062a87b037aF" + "1": "0x7E33B305e12aD0E73B3aedBE67A53B7818732d7d" } }, "84532": { - "CCTPSwitchboard": "0x23463461b040c3B2DE91ce84e697656de6021636", - "CCTPSwitchboardId": "2", - "ContractFactoryPlug": "0xf740d6b59762fF2547Ed7aD629e041F80E1A3f75", - "FastSwitchboard": "0x81046b8A1752253b214E0EAace04E3927ECbC3cC", + "ContractFactoryPlug": "0x24A6Da9bAa5ba4AE8AF411546429b7eD2B29aA48", + "FastSwitchboard": "0x7442C13842dC293fce94Bf86116068F8FF62Ecf9", "FastSwitchboardId": "1", - "MessageSwitchboard": "0x72583393DBF61d3dd37b5474AECd73F16A94e7E0", - "MessageSwitchboardId": "3", - "Socket": "0xbD458B2442d1c9a0BA96b12EeAE98dac7843A220", - "SocketBatcher": "0x8aE491E31A5Caba13Cb9468943B2241E3046F0bb", - "startBlock": 28976719, + "FeesPlug": "0x5cdcD147A01Fc29C20c2061a89faF01F20363A20", + "Socket": "0x4861c9EB83d8ba745a184E5a11a50B6be25e4dDb", + "SocketBatcher": "0x5132751743cD59DB406A043d9983984E52Ca2cD5", + "startBlock": 31095773, + "SUSDC": "0x99D946bB805adba0233956E475bf70ED09d50d40", "SwitchboardIdToAddressMap": { - "1": "0x81046b8A1752253b214E0EAace04E3927ECbC3cC", - "2": "0x23463461b040c3B2DE91ce84e697656de6021636", - "3": "0x72583393DBF61d3dd37b5474AECd73F16A94e7E0" + "1": "0x7442C13842dC293fce94Bf86116068F8FF62Ecf9" } }, "421614": { - "CCTPSwitchboard": "0xc0D6939719120cBB7e5aBa02bc05dB9A2ECa3ffB", - "CCTPSwitchboardId": "2", - "ContractFactoryPlug": "0xB9590200eB8ED11C6A36D06A633Bff92648F9F10", - "FastSwitchboard": "0x6a3cA5381D2074695b9B17e582eaf90a107D1Dd4", + "ContractFactoryPlug": "0x5B6ed8Aaa52643d1d2d3409398e30b4eAdC767f2", + "FastSwitchboard": "0xE6be06b48c66BEbBa2114948a94cbE7eC7220a7e", "FastSwitchboardId": "1", - "MessageSwitchboard": "0xf5450eF55F2396c2cf7A6ee0c6ff63F93701485b", - "MessageSwitchboardId": "3", - "Socket": "0x247d46e6f1E63F323d62f8930775225Aa6f89961", - "SocketBatcher": "0x5F40d9fdc41b56c9E41caB097d68C9F8E49ad2B7", - "startBlock": 178265135, + "FeesPlug": "0x946f1113f19CD1d20465e62D8F5480C49253EbA3", + "Socket": "0x7aA47Ed012c185127edA67f533D91f44391bfC7C", + "SocketBatcher": "0x163272Ec38a16193a22400799D242e381fecEB42", + "startBlock": 194622586, + "SUSDC": "0xb5DbadA4f0F84420F0803089cD52Ef39876A061d", "SwitchboardIdToAddressMap": { - "1": "0x6a3cA5381D2074695b9B17e582eaf90a107D1Dd4", - "2": "0xc0D6939719120cBB7e5aBa02bc05dB9A2ECa3ffB", - "3": "0xf5450eF55F2396c2cf7A6ee0c6ff63F93701485b" + "1": "0xE6be06b48c66BEbBa2114948a94cbE7eC7220a7e" } }, "11155420": { - "CCTPSwitchboard": "0xd044404DA542873c8998BB4E0792BeBFDBf8D870", - "CCTPSwitchboardId": "2", - "ContractFactoryPlug": "0xb5Fb70d981A997240347378f9a6122E76888D325", - "FastSwitchboard": "0x7272e719e2fd5E4fBaA927cfC56431299FcEFe2D", + "ContractFactoryPlug": "0xfC6E8e1aC27b5d61A03a64f383F51d3669F82165", + "FastSwitchboard": "0xbE5CB1cf4e049F124B868DebF15d9B04ce0817b3", "FastSwitchboardId": "1", - "MessageSwitchboard": "0x5bFdC07B0302B51BD1c7ac4419D1d03DD120F034", - "MessageSwitchboardId": "3", - "Socket": "0x8e0F811Bc6ec08ffe152f460Ce9e3Ac211c83c69", - "SocketBatcher": "0x1358990F5D91152086854FB3b5137E88ac41004c", - "startBlock": 30959559, + "FeesPlug": "0xf0A01453C34759588e2Ebd42183F4FF122cc73ee", + "Socket": "0x26292db660fbeB0271E11aa4f1d2a2d0c57dc378", + "SocketBatcher": "0xaA02a6FdA809cF11c4e26a82AcfE7666204736A0", + "startBlock": 33078325, + "SUSDC": "0x3039AC5cC80C531c682045278f92439D740fa62B", "SwitchboardIdToAddressMap": { - "1": "0x7272e719e2fd5E4fBaA927cfC56431299FcEFe2D", - "2": "0xd044404DA542873c8998BB4E0792BeBFDBf8D870", - "3": "0x5bFdC07B0302B51BD1c7ac4419D1d03DD120F034" + "1": "0xbE5CB1cf4e049F124B868DebF15d9B04ce0817b3" } } } diff --git a/deployments/stage_verification.json b/deployments/stage_verification.json index 7851e646..c3aee9cc 100644 --- a/deployments/stage_verification.json +++ b/deployments/stage_verification.json @@ -1,16 +1,467 @@ { - "10": [], - "8453": [], + "10": [ + [ + "0xC559BABEbcD92278E91a545308190E4761efc347", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x6D54668ba18B425a1DbFC0BD720145c0aeE97f65", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xA557EBE094F939ae6eE8F18c8F88D06182168786", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xD78f99D62BeaF0918bB0601C68EB537b6703Ce63", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 10, + "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x06234dB2D69Ac158793a3ce59c3764422028E964", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7" + ] + ], + [ + "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", + "Socket", + "contracts/protocol/Socket.sol", + [10, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "8453": [ + [ + "0x2e531e37FdccA3CFd427a593f53f326bd24b8142", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x900Cf1914Adcee43Cb1A69c042ded801Cd5051Ef", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xFAF76924169cf58f239d02EC40a2a1eA9eaeb62E", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xd3009795fFDc64Ee0d23198772a58ca9e53EEd25", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 8453, + "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x356DBc19C69832010f92c963a8Ded6b5f9deeaCe", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9" + ] + ], + [ + "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9", + "Socket", + "contracts/protocol/Socket.sol", + [8453, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], "14323": [ [ - "0xB7Bf09935108753491E59114dc0B713cDa6F703F", + "0x8BB97CaF2B6C94d4f3988cdBC2db6e9eeF12D857", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", + [] + ], + [ + "0xD3E77f10D63031111599CB32C957CA703ec479b8", + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + [] + ], + [ + "0x4f4655Bf2aDf5Ce1b58205942c77C9549bafbEd7", + "RequestHandler", + "contracts/evmx/watcher/RequestHandler.sol", + [] + ], + [ + "0xF31EF92126D4f20799dEb3b2F17Cc64B3272DEc8", + "FeesManager", + "contracts/evmx/fees/FeesManager.sol", + [] + ], + [ + "0x62Be6a0eabce7Efb1B9BB065e36b85C63B2101c6", + "SchedulePrecompile", + "contracts/evmx/watcher/precompiles/SchedulePrecompile.sol", + [ + "0xdd4B3431472573dB6dB988E8746a118005328589", + 86400, + { + "type": "BigNumber", + "hex": "0x02540be400" + }, + { + "type": "BigNumber", + "hex": "0xe8d4a51000" + }, + 3600 + ] + ], + [ + "0xD059D6D64B9dbAE2e56F70CBEc9Af03fd41DaE35", + "ReadPrecompile", + "contracts/evmx/watcher/precompiles/ReadPrecompile.sol", + [ + "0xdd4B3431472573dB6dB988E8746a118005328589", + { + "type": "BigNumber", + "hex": "0xe8d4a51000" + }, + 3600 + ] + ], + [ + "0x01aDAb65E88b931860E63928096B16dA717b0f99", + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + [] + ], + [ + "0xD5225A5BC7ef3eAc6eb5255776fF5F007C95D03E", + "PromiseResolver", + "contracts/evmx/watcher/PromiseResolver.sol", + ["0xdd4B3431472573dB6dB988E8746a118005328589"] + ], + [ + "0x994DA55f4295B073f1D60B5074cc7f6cD7b11753", + "RequestHandler", + "contracts/evmx/watcher/RequestHandler.sol", + [] + ], + [ + "0x30240731147d217Bf228EC68104eb8664A377c33", + "Configurations", + "contracts/evmx/watcher/Configurations.sol", + [] + ], + [ + "0xD4DB3AB70EBA19586132686fBD4928809c3e42B4", + "DeployForwarder", + "contracts/evmx/helpers/DeployForwarder.sol", + [] + ], + [ + "0x4B8B34e439EBAB00116B1b4C642923b6A227AdCa", + "AuctionManager", + "contracts/evmx/AuctionManager.sol", + [] + ], + [ + "0x529d72181F1FFDA70aD62737f348d4913D5826F6", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", + [] + ], + [ + "0x148182E16aaf2Fd6137D0eb335c3f6c8266e0936", "AsyncDeployer", "contracts/evmx/helpers/AsyncDeployer.sol", [] + ], + [ + "0xBe2153E78cc02F87a2652390Bd49481dBc1ccd2E", + "FeesManager", + "contracts/evmx/fees/FeesManager.sol", + [] + ], + [ + "0x241532190C8b549Ebb4CE7624454A47c1cC97171", + "AddressResolver", + "contracts/evmx/helpers/AddressResolver.sol", + [] + ], + [ + "0x945300e92aA450A9aEf1d9FBA7b7Aee45622a082", + "ERC1967Factory", + "lib/solady/src/utils/ERC1967Factory.sol", + [] + ] + ], + "42161": [ + [ + "0xae59BA0Bd0D92232B3B6304185448C9Fe5445f4d", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x0c17822dcC44F8202F176a4960EAC8da8FDbfCA5", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xfaf8a3f8f4221398F3eC765836e8BF4A3d975962", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x7E33B305e12aD0E73B3aedBE67A53B7818732d7d", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 42161, + "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x0d7994B4aAc7cbdFAFEAED0B9B51E7de0586ec6f", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C" + ] + ], + [ + "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", + "Socket", + "contracts/protocol/Socket.sol", + [42161, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "84532": [ + [ + "0x99D946bB805adba0233956E475bf70ED09d50d40", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x4861c9EB83d8ba745a184E5a11a50B6be25e4dDb", + "SUSDC", + "SUSDC" + ] + ], + [ + "0x5cdcD147A01Fc29C20c2061a89faF01F20363A20", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x4861c9EB83d8ba745a184E5a11a50B6be25e4dDb", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x24A6Da9bAa5ba4AE8AF411546429b7eD2B29aA48", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x4861c9EB83d8ba745a184E5a11a50B6be25e4dDb", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x7442C13842dC293fce94Bf86116068F8FF62Ecf9", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 84532, + "0x4861c9EB83d8ba745a184E5a11a50B6be25e4dDb", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5132751743cD59DB406A043d9983984E52Ca2cD5", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x4861c9EB83d8ba745a184E5a11a50B6be25e4dDb" + ] + ], + [ + "0x4861c9EB83d8ba745a184E5a11a50B6be25e4dDb", + "Socket", + "contracts/protocol/Socket.sol", + [84532, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ] ], - "42161": [], - "84532": [], - "421614": [], - "11155420": [] + "421614": [ + [ + "0xb5DbadA4f0F84420F0803089cD52Ef39876A061d", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x7aA47Ed012c185127edA67f533D91f44391bfC7C", + "SUSDC", + "SUSDC" + ] + ], + [ + "0x946f1113f19CD1d20465e62D8F5480C49253EbA3", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x7aA47Ed012c185127edA67f533D91f44391bfC7C", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5B6ed8Aaa52643d1d2d3409398e30b4eAdC767f2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x7aA47Ed012c185127edA67f533D91f44391bfC7C", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xE6be06b48c66BEbBa2114948a94cbE7eC7220a7e", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 421614, + "0x7aA47Ed012c185127edA67f533D91f44391bfC7C", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x163272Ec38a16193a22400799D242e381fecEB42", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x7aA47Ed012c185127edA67f533D91f44391bfC7C" + ] + ], + [ + "0x7aA47Ed012c185127edA67f533D91f44391bfC7C", + "Socket", + "contracts/protocol/Socket.sol", + [421614, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], + "11155420": [ + [ + "0x3039AC5cC80C531c682045278f92439D740fa62B", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x26292db660fbeB0271E11aa4f1d2a2d0c57dc378", + "SUSDC", + "SUSDC" + ] + ], + [ + "0xf0A01453C34759588e2Ebd42183F4FF122cc73ee", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x26292db660fbeB0271E11aa4f1d2a2d0c57dc378", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xfC6E8e1aC27b5d61A03a64f383F51d3669F82165", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x26292db660fbeB0271E11aa4f1d2a2d0c57dc378", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbE5CB1cf4e049F124B868DebF15d9B04ce0817b3", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 11155420, + "0x26292db660fbeB0271E11aa4f1d2a2d0c57dc378", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xaA02a6FdA809cF11c4e26a82AcfE7666204736A0", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x26292db660fbeB0271E11aa4f1d2a2d0c57dc378" + ] + ], + [ + "0x26292db660fbeB0271E11aa4f1d2a2d0c57dc378", + "Socket", + "contracts/protocol/Socket.sol", + [11155420, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ] } diff --git a/foundry.toml b/foundry.toml index 5144b5ba..9ac8bc70 100644 --- a/foundry.toml +++ b/foundry.toml @@ -10,26 +10,27 @@ evm_version = 'paris' via_ir = false [labels] -0xAA77c2dE14CfFF4244a127deED6b53ce79481e14 = "AddressResolver" -0xe857a826D330Fc0429c67FaBEB8B66C26ea1DD5f = "AddressResolverImpl" -0x24c3f774c231ADFeb5e22Ad826a666A0FF9742C8 = "AsyncDeployer" -0xB7Bf09935108753491E59114dc0B713cDa6F703F = "AsyncDeployerImpl" -0xd5853f69f5dE728AEF7d1cF029cB3bF1581A4ED4 = "AuctionManager" -0x89A0D4550D5aFa809B74856624D4595188641BCe = "AuctionManagerImpl" -0x0f2801ee741A3BdeA2245d97AB54B1C4d7734534 = "Configurations" -0xD41d93042Dd1aB8c712C212A6907d4dC0718D021 = "ConfigurationsImpl" -0x54676a772aEe69E3F87178F2b5E4414dcE9A9720 = "DeployForwarder" -0x9882ce57b618175Bd9d3a4eC50ebD682B39bc467 = "DeployForwarderImpl" -0x61788F19CA1b098cE8437f8eb13B1Ad68f4FcD77 = "ERC1967Factory" -0x9339e8D915Aaf467d2fC01a4e694c8FE85621e94 = "FeesManager" -0x27b763c5410E83c02F21D97B33555729B77B2Ce1 = "FeesManagerImpl" -0xC8d803B7c1719cdF21392405879D1B56398045C4 = "FeesPool" -0x9BE3513a5d32E74935a54e5516b4daa198da5574 = "PromiseResolver" -0x784730D5e5D2F64eA63BfafeDC759317438c9186 = "ReadPrecompile" -0x22FaddfD47B9E0B545f83a2E7Cd05c12889c7a57 = "RequestHandler" -0xAA6EfF8dbd53B8d95a02c59Fe5C8A8422B08F5AA = "RequestHandlerImpl" -0x074118aB15e54A84b42Ff3de5233721434cF9f55 = "SchedulePrecompile" -0xdd25a87AeB5bCEeBAc0EB27aFfaBB6eB5a2857ca = "Watcher" -0xb143810f13fDF66F7a9B973252AEC80ec47FF0cb = "WatcherImpl" -0x66ce424303EC8499C5cdC4F6437A0434D8bd9b81 = "WritePrecompile" -0x962E1db23f6C5879A5c9D58CcB8c67CD282F1000 = "WritePrecompileImpl" +0xcA99D298B5290558660b4D5C1019Be145FaB6020 = "AddressResolver" +0x39b5D3FBBa1BC28438e25955aaB412C7576eCd61 = "AddressResolverImpl" +0xd608e1345281dE0675e2Cc1E8D0B31aD167618Ad = "AsyncDeployer" +0x2F0E83Fcd03A191D280598c33d278AF8A7e9076a = "AsyncDeployerImpl" +0xED848E9e0CCA0868484353B529E04861Fd8F04Bd = "AuctionManager" +0x2752caa4060bC744216515c247C54Ae5bB873DF2 = "AuctionManagerImpl" +0xf50A9785aef5ADeA0659609e9FF1de8578aF0b4f = "Configurations" +0xa1780f9F81090737267ccd3A5663E058AfE73A49 = "ConfigurationsImpl" +0xffF606007317cb7a1CC4C701d62C38c7734dfb15 = "DeployForwarder" +0x69e3Dc5667f7413039fE3bFd335660A99DA869A9 = "DeployForwarderImpl" +0x4f1Cd0CdBc7EA445b8B34Af8844fA4D4B5f48b79 = "ERC1967Factory" +0xbCFf8224d89f0b4e9B14c4356720439111BAC2bC = "FeesManager" +0x5E0dF9484D5ACd94028459fA7E90F4c3280147CA = "FeesManagerImpl" +0x13A3018920c7b56B20dd34E29C298121025E6de4 = "FeesPool" +0xed318668898303141EA6B9c2a9F97D0622b0a530 = "PromiseResolver" +0x7C82C3d2aE1bFB4b1D294e5181bCd7489EF554d1 = "ReadPrecompile" +0xf053AB14323FF52e7e65D6Fb12f86896F0865a36 = "RequestHandler" +0x751085cA028D2BCfC58Cee2514DeF1ed72c843cd = "RequestHandlerImpl" +0x4660c5fF2762E688f8D0def828ad161AE4940F57 = "SchedulePrecompile" +0xCeEc354B7784C667Bd661483Ae30C8d4eBA96e1d = "Watcher" +0x2996bD0DCB7C349340715472518E76342AC31b1a = "WatcherImpl" +0x9a580f1A4AE6A37CCEe73261B796F85EFbE55B15 = "WritePrecompile" +0xd50ca68c3d0f8341CC19B7eFE7e564971ba52A1D = "WritePrecompileImpl" +0x075A9bD30ce5E0Bb08994774bD55Afcadd96950A = "APP_GATEWAY" diff --git a/hardhat-scripts/addChain/utils.ts b/hardhat-scripts/addChain/utils.ts index 0a7d2c3d..0df31977 100644 --- a/hardhat-scripts/addChain/utils.ts +++ b/hardhat-scripts/addChain/utils.ts @@ -3,10 +3,7 @@ import path from "path"; import { ChainId, ChainType, NativeTokens } from "../../src"; -const enumFolderPath = path.join( - __dirname, - `/../../src/constants/chain-enums/` -); +const enumFolderPath = path.join(__dirname, `/../../src/chain-enums/`); export const updateSDK = async ( chainName: string, diff --git a/hardhat-scripts/admin/disconnect.ts b/hardhat-scripts/admin/disconnect.ts index 2a92d701..d7f195a9 100644 --- a/hardhat-scripts/admin/disconnect.ts +++ b/hardhat-scripts/admin/disconnect.ts @@ -51,7 +51,9 @@ async function disconnectPlug( checkIfAddressExists(switchboard, "Switchboard"); // Check if config is already set - if (await isConfigSetOnSocket(plug, socket, BYTES32_ZERO, switchboard)) { + if ( + await isConfigSetOnSocket(plug, socket, BYTES32_ZERO, switchboard, chain) + ) { console.log(`${plugContract} Socket Config on ${chain} already set!`); return; } diff --git a/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index 097f811f..f6eb1e45 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -3,107 +3,279 @@ dotenvConfig(); import { ethers, utils } from "ethers"; import { ChainSlug, DeploymentMode } from "../../src"; +// ============================================================================ +// DEPLOYMENT MODE CONFIGURATION +// ============================================================================ + export const mode = process.env.DEPLOYMENT_MODE as | DeploymentMode | DeploymentMode.DEV; -export const logConfig = () => { - console.log( - "================================================================================================================" - ); - console.log(""); - console.log(`Mode: ${mode}`); - console.log(""); - console.log( - `Make sure ${mode}_addresses.json and ${mode}_verification.json is cleared for given networks if redeploying!!` - ); - console.log(""); - console.log( - "================================================================================================================" - ); +// Mode-specific configuration interface +interface ModeConfig { + chains: ChainSlug[]; + feesPlugChains: ChainSlug[]; + evmChainId: number; + addresses: { + watcher: string; + transmitter: string; + socketOwner: string; + }; +} + +// Configuration for each deployment mode +const MODE_CONFIGS: Record = { + [DeploymentMode.LOCAL]: { + chains: [ + ChainSlug.ARBITRUM_SEPOLIA, + ChainSlug.OPTIMISM_SEPOLIA, + // ChainSlug.BASE_SEPOLIA, + ], + feesPlugChains: [], // Will use chains by default + evmChainId: 7625382, + addresses: { + watcher: "0xb62505feacC486e809392c65614Ce4d7b051923b", + transmitter: "0x138e9840861C983DC0BB9b3e941FB7C0e9Ade320", + socketOwner: "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + }, + }, + [DeploymentMode.DEV]: { + chains: [ + // ChainSlug.ARBITRUM_SEPOLIA, + // ChainSlug.OPTIMISM_SEPOLIA, + // ChainSlug.BASE_SEPOLIA, + ChainSlug.BSC, + ChainSlug.BASE, + ChainSlug.POLYGON_MAINNET, + ChainSlug.AVALANCHE, + ChainSlug.GNOSIS, + ChainSlug.LINEA, + ChainSlug.SONIC, + ChainSlug.KATANA, + ChainSlug.INK, + ChainSlug.HYPEREVM, + ChainSlug.BERA, + ChainSlug.UNICHAIN, + ChainSlug.SEI, + ChainSlug.MANTLE, + ChainSlug.CAMP, + ChainSlug.FLOW, + ChainSlug.MANTA_PACIFIC, + ChainSlug.MAINNET, + // ChainSlug.PLUME, + ], + feesPlugChains: [], // Will use chains by default + evmChainId: 14323, + addresses: { + watcher: "0xb62505feacC486e809392c65614Ce4d7b051923b", + transmitter: "0x138e9840861C983DC0BB9b3e941FB7C0e9Ade320", + socketOwner: "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + }, + }, + [DeploymentMode.STAGE]: { + chains: [ + // ChainSlug.MAINNET, + ChainSlug.ARBITRUM, + ChainSlug.ARBITRUM_SEPOLIA, + ChainSlug.OPTIMISM, + ChainSlug.OPTIMISM_SEPOLIA, + ChainSlug.BASE, + ChainSlug.BASE_SEPOLIA, + // ChainSlug.BSC, + // ChainSlug.POLYGON_MAINNET, + // ChainSlug.AVALANCHE, + // ChainSlug.GNOSIS, + // ChainSlug.LINEA, + // ChainSlug.SONIC, + // ChainSlug.KATANA, + // ChainSlug.CAMP, + // ChainSlug.INK, + // ChainSlug.HYPEREVM, + // ChainSlug.BERA, + // ChainSlug.UNICHAIN, + // ChainSlug.SEI, + // ChainSlug.MANTLE, + // ChainSlug.FLOW, + // ChainSlug.RISE_TESTNET, + ], + feesPlugChains: [], // Will use chains by default + evmChainId: 14323, // dummy stage + // evmChainId: 12921, + addresses: { + watcher: "0xb62505feacC486e809392c65614Ce4d7b051923b", + transmitter: "0x138e9840861C983DC0BB9b3e941FB7C0e9Ade320", + socketOwner: "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + }, + }, + [DeploymentMode.PROD]: { + chains: [ + ChainSlug.ARBITRUM, + ChainSlug.AVALANCHE, + ChainSlug.BASE, + ChainSlug.BERA, + ChainSlug.BSC, + ChainSlug.CAMP, + ChainSlug.MAINNET, + ChainSlug.FLOW, + ChainSlug.GNOSIS, + ChainSlug.HYPEREVM, + ChainSlug.INK, + ChainSlug.KATANA, + ChainSlug.LINEA, + ChainSlug.MANTA_PACIFIC, + ChainSlug.MANTLE, + ChainSlug.OPTIMISM, + ChainSlug.POLYGON_MAINNET, + ChainSlug.SEI, + ChainSlug.SONIC, + ChainSlug.UNICHAIN, + ], + feesPlugChains: [ + ChainSlug.ARBITRUM, + ChainSlug.AVALANCHE, + ChainSlug.BASE, + ChainSlug.MAINNET, + ChainSlug.HYPEREVM, + ChainSlug.LINEA, + ChainSlug.OPTIMISM, + ChainSlug.POLYGON_MAINNET, + ChainSlug.SEI, + ChainSlug.SONIC, + ChainSlug.UNICHAIN, + ], + evmChainId: 12921, + addresses: { + watcher: "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C", + transmitter: "0x138e9840861C983DC0BB9b3e941FB7C0e9Ade320", + socketOwner: "0x7BD61c667f869FB21b77626f0Ac0ACEE51e4BE7C", + }, + }, }; -export const getChains = () => { - switch (mode) { - case DeploymentMode.LOCAL: - return [ - ChainSlug.ARBITRUM_SEPOLIA, - ChainSlug.OPTIMISM_SEPOLIA, - // ChainSlug.BASE_SEPOLIA, - ]; - case DeploymentMode.DEV: - return [ - ChainSlug.ARBITRUM_SEPOLIA, - ChainSlug.OPTIMISM_SEPOLIA, - ChainSlug.BASE_SEPOLIA, - ]; - case DeploymentMode.STAGE: - return [ - ChainSlug.BASE, - ChainSlug.ARBITRUM, - ChainSlug.OPTIMISM, - ChainSlug.OPTIMISM_SEPOLIA, - ChainSlug.ARBITRUM_SEPOLIA, - ChainSlug.BASE_SEPOLIA, - ]; - case DeploymentMode.PROD: - return [ - ChainSlug.OPTIMISM_SEPOLIA, - ChainSlug.ARBITRUM_SEPOLIA, - ChainSlug.BASE_SEPOLIA, - ChainSlug.SEPOLIA, - ]; - default: - throw new Error(`Invalid deployment mode: ${mode}`); +// Get current mode configuration +const getCurrentModeConfig = (): ModeConfig => { + const config = MODE_CONFIGS[mode]; + if (!config) { + throw new Error(`Invalid deployment mode: ${mode}`); } + return config; }; -export const getFeesPlugChains = (): Array => { - switch (mode) { - case DeploymentMode.LOCAL: - return getChains(); - case DeploymentMode.DEV: - return getChains(); - case DeploymentMode.STAGE: - return [ChainSlug.OPTIMISM, ChainSlug.ARBITRUM, ChainSlug.BASE]; - case DeploymentMode.PROD: - return getChains(); - default: - throw new Error(`Invalid deployment mode: ${mode}`); - } +// ============================================================================ +// MODE-DEPENDENT FUNCTIONS AND VALUES +// ============================================================================ + +export const getChains = (): ChainSlug[] => { + return getCurrentModeConfig().chains; +}; + +export const getFeesPlugChains = (): ChainSlug[] => { + const config = getCurrentModeConfig(); + return config.feesPlugChains.length > 0 + ? config.feesPlugChains + : config.chains; }; +// Current mode configuration values +export const chains: Array = getChains(); +export const EVMX_CHAIN_ID = getCurrentModeConfig().evmChainId; +export const watcher = getCurrentModeConfig().addresses.watcher; +export const transmitter = getCurrentModeConfig().addresses.transmitter; +export const socketOwner = getCurrentModeConfig().addresses.socketOwner; + +// ============================================================================ +// STATIC CHAIN DEFINITIONS +// ============================================================================ + export const testnetChains: Array = [ ChainSlug.OPTIMISM_SEPOLIA, ChainSlug.ARBITRUM_SEPOLIA, ChainSlug.BASE_SEPOLIA, + ChainSlug.RISE_TESTNET, ]; + export const mainnetChains: Array = [ + ChainSlug.MAINNET, ChainSlug.OPTIMISM, ChainSlug.ARBITRUM, ChainSlug.BASE, + ChainSlug.BSC, + ChainSlug.POLYGON_MAINNET, + ChainSlug.AVALANCHE, + ChainSlug.GNOSIS, + ChainSlug.LINEA, + ChainSlug.SONIC, + ChainSlug.KATANA, + ChainSlug.CAMP, + ChainSlug.INK, + ChainSlug.HYPEREVM, + ChainSlug.BERA, + ChainSlug.UNICHAIN, + ChainSlug.SEI, + ChainSlug.MANTLE, + ChainSlug.ZKSYNC, + ChainSlug.FLOW, ]; -export const chains: Array = getChains(); -export const EVM_CHAIN_ID_MAP: Record = { - [DeploymentMode.LOCAL]: 7625382, - [DeploymentMode.DEV]: 14323, - [DeploymentMode.STAGE]: 14323, - [DeploymentMode.PROD]: 3605, +export const cronOnlyChains: Array = [ + ChainSlug.HYPEREVM, + ChainSlug.AVALANCHE, +]; + +// Derived chain lists (depend on current mode) +export const IndexerHighChains: Array = [ + ChainSlug.MAINNET, + ChainSlug.OPTIMISM, + ChainSlug.ARBITRUM, + ChainSlug.BASE, + ChainSlug.BSC, + ChainSlug.POLYGON_MAINNET, + ChainSlug.AVALANCHE, + ChainSlug.BERA, + ChainSlug.UNICHAIN, + ChainSlug.SONIC, +].filter((chain) => getChains().includes(chain)); + +export const IndexerLowChains: Array = getChains().filter( + (chain) => !IndexerHighChains.includes(chain) +); + +// ============================================================================ +// UTILITY FUNCTIONS +// ============================================================================ + +export const logConfig = () => { + console.log( + "================================================================================================================" + ); + console.log(""); + console.log(`Mode: ${mode}`); + console.log(""); + console.log( + `Make sure ${mode}_addresses.json and ${mode}_verification.json is cleared for given networks if redeploying!!` + ); + console.log(""); + console.log( + "================================================================================================================" + ); }; -// Addresses -export const watcher = "0xb62505feacC486e809392c65614Ce4d7b051923b"; -export const transmitter = "0x138e9840861C983DC0BB9b3e941FB7C0e9Ade320"; +// ============================================================================ +// STATIC CONSTANTS (MODE-INDEPENDENT) +// ============================================================================ + +// Deployment flags +export const skipEVMXDeployment = false; -// Chain config -export const EVMX_CHAIN_ID = EVM_CHAIN_ID_MAP[mode]; +// Value limits export const MAX_MSG_VALUE_LIMIT = ethers.utils.parseEther("0.001"); // Auction parameters export const AUCTION_END_DELAY_SECONDS = 0; export const BID_TIMEOUT = 600; // 10 minutes -export const EXPIRY_TIME = 3600; // 1 hour +export const WRITE_EXPIRY_TIME = 3600 * 24; // 24 hours +export const READ_EXPIRY_TIME = 3600; // 1 hour +export const SCHEDULE_EXPIRY_TIME = 3600; // 1 hour export const MAX_RE_AUCTION_COUNT = 5; // Fees Pool Funding Amount @@ -116,11 +288,14 @@ export const TRIGGER_FEES = utils.parseEther("0.000001"); export const WRITE_FEES = utils.parseEther("0.000001"); export const SCHEDULE_FEES_PER_SECOND = utils.parseEther("0.00000001"); export const SCHEDULE_CALLBACK_FEES = utils.parseEther("0.000001"); -export const MAX_SCHEDULE_DELAY_SECONDS = 60 * 60 * 24; +export const MAX_SCHEDULE_DELAY_SECONDS = 60 * 60 * 24; // 24 hours -// Other constants +// Versioning export const UPGRADE_VERSION = 1; -// Transmitter constants +// Transmitter thresholds export const TRANSMITTER_CREDIT_THRESHOLD = ethers.utils.parseEther("100"); // 100 ETH threshold export const TRANSMITTER_NATIVE_THRESHOLD = ethers.utils.parseEther("100"); // 100 ETH threshold + +// Performance settings +export const CONCURRENCY_LIMIT = 5; diff --git a/hardhat-scripts/constants/constants.ts b/hardhat-scripts/constants/constants.ts index a7719397..da2495ec 100644 --- a/hardhat-scripts/constants/constants.ts +++ b/hardhat-scripts/constants/constants.ts @@ -1,4 +1,4 @@ -import { constants, ethers } from "ethers"; +import { ethers } from "ethers"; import { id } from "ethers/lib/utils"; export const ETH_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; @@ -9,6 +9,7 @@ export const IMPLEMENTATION_SLOT = export const FAST_SWITCHBOARD_TYPE = id("FAST"); export const CCTP_SWITCHBOARD_TYPE = id("CCTP"); -export const BYTES32_ZERO = ethers.utils.hexZeroPad(constants.AddressZero, 32); +export const BYTES32_ZERO = ethers.constants.HashZero; export const MSG_SB_FEES = "100000000"; +export const FEE_MANAGER_WRITE_MAX_FEES = ethers.utils.parseEther("10"); diff --git a/hardhat-scripts/constants/fee.ts b/hardhat-scripts/constants/fee.ts new file mode 100644 index 00000000..25a1855e --- /dev/null +++ b/hardhat-scripts/constants/fee.ts @@ -0,0 +1,15 @@ +import { ChainSlug } from "../../src"; +import { parseEther } from "ethers/lib/utils"; +import { EVMX_CHAIN_ID, mainnetChains } from "../config"; +import { FEE_MANAGER_WRITE_MAX_FEES } from "./constants"; + +const CHAIN_MAX_FEES: { [key: number]: string } = { + [ChainSlug.MAINNET]: parseEther("1").toHexString(), + [EVMX_CHAIN_ID]: FEE_MANAGER_WRITE_MAX_FEES.toHexString(), +}; + +export const getMaxFees = (chainSlug: ChainSlug) => { + if (CHAIN_MAX_FEES[chainSlug]) return CHAIN_MAX_FEES[chainSlug]; + if (mainnetChains.includes(chainSlug)) return parseEther("0.1").toHexString(); + return parseEther("0.1").toHexString(); +}; diff --git a/hardhat-scripts/constants/feeConstants.ts b/hardhat-scripts/constants/feeConstants.ts index 8428e868..b570ddc5 100644 --- a/hardhat-scripts/constants/feeConstants.ts +++ b/hardhat-scripts/constants/feeConstants.ts @@ -1,31 +1,355 @@ -import { DeploymentMode } from "../../src"; +import { ChainSlug, DeploymentMode } from "../../src"; import { mode } from "../config"; -import { TokenMap } from "./types"; +import { TokenMap } from "../../src"; -const tokens: TokenMap = { +export const tokens: TokenMap = { [DeploymentMode.LOCAL]: { - 421614: ["0x5e732b6f5DC56dDAe4dBDbf844348F87C3B0b957"], - 11155420: ["0xb669f76f781dC75E06183DcdB7fd8bcD8Ef700E6"], + [ChainSlug.ARBITRUM_SEPOLIA]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5e732b6f5DC56dDAe4dBDbf844348F87C3B0b957", + decimals: 6, + }, + ], + [ChainSlug.OPTIMISM_SEPOLIA]: [ + { + name: "USDC", + symbol: "USDC", + address: "0xb669f76f781dC75E06183DcdB7fd8bcD8Ef700E6", + decimals: 6, + }, + ], }, [DeploymentMode.DEV]: { - 421614: ["0x2321BF7AdFaf49b1338F1Cd474859dBc0D8dfA96"], - 11155420: ["0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697"], + [ChainSlug.MANTA_PACIFIC]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + decimals: 6, + }, + ], + [ChainSlug.ARBITRUM_SEPOLIA]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x2321BF7AdFaf49b1338F1Cd474859dBc0D8dfA96", + decimals: 6, + }, + ], + [ChainSlug.OPTIMISM_SEPOLIA]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697", + decimals: 6, + }, + ], + [ChainSlug.BASE_SEPOLIA]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x95Be4D8500e3e5C970802c64b0755027d4Fc5C9F", + decimals: 6, + }, + ], + [ChainSlug.BSC]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + decimals: 6, + }, + ], + [ChainSlug.BASE]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x8aAaa86d6a4A4bEC43d985D4eCdF9CA02386d583", + decimals: 6, + }, + ], + [ChainSlug.AVALANCHE]: [ + { + name: "USDC", + symbol: "USDC", + address: "0xeAb2e310A53FD3Fb34C2944690a79DFB2e834F20", + decimals: 6, + }, + ], + [ChainSlug.GNOSIS]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + decimals: 6, + }, + ], + [ChainSlug.LINEA]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + decimals: 6, + }, + ], + [ChainSlug.SONIC]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + decimals: 6, + }, + ], + [ChainSlug.KATANA]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + decimals: 6, + }, + ], + [ChainSlug.POLYGON_MAINNET]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + decimals: 6, + }, + ], + [ChainSlug.INK]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + decimals: 6, + }, + ], + [ChainSlug.HYPEREVM]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + decimals: 6, + }, + ], + [ChainSlug.BERA]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + decimals: 6, + }, + ], + [ChainSlug.UNICHAIN]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + decimals: 6, + }, + ], + [ChainSlug.SEI]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + decimals: 6, + }, + ], + [ChainSlug.PLUME]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + decimals: 6, + }, + ], + [ChainSlug.MANTLE]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + decimals: 6, + }, + ], + [ChainSlug.CAMP]: [ + { + name: "USDC", + symbol: "USDC", + address: "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + decimals: 6, + }, + ], + [ChainSlug.FLOW]: [ + { + name: "USDC", + symbol: "USDC", + address: "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + decimals: 6, + }, + ], + [ChainSlug.MAINNET]: [ + { + name: "USDC", + symbol: "USDC", + address: "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + decimals: 6, + }, + ], }, [DeploymentMode.STAGE]: { - 8453: ["0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"], - 42161: ["0xaf88d065e77c8cc2239327c5edb3a432268e5831"], - 10: ["0x0b2c639c533813f4aa9d7837caf62653d097ff85"], + [ChainSlug.ARBITRUM_SEPOLIA]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x2321BF7AdFaf49b1338F1Cd474859dBc0D8dfA96", + decimals: 6, + }, + ], + [ChainSlug.OPTIMISM_SEPOLIA]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697", + decimals: 6, + }, + ], + [ChainSlug.BASE_SEPOLIA]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x95Be4D8500e3e5C970802c64b0755027d4Fc5C9F", + decimals: 6, + }, + ], + [ChainSlug.BASE]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x8aAaa86d6a4A4bEC43d985D4eCdF9CA02386d583", + decimals: 6, + }, + ], + [ChainSlug.ARBITRUM]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x0E0F673C9b34d08b99407F1947A10Fe73aa17928", + decimals: 6, + }, + ], + [ChainSlug.OPTIMISM]: [ + { + name: "USDC", + symbol: "USDC", + address: "0xE90649F3BA488D91c7e8E3025F639F435Fa85243", + decimals: 6, + }, + ], + }, + [DeploymentMode.PROD]: { + [ChainSlug.ARBITRUM]: [ + { + name: "USDC", + symbol: "USDC", + address: "0xaf88d065e77c8cc2239327c5edb3a432268e5831", + decimals: 6, + }, + ], + [ChainSlug.AVALANCHE]: [ + { + name: "USDC", + symbol: "USDC", + address: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", + decimals: 6, + }, + ], + [ChainSlug.BASE]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + decimals: 6, + }, + ], + [ChainSlug.MAINNET]: [ + { + name: "USDC", + symbol: "USDC", + address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + decimals: 6, + }, + ], + [ChainSlug.HYPEREVM]: [ + { + name: "USDC", + symbol: "USDC", + address: "0xb88339CB7199b77E23DB6E890353E22632Ba630f", + decimals: 6, + }, + ], + [ChainSlug.LINEA]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x176211869cA2b568f2A7D4EE941E073a821EE1ff", + decimals: 6, + }, + ], + [ChainSlug.OPTIMISM]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x0b2c639c533813f4aa9d7837caf62653d097ff85", + decimals: 6, + }, + ], + [ChainSlug.POLYGON_MAINNET]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + decimals: 6, + }, + ], + [ChainSlug.SEI]: [ + { + name: "USDC", + symbol: "USDC", + address: "0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392", + decimals: 6, + }, + ], + [ChainSlug.SONIC]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x29219dd400f2Bf60E5a23d13Be72B486D4038894", + decimals: 6, + }, + ], + [ChainSlug.UNICHAIN]: [ + { + name: "USDC", + symbol: "USDC", + address: "0x078D782b760474a361dDA0AF3839290b0EF57AD6", + decimals: 6, + }, + ], }, }; -const feePools: { [key: string]: string } = { +export const feePools: { [key: string]: string } = { [DeploymentMode.LOCAL]: "0x9De353dD1131aB4e502590D3a1832652FA316268", [DeploymentMode.DEV]: "0x13A3018920c7b56B20dd34E29C298121025E6de4", [DeploymentMode.STAGE]: "0xC8d803B7c1719cdF21392405879D1B56398045C4", + [DeploymentMode.PROD]: "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", }; export const getFeeTokens = (chainSlug: number): string[] => { - return tokens[mode][chainSlug] || []; + return (tokens[mode][chainSlug] || []).map((token) => token.address); }; export const getFeePool = (): string => { diff --git a/hardhat-scripts/constants/types.ts b/hardhat-scripts/constants/types.ts index 612ff879..1a229d3c 100644 --- a/hardhat-scripts/constants/types.ts +++ b/hardhat-scripts/constants/types.ts @@ -4,8 +4,6 @@ export type DeploymentAddresses = { [chainSlug in ChainSlug]?: ChainAddressesObj; }; -export type TokenMap = { [key: string]: { [chainSlug: number]: string[] } }; - export interface WatcherMultiCallParams { contractAddress: string; data: string; diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index 0bbf2b65..fa763226 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -13,7 +13,9 @@ import { BID_TIMEOUT, chains, EVMX_CHAIN_ID, - EXPIRY_TIME, + WRITE_EXPIRY_TIME, + READ_EXPIRY_TIME, + SCHEDULE_EXPIRY_TIME, getFeesPlugChains, logConfig, MAX_RE_AUCTION_COUNT, @@ -22,6 +24,7 @@ import { READ_FEES, SCHEDULE_CALLBACK_FEES, SCHEDULE_FEES_PER_SECOND, + skipEVMXDeployment, TRIGGER_FEES, WRITE_FEES, } from "../config/config"; @@ -30,10 +33,12 @@ import { FAST_SWITCHBOARD_TYPE, getFeePool, IMPLEMENTATION_SLOT, + FEE_MANAGER_WRITE_MAX_FEES, } from "../constants"; import { DeployParams, getAddresses, + getInstance, getOrDeploy, storeAddresses, } from "../utils"; @@ -74,6 +79,10 @@ const logBalances = async () => { const deployEVMxContracts = async () => { try { + if (skipEVMXDeployment) { + console.log("Skipping EVMx deployment"); + return; + } let addresses: DeploymentAddresses; let deployUtils: DeployParams = { addresses: {} as ChainAddressesObj, @@ -145,6 +154,7 @@ const deployEVMxContracts = async () => { addressResolver.address, deployUtils.addresses[Contracts.FeesPool], EVMxOwner, + FEE_MANAGER_WRITE_MAX_FEES, FAST_SWITCHBOARD_TYPE, ], proxyFactory, @@ -159,6 +169,18 @@ const deployEVMxContracts = async () => { deployUtils ); + const asyncDeployer = await getInstance( + Contracts.AsyncDeployer, + deployUtils.addresses[Contracts.AsyncDeployer] + ); + + deployUtils.addresses[Contracts.ForwarderImpl] = await asyncDeployer + .connect(signer) + .forwarderImplementation(); + deployUtils.addresses[Contracts.AsyncPromiseImpl] = await asyncDeployer + .connect(signer) + .asyncPromiseImplementation(); + deployUtils = await deployContractWithProxy( Contracts.Watcher, `contracts/evmx/watcher/Watcher.sol`, @@ -206,15 +228,13 @@ const deployEVMxContracts = async () => { deployUtils ); - const promiseResolver = await getOrDeploy( - Contracts.PromiseResolver, + deployUtils = await deployContractWithProxy( Contracts.PromiseResolver, - "contracts/evmx/watcher/PromiseResolver.sol", + `contracts/evmx/watcher/PromiseResolver.sol`, [deployUtils.addresses[Contracts.Watcher]], + proxyFactory, deployUtils ); - deployUtils.addresses[Contracts.PromiseResolver] = - promiseResolver.address; deployUtils = await deployContractWithProxy( Contracts.WritePrecompile, @@ -223,7 +243,7 @@ const deployEVMxContracts = async () => { EVMxOwner, deployUtils.addresses[Contracts.Watcher], WRITE_FEES, - EXPIRY_TIME, + WRITE_EXPIRY_TIME, ], proxyFactory, deployUtils @@ -233,7 +253,7 @@ const deployEVMxContracts = async () => { Contracts.ReadPrecompile, Contracts.ReadPrecompile, "contracts/evmx/watcher/precompiles/ReadPrecompile.sol", - [deployUtils.addresses[Contracts.Watcher], READ_FEES, EXPIRY_TIME], + [deployUtils.addresses[Contracts.Watcher], READ_FEES, READ_EXPIRY_TIME], deployUtils ); deployUtils.addresses[Contracts.ReadPrecompile] = readPrecompile.address; @@ -247,7 +267,7 @@ const deployEVMxContracts = async () => { MAX_SCHEDULE_DELAY_SECONDS, SCHEDULE_FEES_PER_SECOND, SCHEDULE_CALLBACK_FEES, - EXPIRY_TIME, + SCHEDULE_EXPIRY_TIME, ], deployUtils ); @@ -327,42 +347,50 @@ const deploySocketContracts = async () => { ); deployUtils.addresses[contractName] = sb.address; - contractName = Contracts.CCTPSwitchboard; - const cctpSwitchboard: Contract = await getOrDeploy( + // contractName = Contracts.CCTPSwitchboard; + // const cctpSwitchboard: Contract = await getOrDeploy( + // contractName, + // contractName, + // `contracts/protocol/switchboard/${contractName}.sol`, + // [ + // chain as ChainSlug, + // socket.address, + // socketOwner, + // MESSAGE_TRANSMITTER[chain as ChainSlug], + // ], + // deployUtils + // ); + // deployUtils.addresses[contractName] = cctpSwitchboard.address; + + // contractName = Contracts.MessageSwitchboard; + // const messageSwitchboard: Contract = await getOrDeploy( + // contractName, + // contractName, + // `contracts/protocol/switchboard/${contractName}.sol`, + // [chain as ChainSlug, socket.address, socketOwner], + // deployUtils + // ); + // deployUtils.addresses[contractName] = messageSwitchboard.address; + + contractName = Contracts.FeesPlug; + const feesPlug: Contract = await getOrDeploy( contractName, contractName, - `contracts/protocol/switchboard/${contractName}.sol`, - [ - chain as ChainSlug, - socket.address, - socketOwner, - MESSAGE_TRANSMITTER[chain as ChainSlug], - ], + `contracts/evmx/plugs/${contractName}.sol`, + [socket.address, socketOwner], deployUtils ); - deployUtils.addresses[contractName] = cctpSwitchboard.address; + deployUtils.addresses[contractName] = feesPlug.address; - contractName = Contracts.MessageSwitchboard; - const messageSwitchboard: Contract = await getOrDeploy( + contractName = Contracts.SUSDC; + const susdcPlug: Contract = await getOrDeploy( contractName, contractName, - `contracts/protocol/switchboard/${contractName}.sol`, - [chain as ChainSlug, socket.address, socketOwner], + `contracts/evmx/plugs/${contractName}.sol`, + [18, socketOwner, socket.address, "SUSDC", "SUSDC"], deployUtils ); - deployUtils.addresses[contractName] = messageSwitchboard.address; - - if (getFeesPlugChains().includes(chain as ChainSlug)) { - contractName = Contracts.FeesPlug; - const feesPlug: Contract = await getOrDeploy( - contractName, - contractName, - `contracts/evmx/plugs/${contractName}.sol`, - [socket.address, socketOwner], - deployUtils - ); - deployUtils.addresses[contractName] = feesPlug.address; - } + deployUtils.addresses[contractName] = susdcPlug.address; contractName = Contracts.ContractFactoryPlug; const contractFactoryPlug: Contract = await getOrDeploy( @@ -426,6 +454,10 @@ const deployContractWithProxy = async ( ); const newImplementation = implementation.address; + if (currentImplAddress.toLowerCase() === newImplementation.toLowerCase()) + return deployUtils; + + console.log("Upgrading contract: ", contractName); console.log( "Current implementation for", contractName, @@ -434,11 +466,6 @@ const deployContractWithProxy = async ( ); console.log("New implementation for", contractName, ":", newImplementation); - if (currentImplAddress.toLowerCase() === newImplementation.toLowerCase()) - return deployUtils; - - console.log("Upgrading contract: ", contractName); - const tx = await proxyFactory .connect(deployUtils.signer) .upgrade(deployUtils.addresses[contractName], newImplementation); diff --git a/hardhat-scripts/deploy/2.roles.ts b/hardhat-scripts/deploy/2.roles.ts index 8150ca15..0f43c4d3 100644 --- a/hardhat-scripts/deploy/2.roles.ts +++ b/hardhat-scripts/deploy/2.roles.ts @@ -2,9 +2,23 @@ import { config as dotenvConfig } from "dotenv"; dotenvConfig(); import { Wallet } from "ethers"; -import { chains, EVMX_CHAIN_ID, mode, watcher, transmitter } from "../config"; +import pLimit from "p-limit"; +import { + chains, + EVMX_CHAIN_ID, + mode, + watcher, + transmitter, + CONCURRENCY_LIMIT, +} from "../config"; import { DeploymentAddresses } from "../constants"; -import { getAddresses, getInstance, getRoleHash, overrides } from "../utils"; +import { + getAddresses, + getInstance, + getReadOverrides, + getRoleHash, + overrides, +} from "../utils"; import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { ROLES } from "../constants/roles"; import { getWatcherSigner, getSocketSigner } from "../utils/sign"; @@ -45,20 +59,20 @@ async function setRoleForContract( roleHash, targetAddress, { + ...(await getReadOverrides(chain as ChainSlug)), from: signer.address, } ); if (!hasRole) { - let tx = await contract.grantRole(roleHash, targetAddress, { - ...(await overrides(chain as ChainSlug)), - }); console.log( `granting ${roleName} role to ${targetAddress} for ${contractName}`, - chain, - "txHash: ", - tx.hash + chain ); + let tx = await contract.grantRole(roleHash, targetAddress, { + ...(await overrides(chain as ChainSlug)), + }); + console.log("txHash: ", tx.hash); await tx.wait(); } } @@ -90,7 +104,7 @@ async function setRolesOnChain(chain: number, addresses: DeploymentAddresses) { await setRoleForContract( contractName as Contracts, - contractAddress, + contractAddress.toString(), targetAddress, roleName, signer, @@ -129,9 +143,17 @@ export const main = async () => { console.log("Setting Roles"); const addresses = getAddresses(mode) as unknown as DeploymentAddresses; console.log("Setting Roles for On Chain"); + + // Set up parallel processing with concurrency limit of 3 for (const chain of chains) { await setRolesOnChain(chain, addresses); } + // const limit = pLimit(CONCURRENCY_LIMIT); + // const chainTasks = chains.map((chain) => + // limit(() => setRolesOnChain(chain, addresses)) + // ); + // await Promise.all(chainTasks); + await setRolesForEVMx(addresses); } catch (error) { console.log("Error:", error); diff --git a/hardhat-scripts/deploy/3.configureChains.ts b/hardhat-scripts/deploy/3.configureChains.ts index 0b106fa5..7c6a65de 100644 --- a/hardhat-scripts/deploy/3.configureChains.ts +++ b/hardhat-scripts/deploy/3.configureChains.ts @@ -1,32 +1,25 @@ import { config as dotenvConfig } from "dotenv"; dotenvConfig(); -import { Contract, Signer, Wallet } from "ethers"; -import { - ChainAddressesObj, - ChainSlug, - Contracts, - CCTP_DOMAINS, -} from "../../src"; +import { Contract, Signer, Wallet, constants, ethers } from "ethers"; +import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { chains, EVMX_CHAIN_ID, - mainnetChains, + getFeesPlugChains, MAX_MSG_VALUE_LIMIT, mode, - testnetChains, } from "../config"; import { - CCTP_SWITCHBOARD_TYPE, DeploymentAddresses, FAST_SWITCHBOARD_TYPE, getFeeTokens, - MSG_SB_FEES, } from "../constants"; import { DeployParams, getAddresses, getInstance, + getReadOverrides, getSocketSigner, getWatcherSigner, overrides, @@ -48,6 +41,7 @@ export const main = async () => { export const configureChains = async (addresses: DeploymentAddresses) => { for (const chain of chains) { + console.log("Configuring chain: ", chain); let chainAddresses: ChainAddressesObj = addresses[chain] ? (addresses[chain] as ChainAddressesObj) : ({} as ChainAddressesObj); @@ -76,29 +70,29 @@ export const configureChains = async (addresses: DeploymentAddresses) => { fastSwitchboardId.toString() ] = chainAddresses[Contracts.FastSwitchboard]; - const cctpSwitchboardId = await registerSb( - chain, - chainAddresses[Contracts.CCTPSwitchboard], - signer, - socketContract - ); - deployUtils.addresses[Contracts.CCTPSwitchboardId] = - cctpSwitchboardId.toString(); - deployUtils.addresses.SwitchboardIdToAddressMap[ - cctpSwitchboardId.toString() - ] = chainAddresses[Contracts.CCTPSwitchboard]; - - const messageSwitchboardId = await registerSb( - chain, - chainAddresses[Contracts.MessageSwitchboard], - signer, - socketContract - ); - deployUtils.addresses[Contracts.MessageSwitchboardId] = - messageSwitchboardId.toString(); - deployUtils.addresses.SwitchboardIdToAddressMap[ - messageSwitchboardId.toString() - ] = chainAddresses[Contracts.MessageSwitchboard]; + // const cctpSwitchboardId = await registerSb( + // chain, + // chainAddresses[Contracts.CCTPSwitchboard], + // signer, + // socketContract + // ); + // deployUtils.addresses[Contracts.CCTPSwitchboardId] = + // cctpSwitchboardId.toString(); + // deployUtils.addresses.SwitchboardIdToAddressMap[ + // cctpSwitchboardId.toString() + // ] = chainAddresses[Contracts.CCTPSwitchboard]; + + // const messageSwitchboardId = await registerSb( + // chain, + // chainAddresses[Contracts.MessageSwitchboard], + // signer, + // socketContract + // ); + // deployUtils.addresses[Contracts.MessageSwitchboardId] = + // messageSwitchboardId.toString(); + // deployUtils.addresses.SwitchboardIdToAddressMap[ + // messageSwitchboardId.toString() + // ] = chainAddresses[Contracts.MessageSwitchboard]; if (chainAddresses[Contracts.FeesPlug]) { await whitelistToken(chain, chainAddresses[Contracts.FeesPlug], signer); @@ -109,18 +103,26 @@ export const configureChains = async (addresses: DeploymentAddresses) => { await setOnchainContracts( chain, addresses, - fastSwitchboardId, - cctpSwitchboardId + fastSwitchboardId + // cctpSwitchboardId ); - await addRemoteEndpointsToCCTPSwitchboard( - chain, - addresses, - signer, - socketContract - ); + // await addRemoteEndpointsToCCTPSwitchboard( + // chain, + // addresses, + // signer, + // socketContract + // ); + + // await setSiblingConfig(chain, addresses, signer); + + if (chainAddresses[Contracts.SUSDC]) + await setSUSDCToken( + chain, + addresses[EVMX_CHAIN_ID]?.[Contracts.FeesManager]!, + chainAddresses[Contracts.SUSDC] + ); - await setSiblingConfig(chain, addresses, signer); await storeAddresses(deployUtils.addresses, chain, mode); } }; @@ -144,7 +146,7 @@ async function setOnchainContracts( chain: number, addresses: DeploymentAddresses, fastSwitchboardId: string, - cctpSwitchboardId: string + cctpSwitchboardId?: string ) { console.log("Setting onchain contracts", chain); const signer: Wallet = getWatcherSigner(); @@ -166,16 +168,16 @@ async function setOnchainContracts( signer ); - await updateContractSettings( - EVMX_CHAIN_ID, - Contracts.Configurations, - "switchboards", - [chain, CCTP_SWITCHBOARD_TYPE], - cctpSwitchboardId, - "setSwitchboard", - [chain, CCTP_SWITCHBOARD_TYPE, cctpSwitchboardId], - signer - ); + // await updateContractSettings( + // EVMX_CHAIN_ID, + // Contracts.Configurations, + // "switchboards", + // [chain, CCTP_SWITCHBOARD_TYPE], + // cctpSwitchboardId, + // "setSwitchboard", + // [chain, CCTP_SWITCHBOARD_TYPE, cctpSwitchboardId], + // signer + // ); await updateContractSettings( EVMX_CHAIN_ID, @@ -204,6 +206,7 @@ async function setOnchainContracts( signer ); } + await updateContractSettings( EVMX_CHAIN_ID, Contracts.WritePrecompile, @@ -216,140 +219,140 @@ async function setOnchainContracts( ); } -const setSiblingConfig = async ( - chain: number, - addresses: DeploymentAddresses, - signer: Wallet -) => { - try { - console.log("Setting sibling config"); - const chainAddresses = addresses[chain] as ChainAddressesObj; - const sbAddress = chainAddresses[Contracts.MessageSwitchboard]; - const switchboard = ( - await getInstance(Contracts.MessageSwitchboard, sbAddress) - ).connect(signer); - - const remoteChainSlugs = getRemoteChainSlugs(chain); - - for (const remoteChainSlug of remoteChainSlugs) { - const remoteSwitchboardAddress = - addresses[remoteChainSlug]?.[Contracts.MessageSwitchboard]; - - if (!remoteSwitchboardAddress) { - console.log( - `Remote switchboard address not found for ${remoteChainSlug}` - ); - continue; - } - - const remoteSocket = addresses[remoteChainSlug]?.[Contracts.Socket]; - - if (!remoteSocket) { - console.log(`Remote socket address not found for ${remoteChainSlug}`); - continue; - } - - const siblingSwitchboard = await switchboard.siblingSwitchboards( - remoteChainSlug - ); - const siblingSocket = await switchboard.siblingSockets(remoteChainSlug); - const siblingFees = await switchboard.switchboardFees(remoteChainSlug); - - if ( - siblingSwitchboard == - toBytes32FormatHexString(remoteSwitchboardAddress) && - siblingSocket == toBytes32FormatHexString(remoteSocket) && - siblingFees == MSG_SB_FEES - ) { - console.log(`Sibling config ${remoteChainSlug} already exists`); - continue; - } - - const registerTx = await switchboard.setSiblingConfig( - remoteChainSlug, - MSG_SB_FEES, - toBytes32FormatHexString(remoteSocket), - toBytes32FormatHexString(remoteSwitchboardAddress), - { - ...(await overrides(chain)), - } - ); - console.log( - `Setting sibling config ${remoteChainSlug} to ${sbAddress}: ${registerTx.hash}` - ); - await registerTx.wait(); - } - } catch (error) { - throw error; - } -}; - -const addRemoteEndpointsToCCTPSwitchboard = async ( - chain: number, - addresses: DeploymentAddresses, - signer: Wallet, - socket: Contract -) => { - try { - console.log("Adding remote endpoints to CCTP switchboard"); - const chainAddresses = addresses[chain] as ChainAddressesObj; - const sbAddress = chainAddresses[Contracts.CCTPSwitchboard]; - const switchboard = ( - await getInstance(Contracts.CCTPSwitchboard, sbAddress) - ).connect(signer); - const remoteChainSlugs = getRemoteChainSlugs(chain); - console.log(chain, " remoteChainSlugs: ", remoteChainSlugs); - - for (const remoteChainSlug of remoteChainSlugs) { - const remoteSwitchboardAddress = toBytes32FormatHexString( - addresses[remoteChainSlug]?.[Contracts.CCTPSwitchboard]! - ); - const currentRemoteEndpoint = await switchboard.chainSlugToRemoteEndpoint( - remoteChainSlug - ); - - if (currentRemoteEndpoint.remoteAddress == remoteSwitchboardAddress) { - console.log(`Remote endpoint ${remoteChainSlug} already exists`); - continue; - } - - if (!remoteSwitchboardAddress) { - console.log( - `Remote switchboard address not found for ${remoteChainSlug}` - ); - continue; - } - const registerTx = await switchboard.addRemoteEndpoint( - remoteChainSlug, - remoteSwitchboardAddress, - CCTP_DOMAINS[remoteChainSlug], - { - ...(await overrides(chain)), - } - ); - console.log( - `Adding remote endpoint ${remoteChainSlug} to ${sbAddress}: ${registerTx.hash}` - ); - await registerTx.wait(); - } - } catch (error) { - throw error; - } -}; - -const getRemoteChainSlugs = (chain: number) => { - if (testnetChains.includes(chain)) { - return chains.filter( - (c) => c !== chain && testnetChains.includes(c as ChainSlug) - ); - } - if (mainnetChains.includes(chain)) { - return chains.filter( - (c) => c !== chain && mainnetChains.includes(c as ChainSlug) - ); - } - return chains.filter((c) => c !== chain); -}; +// const setSiblingConfig = async ( +// chain: number, +// addresses: DeploymentAddresses, +// signer: Wallet +// ) => { +// try { +// console.log("Setting sibling config"); +// const chainAddresses = addresses[chain] as ChainAddressesObj; +// const sbAddress = chainAddresses[Contracts.MessageSwitchboard]; +// const switchboard = ( +// await getInstance(Contracts.MessageSwitchboard, sbAddress) +// ).connect(signer); + +// const remoteChainSlugs = getRemoteChainSlugs(chain); + +// for (const remoteChainSlug of remoteChainSlugs) { +// const remoteSwitchboardAddress = +// addresses[remoteChainSlug]?.[Contracts.MessageSwitchboard]; + +// if (!remoteSwitchboardAddress) { +// console.log( +// `Remote switchboard address not found for ${remoteChainSlug}` +// ); +// continue; +// } + +// const remoteSocket = addresses[remoteChainSlug]?.[Contracts.Socket]; + +// if (!remoteSocket) { +// console.log(`Remote socket address not found for ${remoteChainSlug}`); +// continue; +// } + +// const siblingSwitchboard = await switchboard.siblingSwitchboards( +// remoteChainSlug +// ); +// const siblingSocket = await switchboard.siblingSockets(remoteChainSlug); +// const siblingFees = await switchboard.switchboardFees(remoteChainSlug); + +// if ( +// siblingSwitchboard == +// toBytes32FormatHexString(remoteSwitchboardAddress) && +// siblingSocket == toBytes32FormatHexString(remoteSocket) && +// siblingFees == MSG_SB_FEES +// ) { +// console.log(`Sibling config ${remoteChainSlug} already exists`); +// continue; +// } + +// const registerTx = await switchboard.setSiblingConfig( +// remoteChainSlug, +// MSG_SB_FEES, +// toBytes32FormatHexString(remoteSocket), +// toBytes32FormatHexString(remoteSwitchboardAddress), +// { +// ...(await overrides(chain)), +// } +// ); +// console.log( +// `Setting sibling config ${remoteChainSlug} to ${sbAddress}: ${registerTx.hash}` +// ); +// await registerTx.wait(); +// } +// } catch (error) { +// throw error; +// } +// }; + +// const addRemoteEndpointsToCCTPSwitchboard = async ( +// chain: number, +// addresses: DeploymentAddresses, +// signer: Wallet, +// socket: Contract +// ) => { +// try { +// console.log("Adding remote endpoints to CCTP switchboard"); +// const chainAddresses = addresses[chain] as ChainAddressesObj; +// const sbAddress = chainAddresses[Contracts.CCTPSwitchboard]; +// const switchboard = ( +// await getInstance(Contracts.CCTPSwitchboard, sbAddress) +// ).connect(signer); +// const remoteChainSlugs = getRemoteChainSlugs(chain); +// console.log(chain, " remoteChainSlugs: ", remoteChainSlugs); + +// for (const remoteChainSlug of remoteChainSlugs) { +// const remoteSwitchboardAddress = toBytes32FormatHexString( +// addresses[remoteChainSlug]?.[Contracts.CCTPSwitchboard]! +// ); +// const currentRemoteEndpoint = await switchboard.chainSlugToRemoteEndpoint( +// remoteChainSlug +// ); + +// if (currentRemoteEndpoint.remoteAddress == remoteSwitchboardAddress) { +// console.log(`Remote endpoint ${remoteChainSlug} already exists`); +// continue; +// } + +// if (!remoteSwitchboardAddress) { +// console.log( +// `Remote switchboard address not found for ${remoteChainSlug}` +// ); +// continue; +// } +// const registerTx = await switchboard.addRemoteEndpoint( +// remoteChainSlug, +// remoteSwitchboardAddress, +// CCTP_DOMAINS[remoteChainSlug], +// { +// ...(await overrides(chain)), +// } +// ); +// console.log( +// `Adding remote endpoint ${remoteChainSlug} to ${sbAddress}: ${registerTx.hash}` +// ); +// await registerTx.wait(); +// } +// } catch (error) { +// throw error; +// } +// }; + +// const getRemoteChainSlugs = (chain: number) => { +// if (testnetChains.includes(chain)) { +// return chains.filter( +// (c) => c !== chain && testnetChains.includes(c as ChainSlug) +// ); +// } +// if (mainnetChains.includes(chain)) { +// return chains.filter( +// (c) => c !== chain && mainnetChains.includes(c as ChainSlug) +// ); +// } +// return chains.filter((c) => c !== chain); +// }; const registerSb = async ( chain: number, @@ -370,6 +373,7 @@ const registerSb = async ( // therefore override from address as well switchboardId = await socket.switchboardIds(sbAddress, { from: signer.address, + ...(await overrides(chain)), }); if (Number(switchboardId) == 0) { @@ -379,7 +383,9 @@ const registerSb = async ( console.log(`Registering Switchboard ${sbAddress}: ${registerTx.hash}`); await registerTx.wait(); - switchboardId = await switchboard.switchboardId(); + switchboardId = await switchboard.switchboardId({ + ...(await overrides(chain)), + }); console.log(`Switchboard ID: ${switchboardId}`); } @@ -395,24 +401,33 @@ export const whitelistToken = async ( signer: Signer ) => { console.log("Whitelisting token"); - + if (!getFeesPlugChains().includes(chain as ChainSlug)) { + console.log( + "Skipping whitelisting token for fees plug, not part of fees plug chains" + ); + return; + } + console.log("feesPlugAddress: ", feesPlugAddress); const feesPlugContract = ( await getInstance(Contracts.FeesPlug, feesPlugAddress) ).connect(signer); - + // console.log("feesPlugContract: ", feesPlugContract); const tokens = getFeeTokens(chain); + console.log("tokens: ", tokens); if (tokens.length == 0) return; for (const token of tokens) { - const isWhitelisted = await feesPlugContract.whitelistedTokens(token); + console.log("token: ", token); + const isWhitelisted = await feesPlugContract.whitelistedTokens(token, { + ...(await getReadOverrides(chain as ChainSlug)), + }); if (!isWhitelisted) { const tx = await feesPlugContract.whitelistToken(token, { ...(await overrides(chain)), }); console.log( - `Whitelisting token ${token} for ${feesPlugContract.address}`, - tx.hash + `Whitelisting token ${token} for ${feesPlugContract.address}, txHash: ${tx.hash}` ); await tx.wait(); } else { @@ -421,6 +436,50 @@ export const whitelistToken = async ( } }; +export const setSUSDCToken = async ( + chain: number, + feesManagerAddress: string, + susdcAddress: string +) => { + let contractInstance = await getInstance( + Contracts.FeesManager, + feesManagerAddress + ); + contractInstance = await contractInstance.connect(getWatcherSigner()); + + const susdcToken = contractInstance.susdcToken(); + const forwarderAddress = await contractInstance.forwarderAddresses( + susdcToken, + chain + ); + + if (forwarderAddress != constants.AddressZero) { + const forwarderABI = [ + "function getOnChainAddress() external view returns (bytes32)", + ]; + const forwarderContract = new ethers.Contract( + forwarderAddress, + forwarderABI, + getWatcherSigner() + ); + const onChainAddress = await forwarderContract.getOnChainAddress(); + + if ( + onChainAddress.toLowerCase() == + toBytes32FormatHexString(susdcAddress).toLowerCase() + ) { + console.log(`SUSDC token is already set to ${susdcAddress}`); + return; + } + } + const tx = await contractInstance.setSusdcToken( + chain, + toBytes32FormatHexString(susdcAddress) + ); + console.log(`Setting SUSDC token to ${susdcAddress}, txHash: ${tx.hash}`); + await tx.wait(); +}; + main() .then(() => process.exit(0)) .catch((error: Error) => { diff --git a/hardhat-scripts/deploy/4.configureEVMx.ts b/hardhat-scripts/deploy/4.configureEVMx.ts index 1b05f542..77b2ea27 100644 --- a/hardhat-scripts/deploy/4.configureEVMx.ts +++ b/hardhat-scripts/deploy/4.configureEVMx.ts @@ -3,7 +3,7 @@ dotenvConfig(); import { Contracts, EVMxAddressesObj, READ, SCHEDULE, WRITE } from "../../src"; import { Wallet } from "ethers"; -import { EVMX_CHAIN_ID, mode } from "../config"; +import { chains, EVMX_CHAIN_ID, mode } from "../config"; import { DeploymentAddresses } from "../constants"; import { getAddresses, @@ -12,6 +12,8 @@ import { overrides, updateContractSettings, } from "../utils"; +import { getMaxFees } from "../constants/fee"; +import { formatEther } from "ethers/lib/utils"; export const main = async () => { let addresses: DeploymentAddresses; @@ -29,6 +31,8 @@ export const main = async () => { export const configureEVMx = async (evmxAddresses: EVMxAddressesObj) => { const signer: Wallet = getWatcherSigner(); + await checkAndSetMaxFees(evmxAddresses); + await updateContractSettings( EVMX_CHAIN_ID, Contracts.AddressResolver, @@ -120,6 +124,47 @@ export const configureEVMx = async (evmxAddresses: EVMxAddressesObj) => { await setWatcherCoreContracts(evmxAddresses); }; +const checkAndSetMaxFees = async (evmxAddresses: EVMxAddressesObj) => { + const feesManagerContract = ( + await getInstance( + Contracts.FeesManager, + evmxAddresses[Contracts.FeesManager] + ) + ).connect(getWatcherSigner()); + + const allChains = [...chains, EVMX_CHAIN_ID]; + const currentMaxFeesArray = await feesManagerContract.getChainMaxFees( + allChains + ); + const maxFeesUpdateArray: { chainSlug: number; maxFees: string }[] = []; + + for (let i = 0; i < allChains.length; i++) { + const chain = allChains[i]; + const fees = getMaxFees(chain); + console.log( + `Chain ${chain} New Max Fees: ${formatEther( + fees + )} USDC, Current fees: ${formatEther(currentMaxFeesArray[i])} USDC` + ); + if (!currentMaxFeesArray[i].eq(fees)) { + console.log(`Set Chain Max Fees for chain ${chain}`); + maxFeesUpdateArray.push({ chainSlug: chain, maxFees: fees }); + } + } + + if (maxFeesUpdateArray.length > 0) { + const chains = maxFeesUpdateArray.map((item) => item.chainSlug); + const maxFees = maxFeesUpdateArray.map((item) => item.maxFees); + let tx = await feesManagerContract.setChainMaxFees(chains, maxFees); + console.log( + `Setting Chain Max Fees for chains: ${chains.join(", ")} tx hash: ${ + tx.hash + }` + ); + await tx.wait(); + } +}; + export const setWatcherCoreContracts = async ( evmxAddresses: EVMxAddressesObj ) => { diff --git a/hardhat-scripts/deploy/6.connect.ts b/hardhat-scripts/deploy/6.connect.ts index 32975a63..460b4b6f 100644 --- a/hardhat-scripts/deploy/6.connect.ts +++ b/hardhat-scripts/deploy/6.connect.ts @@ -1,9 +1,8 @@ -import { ethers, Wallet } from "ethers"; +import { Wallet } from "ethers"; import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; -import { chains, EVMX_CHAIN_ID, mode } from "../config"; +import { chains, CONCURRENCY_LIMIT, EVMX_CHAIN_ID, mode } from "../config"; import { AppGatewayConfig, DeploymentAddresses } from "../constants"; import { - checkIfAddressExists, checkIfAppGatewayIdExists, getAddresses, getAppGatewayId, @@ -14,13 +13,18 @@ import { } from "../utils"; import { getWatcherSigner, sendWatcherMultiCallWithNonce } from "../utils/sign"; import { isConfigSetOnEVMx, isConfigSetOnSocket } from "../utils"; +import pLimit from "p-limit"; -const plugs = [Contracts.ContractFactoryPlug, Contracts.FeesPlug]; +const plugs = [ + Contracts.ContractFactoryPlug, + Contracts.FeesPlug, + Contracts.SUSDC, +]; // Main function to connect plugs on all chains export const main = async () => { try { - await connectPlugsOnSocket(); + await connectPlugsOnSocketForAllChains(); await updateConfigEVMx(); } catch (error) { console.log("Error while sending transaction", error); @@ -50,13 +54,22 @@ async function connectPlug( const appGatewayId = getAppGatewayId(plugContract, addresses); checkIfAppGatewayIdExists(appGatewayId, "AppGatewayId"); // Check if config is already set - if (await isConfigSetOnSocket(plug, socket, appGatewayId, switchboardId)) { + if ( + await isConfigSetOnSocket(plug, socket, appGatewayId, switchboardId, chain) + ) { console.log(`${plugContract} Socket Config on ${chain} already set!`); return; } // Connect the plug - const tx = await plug.functions["connectSocket"]( + let functionName = "initSocket"; + + const isInitialized = await plug.isSocketInitialized({ + ...(await overrides(chain)), + }); + if (isInitialized.toNumber() === 1) functionName = "connectSocket"; + + const tx = await plug.functions[functionName]( appGatewayId, socket.address, switchboardId, @@ -68,24 +81,37 @@ async function connectPlug( await tx.wait(); } -export const connectPlugsOnSocket = async () => { +export const connectPlugsOnSocketForAllChains = async () => { console.log("Connecting plugs"); const addresses = getAddresses(mode) as unknown as DeploymentAddresses; // Connect plugs on each chain - await Promise.all( - chains.map(async (chain) => { - if (!addresses[chain]) return; - - const socketSigner = getSocketSigner(chain as ChainSlug); - const addr = addresses[chain]!; - // Connect each plug contract - for (const plugContract of plugs) { - if (addr[plugContract]) { - await connectPlug(chain, plugContract, socketSigner, addresses, addr); - } + for (const chain of chains) { + await connectPlugsOnSocket(chain, addresses); + } +}; + +export const connectPlugsOnSocket = async ( + chain: number, + addresses: DeploymentAddresses +) => { + try { + if (!addresses[chain]) { + console.log(`${chain} not found in addresses`); + return; + } + const socketSigner = getSocketSigner(chain as ChainSlug); + const addr = addresses[chain]!; + // Connect each plug contract + for (const plugContract of plugs) { + if (addr[plugContract]) { + await connectPlug(chain, plugContract, socketSigner, addresses, addr); + } else { + console.log(`${plugContract} not found in ${chain}`); } - }) - ); + } + } catch (error) { + console.log("Error while sending transaction", error); + } }; // Configure plugs on the Watcher VM diff --git a/hardhat-scripts/deploy/7.upload.ts b/hardhat-scripts/deploy/7.upload.ts index f5f83811..02e5e462 100644 --- a/hardhat-scripts/deploy/7.upload.ts +++ b/hardhat-scripts/deploy/7.upload.ts @@ -15,7 +15,7 @@ const getBucketName = () => { case DeploymentMode.STAGE: return "socket-stage"; case DeploymentMode.PROD: - return "socket-prod"; + return "socket-stage"; default: throw new Error(`Invalid deployment mode: ${mode}`); } diff --git a/hardhat-scripts/deploy/9.setupTransmitter.ts b/hardhat-scripts/deploy/9.setupTransmitter.ts index a0d68336..4bbe3431 100644 --- a/hardhat-scripts/deploy/9.setupTransmitter.ts +++ b/hardhat-scripts/deploy/9.setupTransmitter.ts @@ -20,8 +20,8 @@ let transmitterAddress: string; export const main = async () => { console.log("Setting up transmitter..."); await init(); - await checkAndDepositCredits(); - await checkAndDepositNative(); + await checkAndDepositCredits(transmitterAddress); + await checkAndDepositNative(transmitterAddress); await approveAuctionManager(); console.log("Transmitter setup complete!"); @@ -48,13 +48,9 @@ export const approveAuctionManager = async () => { console.log("Approving auction manager"); const tx = await feesManagerContract .connect(transmitterSigner) - .approveAppGateways( - [ - { - appGateway: auctionManagerAddress, - approval: true, - }, - ], + ["approve(address,bool)"]( + auctionManagerAddress, + true, await overrides(EVMX_CHAIN_ID as ChainSlug) ); console.log("Auction manager approval tx hash:", tx.hash); @@ -65,17 +61,17 @@ export const approveAuctionManager = async () => { } }; -export const checkAndDepositCredits = async () => { +export const checkAndDepositCredits = async (transmitter: string) => { console.log("Checking and depositing credits"); const credits = await feesManagerContract .connect(transmitterSigner) - .getAvailableCredits(transmitterAddress); + .balanceOf(transmitter); if (credits.lt(TRANSMITTER_CREDIT_THRESHOLD)) { console.log("Depositing credits for transmitter..."); const tx = await feesManagerContract .connect(getWatcherSigner()) - .wrap(transmitterAddress, { + .wrap(transmitter, { ...(await overrides(EVMX_CHAIN_ID as ChainSlug)), value: TRANSMITTER_CREDIT_THRESHOLD, }); @@ -85,16 +81,16 @@ export const checkAndDepositCredits = async () => { } }; -export const checkAndDepositNative = async () => { +export const checkAndDepositNative = async (transmitter: string) => { console.log("Checking and depositing native"); const nativeBalance = await transmitterSigner.provider!.getBalance( - transmitterAddress + transmitter ); if (nativeBalance.lt(TRANSMITTER_NATIVE_THRESHOLD)) { console.log("Depositing native for transmitter..."); const tx = await getWatcherSigner().sendTransaction({ - to: transmitterAddress, + to: transmitter, value: TRANSMITTER_NATIVE_THRESHOLD, ...(await overrides(EVMX_CHAIN_ID as ChainSlug)), }); diff --git a/hardhat-scripts/deploy/UpgradeForwarder.ts b/hardhat-scripts/deploy/UpgradeForwarder.ts new file mode 100644 index 00000000..349a665c --- /dev/null +++ b/hardhat-scripts/deploy/UpgradeForwarder.ts @@ -0,0 +1,76 @@ +import { config as dotenvConfig } from "dotenv"; +dotenvConfig(); + +import { ChainSlug } from "@socket.tech/socket-protocol"; +import { Wallet } from "ethers"; +import { ChainAddressesObj, Contracts } from "../../src"; +import { EVMX_CHAIN_ID, mode } from "../config"; +import { + DeployParams, + getAddresses, + getInstance, + getOrDeploy, + overrides, + storeAddresses, +} from "../utils"; +import { getWatcherSigner } from "../utils/sign"; +import { DeploymentAddresses } from "../constants"; + +const main = async () => { + let addresses: DeploymentAddresses = getAddresses( + mode + ) as unknown as DeploymentAddresses; + const evmxAddresses = addresses[EVMX_CHAIN_ID] as ChainAddressesObj; + const signer: Wallet = getWatcherSigner(); + + let deployUtils: DeployParams = { + addresses: evmxAddresses, + mode, + signer: signer, + currentChainSlug: EVMX_CHAIN_ID as ChainSlug, + }; + + const oldImpl = deployUtils.addresses[Contracts.ForwarderImpl]; + const implementation = await getOrDeploy( + Contracts.ForwarderImpl, + Contracts.Forwarder, + "contracts/evmx/helpers/Forwarder.sol", + [], + deployUtils + ); + + if ( + oldImpl && + oldImpl.toLowerCase() === implementation.address.toLowerCase() + ) { + console.log("ForwarderImpl upgrade not needed"); + return; + } + + deployUtils.addresses[Contracts.ForwarderImpl] = implementation.address; + console.log(`ForwarderImpl: ${implementation.address}`); + + const asyncDeployer = await getInstance( + Contracts.AsyncDeployer, + deployUtils.addresses[Contracts.AsyncDeployer] + ); + const tx = await asyncDeployer + .connect(signer) + .setForwarderImplementation(implementation.address, { + ...(await overrides(EVMX_CHAIN_ID)), + }); + console.log(`Upgrading tx hash: ${tx.hash}`); + await tx.wait(); + + await storeAddresses(deployUtils.addresses, EVMX_CHAIN_ID, mode); + console.log( + `Upgraded forwarder ${implementation.address} implementation on chain ${EVMX_CHAIN_ID}` + ); +}; + +main() + .then(() => process.exit(0)) + .catch((error: Error) => { + console.error(error); + process.exit(1); + }); diff --git a/hardhat-scripts/deploy/UpgradePromise.ts b/hardhat-scripts/deploy/UpgradePromise.ts new file mode 100644 index 00000000..7e0b8435 --- /dev/null +++ b/hardhat-scripts/deploy/UpgradePromise.ts @@ -0,0 +1,75 @@ +import { config as dotenvConfig } from "dotenv"; +dotenvConfig(); + +import { ChainSlug } from "@socket.tech/socket-protocol"; +import { Wallet } from "ethers"; +import { ChainAddressesObj, Contracts } from "../../src"; +import { EVMX_CHAIN_ID, mode } from "../config"; +import { + DeployParams, + getAddresses, + getInstance, + getOrDeploy, + overrides, + storeAddresses, +} from "../utils"; +import { getWatcherSigner } from "../utils/sign"; +import { DeploymentAddresses } from "../constants"; + +const main = async () => { + let addresses: DeploymentAddresses = getAddresses( + mode + ) as unknown as DeploymentAddresses; + const evmxAddresses = addresses[EVMX_CHAIN_ID] as ChainAddressesObj; + const signer: Wallet = getWatcherSigner(); + + let deployUtils: DeployParams = { + addresses: evmxAddresses, + mode, + signer: signer, + currentChainSlug: EVMX_CHAIN_ID as ChainSlug, + }; + + const oldImpl = deployUtils.addresses[Contracts.AsyncPromiseImpl]; + const implementation = await getOrDeploy( + Contracts.AsyncPromiseImpl, + Contracts.AsyncPromise, + "contracts/evmx/helpers/AsyncPromise.sol", + [], + deployUtils + ); + + if ( + oldImpl && + oldImpl.toLowerCase() === implementation.address.toLowerCase() + ) { + console.log("AsyncPromiseImpl upgrade not needed"); + return; + } + + deployUtils.addresses[Contracts.AsyncPromiseImpl] = implementation.address; + console.log(`AsyncPromiseImpl: ${implementation.address}`); + const asyncDeployer = await getInstance( + Contracts.AsyncDeployer, + deployUtils.addresses[Contracts.AsyncDeployer] + ); + const tx = await asyncDeployer + .connect(signer) + .setAsyncPromiseImplementation(implementation.address, { + ...(await overrides(EVMX_CHAIN_ID)), + }); + console.log(`Upgrading tx hash: ${tx.hash}`); + await tx.wait(); + + await storeAddresses(deployUtils.addresses, EVMX_CHAIN_ID, mode); + console.log( + `Upgraded async promise ${implementation.address} implementation on chain ${EVMX_CHAIN_ID}` + ); +}; + +main() + .then(() => process.exit(0)) + .catch((error: Error) => { + console.error(error); + process.exit(1); + }); diff --git a/hardhat-scripts/deploy/WhitelistFeesReceiver.ts b/hardhat-scripts/deploy/WhitelistFeesReceiver.ts new file mode 100644 index 00000000..1d7e3aed --- /dev/null +++ b/hardhat-scripts/deploy/WhitelistFeesReceiver.ts @@ -0,0 +1,40 @@ +import { config as dotenvConfig } from "dotenv"; +dotenvConfig(); + +import { Contracts, EVMxAddressesObj } from "../../src"; +import { Wallet } from "ethers"; +import { EVMX_CHAIN_ID, mode } from "../config"; +import { DeploymentAddresses } from "../constants"; +import { getAddresses, getInstance, getWatcherSigner } from "../utils"; + +const ADDRESS_TO_WHITELIST = "0xbC4D50311708FFAFC1A26882fdab17cBfE55CBB9"; + +export const main = async () => { + let addresses: DeploymentAddresses; + try { + console.log("Configuring EVMx contracts"); + addresses = getAddresses(mode) as unknown as DeploymentAddresses; + const evmxAddresses = addresses[EVMX_CHAIN_ID] as EVMxAddressesObj; + const signer: Wallet = getWatcherSigner(); + + const feesManager = await getInstance( + Contracts.FeesManager, + evmxAddresses[Contracts.FeesManager] + ); + const tx = await feesManager + .connect(signer) + .setWhitelistedReceiver(ADDRESS_TO_WHITELIST, true); + console.log("Fees manager whitelisted receiver set tx: ", tx.hash); + await tx.wait(); + console.log("Fees manager whitelisted receiver set"); + } catch (error) { + console.log("Error:", error); + } +}; + +main() + .then(() => process.exit(0)) + .catch((error: Error) => { + console.error(error); + process.exit(1); + }); diff --git a/hardhat-scripts/deploy/deployTestUSDC.ts b/hardhat-scripts/deploy/deployTestUSDC.ts new file mode 100644 index 00000000..b4348718 --- /dev/null +++ b/hardhat-scripts/deploy/deployTestUSDC.ts @@ -0,0 +1,85 @@ +import { config } from "dotenv"; +config(); +import { Contract } from "ethers"; +import { formatEther, parseEther } from "ethers/lib/utils"; +import { ChainSlug } from "../../src"; +import { + chains, + EVMX_CHAIN_ID, + mode, + logConfig, + socketOwner, +} from "../config/config"; +import { deployContractWithArgs } from "../utils"; +import { getSocketSigner, getWatcherSigner } from "../utils/sign"; +import { tokens } from "../constants/feeConstants"; + +const main = async () => { + logConfig(); + await logBalances(); + await deployTestUSDC(); +}; + +const chainsToDeploy = [ChainSlug.MANTA_PACIFIC]; +// const chainsToDeploy = chains; + +const logBalances = async () => { + const evmxDeployer = await getWatcherSigner(); + const evmxBalance = await evmxDeployer.provider.getBalance( + evmxDeployer.address + ); + console.log( + `EVMx Deployer ${evmxDeployer.address} balance on ${EVMX_CHAIN_ID}:`, + formatEther(evmxBalance) + ); + await Promise.all( + chainsToDeploy.map(async (chain) => { + const socketDeployer = await getSocketSigner(chain as ChainSlug); + const socketBalance = await socketDeployer.provider.getBalance( + socketDeployer.address + ); + console.log( + `Socket Deployer ${socketDeployer.address} balance on ${chain}:`, + formatEther(socketBalance) + ); + }) + ); +}; +const deployTestUSDC = async () => { + for (const chain of chainsToDeploy) { + const signer = getSocketSigner(chain as ChainSlug); + try { + if ( + tokens[mode][chain as ChainSlug]?.find((token) => token.name === "USDC") + ) { + console.log(`USDC already deployed on ${chain}`); + continue; + } + let contractName = "TestUSDC"; + const testUSDC: Contract = await deployContractWithArgs( + contractName, + [ + "USDC Coin", + "USDC", + 6, + socketOwner, + parseEther("1000000000000000000"), + ], + signer, + chain + ); + console.log( + `Deployed ${contractName} on ${chain} at ${testUSDC.address}` + ); + } catch (error) { + console.error(error); + } + } +}; + +main() + .then(() => process.exit(0)) + .catch((error: Error) => { + console.error(error); + process.exit(1); + }); diff --git a/hardhat-scripts/s3Config/buildConfig.ts b/hardhat-scripts/s3Config/buildConfig.ts index 5ac578b5..d8541a6b 100644 --- a/hardhat-scripts/s3Config/buildConfig.ts +++ b/hardhat-scripts/s3Config/buildConfig.ts @@ -1,8 +1,18 @@ import { config as dotenvConfig } from "dotenv"; -import { ChainConfig, ChainSlug, S3Config, getFinalityBlocks } from "../../src"; +import { + ChainConfig, + ChainSlug, + Currency, + NativeTokens, + S3Config, + getFinalityBlocks, +} from "../../src"; import { EVMX_CHAIN_ID, + IndexerHighChains, + IndexerLowChains, chains, + cronOnlyChains, mainnetChains, mode, testnetChains, @@ -11,7 +21,10 @@ import { getAddresses } from "../utils/address"; import { getChainName, rpcKeys, wssRpcKeys } from "../utils/networks"; import { getChainType } from "./utils"; import { version } from "./version"; - +import { tokens } from "../constants/feeConstants"; +import { ChainGasPriceType } from "../../src/chain-enums/gasPriceType"; +import { GasPriceType } from "../../src/enums"; +import { ChainEventBlockRange } from "../../src/chain-enums/eventBlockRange"; dotenvConfig(); const addresses = getAddresses(mode); @@ -21,9 +34,13 @@ export const getS3Config = () => { supportedChainSlugs, version: version[mode], chains: {}, + tokens, testnetChainSlugs: testnetChains, mainnetChainSlugs: mainnetChains, evmxChainSlug: EVMX_CHAIN_ID as ChainSlug, + indexerHighChains: IndexerHighChains, + indexerLowChains: IndexerLowChains, + cronOnlyChains: cronOnlyChains, }; supportedChainSlugs.forEach((chainSlug) => { config.chains[chainSlug] = getChainConfig(chainSlug); @@ -44,10 +61,12 @@ export const getChainConfig = (chainSlug: ChainSlug) => { rpc: process.env[rpcKey], wssRpc: process.env[wssRpcKey], confirmations: 0, - eventBlockRange: 5000, + eventBlockRange: ChainEventBlockRange[chainSlug] ?? 5000, addresses: addresses[chainSlug], chainType: getChainType(chainSlug), finalityBlocks: getFinalityBlocks(chainSlug), + nativeToken: Currency[chainSlug] ?? NativeTokens.ETHEREUM, + gasPriceType: ChainGasPriceType[chainSlug] ?? GasPriceType.EIP1559, }; return chainConfig; }; diff --git a/hardhat-scripts/test/chainTest.ts b/hardhat-scripts/test/chainTest.ts new file mode 100644 index 00000000..a243c257 --- /dev/null +++ b/hardhat-scripts/test/chainTest.ts @@ -0,0 +1,368 @@ +import { config as dotenvConfig } from "dotenv"; +dotenvConfig(); +import { ethers } from "ethers"; +import axios from "axios"; +import { chains } from "../config/config"; +import { ChainSlug, chainSlugToHardhatChainName } from "../../src"; + +// Chain IDs to test +const TEST_CHAINS = [ + // ChainSlug.ARBITRUM, + // ChainSlug.AVALANCHE, + ChainSlug.BASE, + // ChainSlug.BERA, + // ChainSlug.BSC, + ChainSlug.CAMP, + ChainSlug.MAINNET, + ChainSlug.FLOW, + ChainSlug.HYPEREVM, + ChainSlug.INK, + // ChainSlug.KATANA, + ChainSlug.MANTA_PACIFIC, + ChainSlug.MANTLE, + ChainSlug.OPTIMISM, + ChainSlug.POLYGON_MAINNET, + ChainSlug.SEI, + // ChainSlug.SONIC, + // ChainSlug.UNICHAIN +]; + +interface ChainTestResult { + chainId: number; + chainName: string; + hasForwarder: boolean; + forwarderAddress?: string; + txHash?: string; + status?: string; + error?: string; +} + +interface StatusResponse { + status: string; + response: Array<{ + status: string; + requestCount: number; + writePayloads: Array<{ + payloadId: string; + chainSlug: number; + batchCount: number; + target: string; + callType: string; + payload: string; + }>; + }>; +} + +class ChainTester { + private provider: ethers.providers.JsonRpcProvider; + private wallet: ethers.Wallet; + private counterAppGateway: ethers.Contract; + private feesManager: ethers.Contract; + private results: ChainTestResult[] = []; + + constructor() { + // Initialize provider and wallet + this.provider = new ethers.providers.JsonRpcProvider(process.env.EVMX_RPC); + this.wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, this.provider); + + // Counter App Gateway ABI (minimal required functions) + const counterAppGatewayABI = [ + "function forwarderAddresses(bytes32, uint32) view returns (address)", + "function deployContracts(uint32) external", + "function incrementCounters(address[] memory instances_) external", + "function counter() view returns (bytes32)", + ]; + + // FeesManager ABI (minimal required functions) + const feesManagerABI = [ + "function totalBalanceOf(address) view returns (uint256)", + "function getBlockedCredits(address) view returns (uint256)", + "function balanceOf(address) view returns (uint256)", + ]; + + this.counterAppGateway = new ethers.Contract( + process.env.COUNTER_APP_GATEWAY!, + counterAppGatewayABI, + this.wallet + ); + + this.feesManager = new ethers.Contract( + process.env.FEES_MANAGER!, + feesManagerABI, + this.provider + ); + } + + async checkBalance(): Promise { + console.log("=".repeat(80)); + console.log("CHECKING COUNTER APP GATEWAY BALANCE"); + console.log("=".repeat(80)); + + try { + const appGatewayAddress = process.env.COUNTER_APP_GATEWAY!; + const feesManagerAddress = process.env.FEES_MANAGER!; + + const totalCredits = await this.feesManager.totalBalanceOf( + appGatewayAddress + ); + const blockedCredits = await this.feesManager.getBlockedCredits( + appGatewayAddress + ); + const availableFees = await this.feesManager.balanceOf(appGatewayAddress); + + console.log(`Counter App Gateway: ${appGatewayAddress}`); + console.log(`Fees Manager: ${feesManagerAddress}`); + console.log( + `Total Credits: ${ethers.utils.formatEther(totalCredits)} ETH` + ); + console.log( + `Blocked Credits: ${ethers.utils.formatEther(blockedCredits)} ETH` + ); + console.log( + `Available Fees: ${ethers.utils.formatEther(availableFees)} ETH` + ); + } catch (error) { + console.error("Error checking balance:", error); + } + + console.log(""); + } + + async testChain(chainId: number): Promise { + const chainName = + chainSlugToHardhatChainName[chainId] || `Chain ${chainId}`; + console.log(`Testing ${chainName} (${chainId})...`); + + const result: ChainTestResult = { + chainId, + chainName, + hasForwarder: false, + }; + + try { + // Get counter contract ID + const counterContractId = await this.counterAppGateway.counter(); + + // Check if forwarder exists + const forwarderAddress = await this.counterAppGateway.forwarderAddresses( + counterContractId, + chainId + ); + + if (forwarderAddress !== ethers.constants.AddressZero) { + // Forwarder exists, call increment + result.hasForwarder = true; + result.forwarderAddress = forwarderAddress; + console.log(` ✓ Forwarder exists: ${forwarderAddress}`); + console.log(` → Calling incrementCounters...`); + + const tx = await this.counterAppGateway.incrementCounters([ + forwarderAddress, + ]); + result.txHash = tx.hash; + console.log(` → Transaction: ${tx.hash}`); + + await tx.wait(); + console.log(` ✓ Transaction confirmed`); + } else { + // No forwarder, deploy contracts + result.hasForwarder = false; + console.log(` ✗ No forwarder found`); + console.log(` → Calling deployContracts...`); + + const tx = await this.counterAppGateway.deployContracts(chainId); + result.txHash = tx.hash; + console.log(` → Transaction: ${tx.hash}`); + + await tx.wait(); + console.log(` ✓ Transaction confirmed`); + } + } catch (error) { + result.error = error instanceof Error ? error.message : String(error); + console.log(` ✗ Error: ${result.error}`); + } + + return result; + } + + async checkTransactionStatus(txHash: string): Promise { + const maxRetries = 12; // 12 * 5 seconds = 1 minute + let retries = 0; + + while (retries < maxRetries) { + try { + console.log( + ` Checking status... (attempt ${retries + 1}/${maxRetries})` + ); + + const response = await axios.get( + `${process.env.API_BASE_URL}/getDetailsByTxHash?txHash=${txHash}`, + { timeout: 10000 } + ); + + const data: StatusResponse = response.data; + + if (data.status === "SUCCESS" && data.response.length > 0) { + const status = data.response[0].status; + console.log(` Status: ${status}`); + + if (status === "COMPLETED") { + return "COMPLETED"; + } else if (status === "REVERTING") { + return "REVERTING"; + } + // Continue checking if status is still processing + } + + retries++; + if (retries < maxRetries) { + console.log(` Waiting 5 seconds before next check...`); + await new Promise((resolve) => setTimeout(resolve, 5000)); + } + } catch (error) { + console.log( + ` API error: ${ + error instanceof Error ? error.message : String(error) + }` + ); + retries++; + if (retries < maxRetries) { + await new Promise((resolve) => setTimeout(resolve, 5000)); + } + } + } + + return "TIMEOUT"; + } + + async runTests(): Promise { + console.log("SOCKET PROTOCOL CHAIN TESTING"); + console.log("=".repeat(80)); + console.log( + `Testing ${TEST_CHAINS.length} chains: ${TEST_CHAINS.join(", ")}` + ); + console.log(""); + + // Check balance first + await this.checkBalance(); + + console.log("=".repeat(80)); + console.log("TESTING CHAINS"); + console.log("=".repeat(80)); + + // Test each chain + for (const chainId of TEST_CHAINS) { + const result = await this.testChain(chainId); + this.results.push(result); + + // Check transaction status if we have a tx hash + if (result.txHash) { + console.log(` → Monitoring transaction status...`); + result.status = await this.checkTransactionStatus(result.txHash); + console.log(` → Final status: ${result.status}`); + } + + console.log(""); + } + + this.printSummary(); + } + + private printSummary(): void { + console.log("=".repeat(80)); + console.log("SUMMARY REPORT"); + console.log("=".repeat(80)); + + let successCount = 0; + let errorCount = 0; + let deployedCount = 0; + let incrementedCount = 0; + + console.log("Chain Results:"); + console.log("-".repeat(80)); + + for (const result of this.results) { + const statusIcon = result.error ? "✗" : "✓"; + const action = result.hasForwarder ? "INCREMENT" : "DEPLOY"; + const status = result.status || (result.error ? "ERROR" : "UNKNOWN"); + + console.log( + `${statusIcon} ${result.chainName.padEnd(20)} | ${action.padEnd( + 10 + )} | ${status.padEnd(12)} | ${result.txHash || "N/A"}` + ); + + if (!result.error) { + successCount++; + if (result.hasForwarder) { + incrementedCount++; + } else { + deployedCount++; + } + } else { + errorCount++; + } + } + + console.log("-".repeat(80)); + console.log(`Total Chains: ${this.results.length}`); + console.log(`Successful: ${successCount}`); + console.log(`Errors: ${errorCount}`); + console.log(`Deployments: ${deployedCount}`); + console.log(`Increments: ${incrementedCount}`); + + const completedTxs = this.results.filter( + (r) => r.status === "COMPLETED" + ).length; + const revertingTxs = this.results.filter( + (r) => r.status === "REVERTING" + ).length; + const timeoutTxs = this.results.filter( + (r) => r.status === "TIMEOUT" + ).length; + + console.log(`Completed Transactions: ${completedTxs}`); + console.log(`Reverting Transactions: ${revertingTxs}`); + console.log(`Timeout Transactions: ${timeoutTxs}`); + + console.log("=".repeat(80)); + + if (errorCount > 0) { + console.log("ERRORS:"); + for (const result of this.results.filter((r) => r.error)) { + console.log(` ${result.chainName}: ${result.error}`); + } + console.log("=".repeat(80)); + } + } +} + +// Main execution +async function main() { + try { + // Validate required environment variables + const requiredEnvVars = [ + "EVMX_RPC", + "PRIVATE_KEY", + "COUNTER_APP_GATEWAY", + "FEES_MANAGER", + "API_BASE_URL", + ]; + + for (const envVar of requiredEnvVars) { + if (!process.env[envVar]) { + throw new Error(`Missing required environment variable: ${envVar}`); + } + } + + const tester = new ChainTester(); + await tester.runTests(); + } catch (error) { + console.error("Fatal error:", error); + process.exit(1); + } +} + +if (require.main === module) { + main(); +} diff --git a/hardhat-scripts/test/gas-fees.ts b/hardhat-scripts/test/gas-fees.ts new file mode 100644 index 00000000..00cecc30 --- /dev/null +++ b/hardhat-scripts/test/gas-fees.ts @@ -0,0 +1,65 @@ +import { ethers } from "ethers"; +import { config as dotenvConfig } from "dotenv"; +dotenvConfig(); +import { ChainSlug } from "../../src"; + +async function main() { + console.log("=".repeat(80)); + console.log("GAS FEE DATA ACROSS CHAINS"); + console.log("=".repeat(80)); + + const chains = [ChainSlug.MAINNET]; + console.log(chains); + for (const chainId of chains) { + try { + console.log(`\nChain: ${chainId}`); + console.log("-".repeat(40)); + + const provider = new ethers.providers.JsonRpcProvider( + process.env.MAINNET_RPC + ); + + const feeData = await provider.getFeeData(); + const gasPrice = await provider.getGasPrice(); + console.log( + "Gas Price:", + ethers.utils.formatUnits(feeData.gasPrice || 0, "gwei"), + "gwei" + ); + console.log( + "Last Base Fee Per Gas:", + ethers.utils.formatUnits(feeData.lastBaseFeePerGas || 0, "gwei"), + "gwei" + ); + console.log( + "Max Fee Per Gas:", + ethers.utils.formatUnits(feeData.maxFeePerGas || 0, "gwei"), + "gwei" + ); + console.log( + "Max Priority Fee Per Gas:", + ethers.utils.formatUnits(feeData.maxPriorityFeePerGas || 0, "gwei"), + "gwei" + ); + + console.log( + "Gas Price:", + ethers.utils.formatUnits(gasPrice, "gwei"), + "gwei" + ); + } catch (error: any) { + console.log( + `Error fetching fee data for chain ${chainId}:`, + error.message + ); + } + } +} + +// Run if called directly +if (require.main === module) { + main().catch((error) => { + console.error("Error:", error); + process.exit(1); + }); +} diff --git a/hardhat-scripts/utils/address.ts b/hardhat-scripts/utils/address.ts index 254facbb..e87c4e3e 100644 --- a/hardhat-scripts/utils/address.ts +++ b/hardhat-scripts/utils/address.ts @@ -1,6 +1,7 @@ import dev_addresses from "../../deployments/dev_addresses.json"; import stage_addresses from "../../deployments/stage_addresses.json"; import local_addresses from "../../deployments/local_addresses.json"; +import prod_addresses from "../../deployments/prod_addresses.json"; import { ChainAddressesObj, EVMxAddressesObj } from "../../src/types"; import { DeploymentMode } from "../../src/enums"; @@ -17,6 +18,9 @@ export const getAddresses = ( case DeploymentMode.STAGE: // @ts-ignore return stage_addresses; + case DeploymentMode.PROD: + // @ts-ignore + return prod_addresses; default: throw new Error(`Invalid deployment mode: ${mode}`); } diff --git a/hardhat-scripts/utils/appConfig.ts b/hardhat-scripts/utils/appConfig.ts index 5f2b4b9b..ddd74a28 100644 --- a/hardhat-scripts/utils/appConfig.ts +++ b/hardhat-scripts/utils/appConfig.ts @@ -1,13 +1,18 @@ import { Contract } from "ethers"; import { toBytes32Format } from "./address"; +import { getReadOverrides, overrides } from "./overrides"; +import { EVMX_CHAIN_ID } from "../config"; export const isConfigSetOnSocket = async ( plug: Contract, socket: Contract, appGatewayId: string, - switchboardId: string + switchboardId: string, + chain: number ) => { - const plugConfigRegistered = await socket.getPlugConfig(plug.address); + const plugConfigRegistered = await socket.getPlugConfig(plug.address, { + ...(await getReadOverrides(chain)), + }); return ( plugConfigRegistered.appGatewayId.toLowerCase() === appGatewayId.toLowerCase() && @@ -22,9 +27,12 @@ export const isConfigSetOnEVMx = async ( appGatewayId: string, switchboardId: string ) => { - const plugConfigRegistered = await watcher.getPlugConfigs( + const plugConfigRegistered = await watcher.callStatic.getPlugConfigs( chain, - toBytes32Format(plug) + toBytes32Format(plug), + { + ...(await getReadOverrides(EVMX_CHAIN_ID)), + } ); return ( plugConfigRegistered[0].toLowerCase() === appGatewayId?.toLowerCase() && diff --git a/hardhat-scripts/utils/deployUtils.ts b/hardhat-scripts/utils/deployUtils.ts index dd71525e..ec50427a 100644 --- a/hardhat-scripts/utils/deployUtils.ts +++ b/hardhat-scripts/utils/deployUtils.ts @@ -11,6 +11,7 @@ import { getAddresses, overrides } from "../utils"; import { VerifyArgs } from "../verify"; import { DeploymentAddresses } from "../constants"; import { EVMX_CHAIN_ID, mode } from "../config"; +import { parseUnits } from "ethers/lib/utils"; export const deploymentsPath = path.join(__dirname, `/../../deployments/`); @@ -87,9 +88,10 @@ export async function deployContractWithArgs( const Contract: ContractFactory = await ethers.getContractFactory( contractName ); + const override = await overrides(chainSlug); // gasLimit is set to undefined to not use the value set in overrides const contract: Contract = await Contract.connect(signer).deploy(...args, { - ...(await overrides(chainSlug)), + ...override, }); await contract.deployed(); return contract; @@ -115,8 +117,11 @@ export const verify = async ( }); return true; } catch (error) { - console.log("Error during verification", error); - if (error.toString().includes("Contract source code already verified")) + console.log("Error during verification", error.toString()); + if ( + error.toString().includes("Contract source code already verified") || + error.toString().includes("already verified") + ) return true; } @@ -130,9 +135,29 @@ export const getInstance = async ( (await ethers.getContractFactory(contractName)).attach(address); export const getChainSlug = async (): Promise => { - if (network.config.chainId === undefined) - throw new Error("chain id not found"); - return Number(network.config.chainId); + // Try to get chain ID from network config first + if (network.config.chainId !== undefined) { + return Number(network.config.chainId); + } + + // If network config doesn't have chainId, try to get it from the provider + try { + const provider = network.provider; + if (provider && "url" in network.config && network.config.url) { + // Try to get chain ID using ethers provider + const ethersProvider = new ethers.providers.JsonRpcProvider( + network.config.url + ); + const networkDetails = await ethersProvider.getNetwork(); + if (networkDetails && networkDetails.chainId) { + return Number(networkDetails.chainId); + } + } + } catch (error) { + console.warn("Could not get chain ID from provider:", error); + } + + throw new Error("chain id not found in network config or provider"); }; export const integrationType = (integrationName: string) => diff --git a/hardhat-scripts/utils/gatewayId.ts b/hardhat-scripts/utils/gatewayId.ts index a24fc02d..fcc4c3d7 100644 --- a/hardhat-scripts/utils/gatewayId.ts +++ b/hardhat-scripts/utils/gatewayId.ts @@ -14,6 +14,7 @@ export const getAppGatewayId = ( if (!address) throw new Error(`WritePrecompile not found on EVMX`); return ethers.utils.hexZeroPad(address, 32); case Contracts.FeesPlug: + case Contracts.SUSDC: address = addresses?.[EVMX_CHAIN_ID]?.[Contracts.FeesManager]; if (!address) throw new Error(`FeesManager not found on EVMX`); return ethers.utils.hexZeroPad(address, 32); diff --git a/hardhat-scripts/utils/overrides.ts b/hardhat-scripts/utils/overrides.ts index 4f05c3b0..dc4c17d2 100644 --- a/hardhat-scripts/utils/overrides.ts +++ b/hardhat-scripts/utils/overrides.ts @@ -2,21 +2,46 @@ import { ChainSlug } from "../../src"; import { BigNumber, BigNumberish, Contract, providers, Signer } from "ethers"; import { EVMX_CHAIN_ID } from "../config/config"; import { getProviderFromChainSlug } from "./networks"; +import { parseUnits } from "ethers/lib/utils"; const defaultType = 0; +const DEFAULT_GAS_PRICE_MULTIPLIER = 1.05; + +type ChainOverride = { + type?: number; + gasLimit?: number; + gasPrice?: BigNumberish; + maxPriorityFeePerGas?: BigNumberish; + maxFeePerGas?: BigNumberish; + gasPriceMultiplier?: number; +}; export const chainOverrides: { - [chainSlug in ChainSlug]?: { - type?: number; - gasLimit?: number; - gasPrice?: number; - }; + [chainSlug in ChainSlug]?: ChainOverride; } = { [ChainSlug.ARBITRUM_SEPOLIA]: { - // type: 2, - // gasLimit: 50_000_000, - gasPrice: 800_000_000, + type: 1, + gasLimit: 50_000_000, + gasPrice: 200_000_000, + }, + [ChainSlug.BASE_SEPOLIA]: { + type: 1, + gasLimit: 3_000_000, + // gasPrice: 200_000_000, + }, + [ChainSlug.BSC]: { + gasLimit: 6_000_000, }, + [ChainSlug.MAINNET]: { + gasLimit: 6_000_000, + gasPriceMultiplier: 1.25, + }, + + [ChainSlug.POLYGON_MAINNET]: { + gasPriceMultiplier: 2, + gasLimit: 3_000_000, + }, + [ChainSlug.SEPOLIA]: { type: 1, gasLimit: 2_000_000, @@ -28,15 +53,41 @@ export const chainOverrides: { // gasPrice: 212_000_000_000, }, [ChainSlug.BASE]: { - // gasLimit: 2_000_000, + gasLimit: 2_000_000, + }, + [ChainSlug.BERA]: { + gasPrice: parseUnits("3", "gwei"), + gasLimit: 10_000_000, + gasPriceMultiplier: 2, + }, + [ChainSlug.AVALANCHE]: { + gasLimit: 3_000_000, + }, + [ChainSlug.GNOSIS]: { + gasLimit: 15_000_000, + gasPriceMultiplier: 2, + }, + [ChainSlug.LINEA]: { + gasLimit: 10_000_000, }, [ChainSlug.ARBITRUM]: { - gasPrice: 100_629_157, + // gasPrice: 100_629_157, + }, + [ChainSlug.SEI]: { + gasLimit: 3_000_000, + }, + [ChainSlug.HYPEREVM]: { + gasLimit: 1_000_000, + }, + [ChainSlug.MANTLE]: { + gasLimit: 10_000_551_690, + gasPrice: parseUnits("0.03", "gwei"), }, + [EVMX_CHAIN_ID as ChainSlug]: { // type: 0, // // gasLimit: 1_000_000_000, - // gasPrice: 0, + // gasPrice: parseUnits("0.1", "gwei"), }, }; @@ -57,15 +108,19 @@ export const getOverrides = async ( chainSlug: ChainSlug, provider: providers.StaticJsonRpcProvider ) => { - let overrides = chainOverrides[chainSlug]; - let gasPrice = overrides?.gasPrice; - let gasLimit = overrides?.gasLimit; - let type = overrides?.type; - if (gasPrice == undefined || gasPrice == null) - gasPrice = (await getGasPrice(chainSlug, provider)).toNumber(); - if (type == undefined) type = defaultType; - // if gas limit is undefined, ethers will calcuate it automatically. If want to override, - // add in the overrides object. Dont set a default value + const overrides = chainOverrides[chainSlug] || {}; + const { gasLimit, type = defaultType } = overrides; + + let gasPrice = overrides.gasPrice; + if (!gasPrice) { + const baseGasPrice = await provider.getGasPrice(); + const multiplier = + overrides.gasPriceMultiplier || DEFAULT_GAS_PRICE_MULTIPLIER; + gasPrice = baseGasPrice + .mul(Math.round(multiplier * 1000)) + .div(1000) + .toNumber(); + } return { gasLimit, gasPrice, type }; }; @@ -80,3 +135,9 @@ export const getGasPrice = async ( } return gasPrice; }; + +export const getReadOverrides = async (chainSlug: ChainSlug) => { + return chainSlug == ChainSlug.MANTLE + ? await overrides(chainSlug as ChainSlug) + : {}; +}; diff --git a/hardhat-scripts/verify/verify.ts b/hardhat-scripts/verify/verify.ts index eaec585c..e228e8ac 100644 --- a/hardhat-scripts/verify/verify.ts +++ b/hardhat-scripts/verify/verify.ts @@ -5,12 +5,15 @@ import { ChainSlugToKey, } from "../../src"; import hre from "hardhat"; -import { EVMX_CHAIN_ID, mode } from "../config/config"; +import { ethers } from "ethers"; +import { CONCURRENCY_LIMIT, EVMX_CHAIN_ID, mode } from "../config/config"; import { storeUnVerifiedParams, verify } from "../utils"; +import pLimit from "p-limit"; import local_addresses from "../../deployments/local_addresses.json"; import dev_verification from "../../deployments/dev_verification.json"; import stage_verification from "../../deployments/stage_verification.json"; +import prod_verification from "../../deployments/prod_verification.json"; const getVerificationParams = (mode: DeploymentMode) => { switch (mode) { @@ -21,6 +24,8 @@ const getVerificationParams = (mode: DeploymentMode) => { return dev_verification; case DeploymentMode.STAGE: return stage_verification; + case DeploymentMode.PROD: + return prod_verification; default: throw new Error(`Invalid deployment mode: ${mode}`); } @@ -37,46 +42,101 @@ export type VerifyArgs = [string, string, string, any[]]; export const main = async () => { try { const verificationParams = getVerificationParams(mode); - const chains = Object.keys(verificationParams); + const chains = Object.keys(verificationParams).map( + (chain) => parseInt(chain) as ChainSlug + ); + console.log({ chains }); if (!chains) return; - for (let chainIndex = 0; chainIndex < chains.length; chainIndex++) { - const chain = parseInt(chains[chainIndex]) as ChainSlug; - let chainName: string; - if (chain == (EVMX_CHAIN_ID as ChainSlug)) { - chainName = "EVMX"; - } else { - chainName = ChainSlugToKey[chain]; - } - console.log({ chainName }); + for (let chain of chains) { + await verifyChain(chain, verificationParams[chain]); + } + // const limit = pLimit(1); + // const chainTasks = chains.map(async (chain) => { + // limit(() => verifyChain(chain, verificationParams[chain])); + // }); + // await Promise.all(chainTasks); + } catch (error) { + console.log("Error in verifying contracts", error); + } +}; + +export const verifyChain = async ( + chain: number, + verificationParams: VerifyArgs[] +) => { + try { + let chainName: string; + // if (chain!=999) return; + // if ([130, 5000, 1329, 57073, 747, 169].includes(chain)) { + // console.log(`Skipping chain: ${chain}`); + // return; + // } + + if (chain == (EVMX_CHAIN_ID as ChainSlug)) { + chainName = "EVMX"; + } else { + chainName = ChainSlugToKey[chain]; + } + console.log({ chainName, chain }); + if (!chainName) { + console.log(`Invalid chain: ${chain}`); + return; + } + console.log("Changing network to", chainName); + + try { hre.changeNetwork(chainName); + // Wait a bit for network change to complete + await new Promise((resolve) => setTimeout(resolve, 1000)); - const chainParams: VerifyArgs[] = verificationParams[chain]; - let retryCount = 0; + // Verify the network change was successful + try { + if ("url" in hre.network.config && hre.network.config.url) { + const ethersProvider = new ethers.providers.JsonRpcProvider( + hre.network.config.url + ); + const currentChainId = await ethersProvider + .getNetwork() + .then((n) => n.chainId); + console.log( + `Successfully changed to network ${chainName} with chain ID ${currentChainId}` + ); + } else { + console.log(`Successfully changed to network ${chainName}`); + } + } catch (error) { + console.log(`Successfully changed to network ${chainName}`); + } + } catch (networkError) { + console.error(`Failed to change network to ${chainName}:`, networkError); + return; + } - while (retryCount < 5) { - const unverifiedChainParams: VerifyArgs[] = []; - if (chainParams.length) { - const len = chainParams.length; - for (let index = 0; index < len!; index++) { - const res = await verify(...chainParams[index]); - if (!res) { - unverifiedChainParams.push(chainParams[index]); - } + const chainParams: VerifyArgs[] = verificationParams as VerifyArgs[]; + let retryCount = 0; + + while (retryCount < 1) { + const unverifiedChainParams: VerifyArgs[] = []; + if (chainParams.length) { + const len = chainParams.length; + for (let index = 0; index < len!; index++) { + const res = await verify(...chainParams[index]); + if (!res) { + unverifiedChainParams.push(chainParams[index]); } } - await storeUnVerifiedParams(unverifiedChainParams, chain, mode); - - await new Promise((resolve) => setTimeout(resolve, 1000)); - retryCount++; - if (unverifiedChainParams.length == 0) break; } + await storeUnVerifiedParams(unverifiedChainParams, chain, mode); + + await new Promise((resolve) => setTimeout(resolve, 1000)); + retryCount++; + if (unverifiedChainParams.length == 0) break; } } catch (error) { console.log("Error in verifying contracts", error); } }; - main() .then(() => process.exit(0)) .catch((error: Error) => { diff --git a/hardhat.config.ts b/hardhat.config.ts index d94a5db6..40ec837b 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -61,8 +61,26 @@ let liveNetworks = { [HardhatChainName.SEPOLIA]: getChainConfig(ChainSlug.SEPOLIA), [HardhatChainName.BASE_SEPOLIA]: getChainConfig(ChainSlug.BASE_SEPOLIA), [HardhatChainName.BASE]: getChainConfig(ChainSlug.BASE), + [HardhatChainName.BSC]: getChainConfig(ChainSlug.BSC), [HardhatChainName.ARBITRUM]: getChainConfig(ChainSlug.ARBITRUM), [HardhatChainName.OPTIMISM]: getChainConfig(ChainSlug.OPTIMISM), + [HardhatChainName.KATANA]: getChainConfig(ChainSlug.KATANA), + [HardhatChainName.SONIC]: getChainConfig(ChainSlug.SONIC), + [HardhatChainName.LINEA]: getChainConfig(ChainSlug.LINEA), + [HardhatChainName.AVALANCHE]: getChainConfig(ChainSlug.AVALANCHE), + [HardhatChainName.GNOSIS]: getChainConfig(ChainSlug.GNOSIS), + [HardhatChainName.POLYGON_MAINNET]: getChainConfig(ChainSlug.POLYGON_MAINNET), + [HardhatChainName.MAINNET]: getChainConfig(ChainSlug.MAINNET), + [HardhatChainName.HYPEREVM]: getChainConfig(ChainSlug.HYPEREVM), + [HardhatChainName.FLOW]: getChainConfig(ChainSlug.FLOW), + [HardhatChainName.MANTA_PACIFIC]: getChainConfig(ChainSlug.MANTA_PACIFIC), + [HardhatChainName.MANTLE]: getChainConfig(ChainSlug.MANTLE), + [HardhatChainName.CAMP]: getChainConfig(ChainSlug.CAMP), + [HardhatChainName.INK]: getChainConfig(ChainSlug.INK), + [HardhatChainName.SEI]: getChainConfig(ChainSlug.SEI), + [HardhatChainName.UNICHAIN]: getChainConfig(ChainSlug.UNICHAIN), + [HardhatChainName.BERA]: getChainConfig(ChainSlug.BERA), + EVMX: { accounts: [`0x${privateKey}`], chainId: EVMX_CHAIN_ID, @@ -89,58 +107,156 @@ const config: HardhatUserConfig = { }, etherscan: { apiKey: { - arbitrumOne: process.env.ARBISCAN_API_KEY || "", - arbitrumTestnet: process.env.ARBISCAN_API_KEY || "", - baseTestnet: process.env.BASESCAN_API_KEY || "", - base: process.env.BASESCAN_API_KEY || "", - bsc: process.env.BSCSCAN_API_KEY || "", - bscTestnet: process.env.BSCSCAN_API_KEY || "", - goerli: process.env.ETHERSCAN_API_KEY || "", + // Etherscan API v2 - single key for all Etherscan-based explorers mainnet: process.env.ETHERSCAN_API_KEY || "", sepolia: process.env.ETHERSCAN_API_KEY || "", - optimisticEthereum: process.env.OPTIMISM_API_KEY || "", - optimisticTestnet: process.env.OPTIMISM_API_KEY || "", - EVMX: "none", + goerli: process.env.ETHERSCAN_API_KEY || "", + arbitrum: process.env.ETHERSCAN_API_KEY || "", + arbitrumSepolia: process.env.ETHERSCAN_API_KEY || "", + optimism: process.env.ETHERSCAN_API_KEY || "", + optimismSepolia: process.env.ETHERSCAN_API_KEY || "", + polygon: process.env.ETHERSCAN_API_KEY || "", + polygonAmoy: process.env.ETHERSCAN_API_KEY || "", + base: process.env.ETHERSCAN_API_KEY || "", + baseSepolia: process.env.ETHERSCAN_API_KEY || "", + bsc: process.env.ETHERSCAN_API_KEY || "", + bscTestnet: process.env.ETHERSCAN_API_KEY || "", + avalanche: process.env.ETHERSCAN_API_KEY || "", + gnosis: process.env.ETHERSCAN_API_KEY || "", + linea: process.env.ETHERSCAN_API_KEY || "", + zkSync: process.env.ETHERSCAN_API_KEY || "", + scroll: process.env.ETHERSCAN_API_KEY || "", + // Blockscout-based explorers + mantle: + process.env.BLOCKSCOUT_API_KEY || process.env.ETHERSCAN_API_KEY || "", + camp: + process.env.BLOCKSCOUT_API_KEY || process.env.ETHERSCAN_API_KEY || "", + flow: + process.env.BLOCKSCOUT_API_KEY || process.env.ETHERSCAN_API_KEY || "", + manta_pacific: + process.env.BLOCKSCOUT_API_KEY || process.env.ETHERSCAN_API_KEY || "", + + // Other custom explorers + sonic: process.env.ETHERSCAN_API_KEY || "", + katana: process.env.ETHERSCAN_API_KEY || "", + hyperevm: process.env.ETHERSCAN_API_KEY || "", + ink: process.env.ETHERSCAN_API_KEY || "", + bera: process.env.ETHERSCAN_API_KEY || "", + unichain: process.env.ETHERSCAN_API_KEY || "", + sei: process.env.ETHERSCAN_API_KEY || "", + zero: process.env.ETHERSCAN_API_KEY || "", + arenaZ: process.env.ETHERSCAN_API_KEY || "", + b3: process.env.ETHERSCAN_API_KEY || "", + monadTestnet: process.env.ETHERSCAN_API_KEY || "", + soneium: process.env.ETHERSCAN_API_KEY || "", + swellchain: process.env.ETHERSCAN_API_KEY || "", + worldChain: process.env.ETHERSCAN_API_KEY || "", + plume: process.env.ETHERSCAN_API_KEY || "", + riseTestnet: process.env.ETHERSCAN_API_KEY || "", }, customChains: [ { - network: "optimisticTestnet", - chainId: ChainId.OPTIMISM_SEPOLIA, + network: HardhatChainName.BSC, + chainId: ChainSlugToId[ChainSlug.BSC], + urls: { + apiURL: "https://api.etherscan.io/v2/api?chainid=56", + browserURL: "https://bscscan.com/", + }, + }, + { + network: HardhatChainName.MANTLE, + chainId: ChainSlugToId[ChainSlug.MANTLE], + urls: { + apiURL: "https://api.etherscan.io/v2/api?chainid=5000", + browserURL: "https://explorer.mantle.xyz/", + }, + }, + { + network: HardhatChainName.UNICHAIN, + chainId: ChainSlugToId[ChainSlug.UNICHAIN], + urls: { + apiURL: "https://api.etherscan.io/v2/api?chainid=130", + browserURL: "https://uniscan.xyz/", + }, + }, + { + network: HardhatChainName.SONIC, + chainId: ChainId.SONIC, + urls: { + apiURL: "https://api.etherscan.io/v2/api?chainid=146", + browserURL: "https://sonicscan.org", + }, + }, + { + network: HardhatChainName.BERA, + chainId: ChainId.BERA, urls: { - apiURL: "https://api-sepolia-optimistic.etherscan.io/api", - browserURL: "https://sepolia-optimism.etherscan.io/", + apiURL: "https://api.etherscan.io/v2/api?chainid=80094", + browserURL: "https://berascan.com/", }, }, { - network: "arbitrumTestnet", - chainId: ChainId.ARBITRUM_SEPOLIA, + network: HardhatChainName.KATANA, + chainId: ChainId.KATANA, urls: { - apiURL: "https://api-sepolia.arbiscan.io/api", - browserURL: "https://sepolia.arbiscan.io/", + apiURL: "https://api.etherscan.io/v2/api?chainid=747474", + browserURL: "https://katanascan.com/", }, }, { - network: "baseTestnet", - chainId: ChainId.BASE_SEPOLIA, + network: HardhatChainName.INK, + chainId: ChainId.INK, urls: { - apiURL: "https://api-sepolia.basescan.org/api", - browserURL: "https://sepolia.basescan.org/", + apiURL: "https://explorer.inkonchain.com/api", + browserURL: "https://explorer.inkonchain.com/", }, }, { - network: "base", - chainId: ChainId.BASE, + network: "hyperevm", + chainId: ChainId.HYPEREVM, urls: { - apiURL: "https://api.basescan.org/api", - browserURL: "https://basescan.org/", + apiURL: "https://api.etherscan.io/v2/api?chainid=999", + browserURL: "https://hyperevmscan.io/", + }, + }, + { + network: HardhatChainName.SEI, + chainId: ChainId.SEI, + urls: { + apiURL: "https://api.etherscan.io/v2/api?chainid=1329", + browserURL: "https://seiscan.io/", }, }, { network: "EVMX", chainId: EVMX_CHAIN_ID, urls: { - apiURL: "https://explorer-evmx-1dpy1f56o4.t.conduit.xyz/api", - browserURL: "https://explorer-evmx-1dpy1f56o4.t.conduit.xyz/", + apiURL: "https://explorer-evmx-testnet.socket.tech/api", + browserURL: "https://explorer-evmx-testnet.socket.tech/", + }, + }, + { + network: HardhatChainName.CAMP, + chainId: ChainId.CAMP, + urls: { + apiURL: "https://camp.cloud.blockscout.com/api", + browserURL: "https://camp.cloud.blockscout.com/", + }, + }, + { + network: HardhatChainName.MANTA_PACIFIC, + chainId: ChainId.MANTA_PACIFIC, + urls: { + apiURL: "https://pacific-explorer.manta.network/api", + browserURL: "https://pacific-explorer.manta.network/", + }, + }, + { + network: HardhatChainName.FLOW, + chainId: ChainId.FLOW, + urls: { + apiURL: "https://evm.flowscan.io/api", + browserURL: "https://evm.flowscan.io/", }, }, ], diff --git a/package.json b/package.json index e284de83..6732c0a5 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "publishConfig": { "access": "public" }, - "version": "1.1.37", + "version": "1.1.48", "description": "socket protocol", "scripts": { "build": "yarn abi && tsc --project lib.tsconfig.json", @@ -19,15 +19,18 @@ "lintContracts": "prettier \"./**\" --write --plugin=prettier-plugin-solidity", "compile": "forge build", "deploy": "bash setupInfraContracts.sh", + "test:counter": "npx hardhat run hardhat-scripts/test/chainTest.ts --no-compile", + "test:gas": "npx hardhat run hardhat-scripts/test/gas-fees.ts --no-compile", "publish-core": "yarn build && yarn publish --patch --no-git-tag-version", - "trace": "source .env && bash trace.sh" + "trace": "source .env && bash trace.sh", + "add:chain": "npx hardhat run hardhat-scripts/addChain/index.ts --no-compile" }, "pre-commit": [], "author": "", "license": "ISC", "devDependencies": { "@aws-sdk/client-s3": "^3.670.0", - "@nomicfoundation/hardhat-verify": "^2.0.12", + "@nomicfoundation/hardhat-verify": "^2.0.14", "@nomiclabs/hardhat-ethers": "2.2.3", "@socket.tech/socket-protocol-common": "1.1.44", "@typechain/ethers-v5": "^10.0.0", @@ -53,5 +56,7 @@ "typechain": "^8.0.0", "typescript": "^4.6.4" }, - "dependencies": {} + "dependencies": { + "@types/uuid": "^10.0.0" + } } diff --git a/script/counter/DeployEVMxCounterApp.s.sol b/script/counter/DeployEVMxCounterApp.s.sol index 50a81c25..5bf183ca 100644 --- a/script/counter/DeployEVMxCounterApp.s.sol +++ b/script/counter/DeployEVMxCounterApp.s.sol @@ -5,7 +5,7 @@ import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; import {CounterAppGateway} from "../../test/apps/app-gateways/counter/CounterAppGateway.sol"; -// source .env && forge script script/counter/deployEVMxCounterApp.s.sol --broadcast --skip-simulation --legacy --gas-price 0 +// source .env && forge script script/counter/deployEVMxCounterApp.s.sol --broadcast --skip-simulation contract CounterDeploy is Script { function run() external { address addressResolver = vm.envAddress("ADDRESS_RESOLVER"); diff --git a/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol index 2d329a2f..3783000b 100644 --- a/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol +++ b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol @@ -17,7 +17,7 @@ contract WithdrawFees is Script { address token = vm.envAddress("USDC"); CounterAppGateway appGateway = CounterAppGateway(appGatewayAddress); - uint256 availableFees = feesManager.getAvailableCredits(appGatewayAddress); + uint256 availableFees = feesManager.balanceOf(appGatewayAddress); console.log("Available fees:", availableFees); if (availableFees > 0) { diff --git a/script/helpers/CheckDepositedCredits.s.sol b/script/helpers/CheckDepositedCredits.s.sol index ad9bca71..80418fe7 100644 --- a/script/helpers/CheckDepositedCredits.s.sol +++ b/script/helpers/CheckDepositedCredits.s.sol @@ -11,13 +11,14 @@ contract CheckDepositedCredits is Script { FeesManager feesManager = FeesManager(payable(vm.envAddress("FEES_MANAGER"))); address appGateway = vm.envAddress("APP_GATEWAY"); - (uint256 totalCredits, uint256 blockedCredits) = feesManager.userCredits(appGateway); + uint256 totalCredits = feesManager.totalBalanceOf(appGateway); + uint256 blockedCredits = feesManager.getBlockedCredits(appGateway); console.log("App Gateway:", appGateway); console.log("Fees Manager:", address(feesManager)); console.log("totalCredits fees:", totalCredits); console.log("blockedCredits fees:", blockedCredits); - uint256 availableFees = feesManager.getAvailableCredits(appGateway); + uint256 availableFees = feesManager.balanceOf(appGateway); console.log("Available fees:", availableFees); } } diff --git a/script/helpers/DepositCredit.s.sol b/script/helpers/DepositCredit.s.sol index b8d432f8..49e94fe0 100644 --- a/script/helpers/DepositCredit.s.sol +++ b/script/helpers/DepositCredit.s.sol @@ -30,6 +30,6 @@ contract DepositCredit is Script { console.log("App Gateway:", appGateway); console.log("Fees Plug:", address(feesPlug)); console.log("Fees Amount:", feesAmount); - feesPlug.depositCredit(address(testUSDCContract), appGateway, feesAmount); + feesPlug.depositCredit(address(testUSDCContract), appGateway, feesAmount, bytes("")); } } diff --git a/script/helpers/DepositCreditAndNative.s.sol b/script/helpers/DepositCreditAndNative.s.sol index 629a3998..47a0cf0d 100644 --- a/script/helpers/DepositCreditAndNative.s.sol +++ b/script/helpers/DepositCreditAndNative.s.sol @@ -30,6 +30,11 @@ contract DepositCreditAndNative is Script { console.log("App Gateway:", appGateway); console.log("Fees Plug:", address(feesPlug)); console.log("Fees Amount:", feesAmount); - feesPlug.depositCreditAndNative(address(testUSDCContract), appGateway, feesAmount); + feesPlug.depositCreditAndNative( + address(testUSDCContract), + appGateway, + feesAmount, + bytes("") + ); } } diff --git a/script/helpers/DepositCreditMainnet.s.sol b/script/helpers/DepositCreditMainnet.s.sol index 4e1a8e33..06b58eab 100644 --- a/script/helpers/DepositCreditMainnet.s.sol +++ b/script/helpers/DepositCreditMainnet.s.sol @@ -31,6 +31,6 @@ contract DepositCredit is Script { console.log("App Gateway:", appGateway); console.log("Fees Plug:", address(feesPlug)); console.log("Fees Amount:", feesAmount); - feesPlug.depositCredit(address(USDCContract), appGateway, feesAmount); + feesPlug.depositCredit(address(USDCContract), appGateway, feesAmount, bytes("")); } } diff --git a/script/helpers/TransferRemainingCredits.s.sol b/script/helpers/TransferRemainingCredits.s.sol index e0ae8cea..6ebec144 100644 --- a/script/helpers/TransferRemainingCredits.s.sol +++ b/script/helpers/TransferRemainingCredits.s.sol @@ -17,17 +17,19 @@ contract TransferRemainingCredits is Script { address appGateway = vm.envAddress("APP_GATEWAY"); address newAppGateway = vm.envAddress("NEW_APP_GATEWAY"); - (uint256 totalCredits, uint256 blockedCredits) = feesManager.userCredits(appGateway); + uint256 totalCredits = feesManager.totalBalanceOf(appGateway); + uint256 blockedCredits = feesManager.getBlockedCredits(appGateway); console.log("App Gateway:", appGateway); console.log("New App Gateway:", newAppGateway); console.log("Fees Manager:", address(feesManager)); console.log("totalCredits fees:", totalCredits); console.log("blockedCredits fees:", blockedCredits); - uint256 availableFees = feesManager.getAvailableCredits(appGateway); + uint256 availableFees = feesManager.balanceOf(appGateway); console.log("Available fees:", availableFees); bytes memory data = abi.encodeWithSignature( - "transferCredits(address,uint256)", + "transferFrom(address,address,uint256)", + appGateway, newAppGateway, availableFees ); diff --git a/script/helpers/WithdrawRemainingCredits.s.sol b/script/helpers/WithdrawRemainingCredits.s.sol index c0b8bd31..c53cf1ee 100644 --- a/script/helpers/WithdrawRemainingCredits.s.sol +++ b/script/helpers/WithdrawRemainingCredits.s.sol @@ -15,15 +15,16 @@ contract WithdrawRemainingCredits is Script { FeesManager feesManager = FeesManager(payable(vm.envAddress("FEES_MANAGER"))); address appGateway = vm.envAddress("APP_GATEWAY"); - (uint256 totalCredits, uint256 blockedCredits) = feesManager.userCredits(appGateway); + uint256 totalCredits = feesManager.totalBalanceOf(appGateway); + uint256 blockedCredits = feesManager.getBlockedCredits(appGateway); console.log("App Gateway:", appGateway); console.log("Fees Manager:", address(feesManager)); console.log("totalCredits fees:", totalCredits); console.log("blockedCredits fees:", blockedCredits); - uint256 availableFees = feesManager.getAvailableCredits(appGateway); + uint256 availableFees = feesManager.balanceOf(appGateway); console.log("Available fees:", availableFees); - feesManager.transferCredits(appGateway, vm.addr(deployerPrivateKey), availableFees); + feesManager.transferFrom(appGateway, vm.addr(deployerPrivateKey), availableFees); vm.stopBroadcast(); } diff --git a/setupInfraContracts.sh b/setupInfraContracts.sh index c08fed42..9ccfe59b 100644 --- a/setupInfraContracts.sh +++ b/setupInfraContracts.sh @@ -1,4 +1,4 @@ -if [ "$1" = "skip-compile" ]; then +if [ "$1" = "skip" ]; then time npx hardhat run hardhat-scripts/deploy/1.deploy.ts --no-compile else time npx hardhat run hardhat-scripts/deploy/1.deploy.ts @@ -15,5 +15,7 @@ time npx hardhat run hardhat-scripts/misc-scripts/errorCodes.ts --no-compile time npx hardhat run hardhat-scripts/misc-scripts/eventTopics.ts --no-compile time npx hardhat run hardhat-scripts/misc-scripts/functionSigs.ts --no-compile time npx ts-node hardhat-scripts/misc-scripts/createLabels.ts +yarn lint time npx hardhat run hardhat-scripts/verify/verify.ts --no-compile -yarn lint \ No newline at end of file + +time npx hardhat run hardhat-scripts/deploy/deployTestUSDC.ts --no-compile diff --git a/src/chain-enums/chainId.ts b/src/chain-enums/chainId.ts index 69a11947..c02af505 100644 --- a/src/chain-enums/chainId.ts +++ b/src/chain-enums/chainId.ts @@ -59,4 +59,24 @@ export enum ChainId { INTEROP_ALPHA_1 = 420120001, SOLANA_MAINNET = 10000001, SOLANA_DEVNET = 10000002, + SONIC = 146, + KATANA = 747474, + HYPEREVM = 999, + SEI = 1329, + ZERO = 543210, + ZKSYNC = 324, + ARENA_Z = 7897, + INK = 57073, + BERA = 80094, + B3 = 8333, + UNICHAIN = 130, + MONAD_TESTNET = 10143, + SCROLL = 534352, + SONEIUM = 1868, + SWELLCHAIN = 1923, + WORLD_CHAIN = 480, + FLOW = 747, + CAMP = 484, + PLUME = 98866, + RISE_TESTNET = 11155931, } diff --git a/src/chain-enums/chainSlug.ts b/src/chain-enums/chainSlug.ts index d62533f8..c0d9089e 100644 --- a/src/chain-enums/chainSlug.ts +++ b/src/chain-enums/chainSlug.ts @@ -61,4 +61,24 @@ export enum ChainSlug { INTEROP_ALPHA_1 = ChainId.INTEROP_ALPHA_1, SOLANA_MAINNET = ChainId.SOLANA_MAINNET, SOLANA_DEVNET = ChainId.SOLANA_DEVNET, + SONIC = ChainId.SONIC, + KATANA = ChainId.KATANA, + HYPEREVM = ChainId.HYPEREVM, + SEI = ChainId.SEI, + ZERO = ChainId.ZERO, + ZKSYNC = ChainId.ZKSYNC, + ARENA_Z = ChainId.ARENA_Z, + INK = ChainId.INK, + BERA = ChainId.BERA, + B3 = ChainId.B3, + UNICHAIN = ChainId.UNICHAIN, + MONAD_TESTNET = ChainId.MONAD_TESTNET, + SCROLL = ChainId.SCROLL, + SONEIUM = ChainId.SONEIUM, + SWELLCHAIN = ChainId.SWELLCHAIN, + WORLD_CHAIN = ChainId.WORLD_CHAIN, + FLOW = ChainId.FLOW, + CAMP = ChainId.CAMP, + PLUME = ChainId.PLUME, + RISE_TESTNET = ChainId.RISE_TESTNET, } diff --git a/src/chain-enums/chainSlugToHardhatChainName.ts b/src/chain-enums/chainSlugToHardhatChainName.ts index 02b6b0ae..e1735dab 100644 --- a/src/chain-enums/chainSlugToHardhatChainName.ts +++ b/src/chain-enums/chainSlugToHardhatChainName.ts @@ -60,4 +60,24 @@ export const chainSlugToHardhatChainName = { [ChainSlug.ZERO_SEPOLIA]: HardhatChainName.ZERO_SEPOLIA, [ChainSlug.INTEROP_ALPHA_0]: HardhatChainName.INTEROP_ALPHA_0, [ChainSlug.INTEROP_ALPHA_1]: HardhatChainName.INTEROP_ALPHA_1, + [ChainSlug.ZERO]: HardhatChainName.ZERO, + [ChainSlug.ZKSYNC]: HardhatChainName.ZKSYNC, + [ChainSlug.ARENA_Z]: HardhatChainName.ARENA_Z, + [ChainSlug.INK]: HardhatChainName.INK, + [ChainSlug.SONIC]: HardhatChainName.SONIC, + [ChainSlug.BERA]: HardhatChainName.BERA, + [ChainSlug.B3]: HardhatChainName.B3, + [ChainSlug.UNICHAIN]: HardhatChainName.UNICHAIN, + [ChainSlug.MONAD_TESTNET]: HardhatChainName.MONAD_TESTNET, + [ChainSlug.SCROLL]: HardhatChainName.SCROLL, + [ChainSlug.SONEIUM]: HardhatChainName.SONEIUM, + [ChainSlug.SWELLCHAIN]: HardhatChainName.SWELLCHAIN, + [ChainSlug.WORLD_CHAIN]: HardhatChainName.WORLD_CHAIN, + [ChainSlug.KATANA]: HardhatChainName.KATANA, + [ChainSlug.HYPEREVM]: HardhatChainName.HYPEREVM, + [ChainSlug.SEI]: HardhatChainName.SEI, + [ChainSlug.FLOW]: HardhatChainName.FLOW, + [ChainSlug.CAMP]: HardhatChainName.CAMP, + [ChainSlug.PLUME]: HardhatChainName.PLUME, + [ChainSlug.RISE_TESTNET]: HardhatChainName.RISE_TESTNET, }; diff --git a/src/chain-enums/chainSlugToId.ts b/src/chain-enums/chainSlugToId.ts index 07b27268..a8e1fe2d 100644 --- a/src/chain-enums/chainSlugToId.ts +++ b/src/chain-enums/chainSlugToId.ts @@ -60,4 +60,24 @@ export const ChainSlugToId = { [ChainSlug.ZERO_SEPOLIA]: ChainId.ZERO_SEPOLIA, [ChainSlug.INTEROP_ALPHA_0]: ChainId.INTEROP_ALPHA_0, [ChainSlug.INTEROP_ALPHA_1]: ChainId.INTEROP_ALPHA_1, + [ChainSlug.FLOW]: ChainId.FLOW, + [ChainSlug.CAMP]: ChainId.CAMP, + [ChainSlug.PLUME]: ChainId.PLUME, + [ChainSlug.RISE_TESTNET]: ChainId.RISE_TESTNET, + [ChainSlug.KATANA]: ChainId.KATANA, + [ChainSlug.SONIC]: ChainId.SONIC, + [ChainSlug.ZERO]: ChainId.ZERO, + [ChainSlug.ZKSYNC]: ChainId.ZKSYNC, + [ChainSlug.ARENA_Z]: ChainId.ARENA_Z, + [ChainSlug.B3]: ChainId.B3, + [ChainSlug.MONAD_TESTNET]: ChainId.MONAD_TESTNET, + [ChainSlug.SCROLL]: ChainId.SCROLL, + [ChainSlug.SONEIUM]: ChainId.SONEIUM, + [ChainSlug.SWELLCHAIN]: ChainId.SWELLCHAIN, + [ChainSlug.WORLD_CHAIN]: ChainId.WORLD_CHAIN, + [ChainSlug.HYPEREVM]: ChainId.HYPEREVM, + [ChainSlug.SEI]: ChainId.SEI, + [ChainSlug.BERA]: ChainId.BERA, + [ChainSlug.INK]: ChainId.INK, + [ChainSlug.UNICHAIN]: ChainId.UNICHAIN, }; diff --git a/src/chain-enums/chainSlugToKey.ts b/src/chain-enums/chainSlugToKey.ts index 43c601a4..7ffbbda2 100644 --- a/src/chain-enums/chainSlugToKey.ts +++ b/src/chain-enums/chainSlugToKey.ts @@ -60,4 +60,24 @@ export const ChainSlugToKey = { [ChainSlug.ZERO_SEPOLIA]: HardhatChainName.ZERO_SEPOLIA, [ChainSlug.INTEROP_ALPHA_0]: HardhatChainName.INTEROP_ALPHA_0, [ChainSlug.INTEROP_ALPHA_1]: HardhatChainName.INTEROP_ALPHA_1, + [ChainSlug.ZERO]: HardhatChainName.ZERO, + [ChainSlug.ZKSYNC]: HardhatChainName.ZKSYNC, + [ChainSlug.ARENA_Z]: HardhatChainName.ARENA_Z, + [ChainSlug.INK]: HardhatChainName.INK, + [ChainSlug.SONIC]: HardhatChainName.SONIC, + [ChainSlug.BERA]: HardhatChainName.BERA, + [ChainSlug.B3]: HardhatChainName.B3, + [ChainSlug.UNICHAIN]: HardhatChainName.UNICHAIN, + [ChainSlug.KATANA]: HardhatChainName.KATANA, + [ChainSlug.HYPEREVM]: HardhatChainName.HYPEREVM, + [ChainSlug.SEI]: HardhatChainName.SEI, + [ChainSlug.FLOW]: HardhatChainName.FLOW, + [ChainSlug.CAMP]: HardhatChainName.CAMP, + [ChainSlug.PLUME]: HardhatChainName.PLUME, + [ChainSlug.RISE_TESTNET]: HardhatChainName.RISE_TESTNET, + [ChainSlug.MONAD_TESTNET]: HardhatChainName.MONAD_TESTNET, + [ChainSlug.SCROLL]: HardhatChainName.SCROLL, + [ChainSlug.SONEIUM]: HardhatChainName.SONEIUM, + [ChainSlug.SWELLCHAIN]: HardhatChainName.SWELLCHAIN, + [ChainSlug.WORLD_CHAIN]: HardhatChainName.WORLD_CHAIN, }; diff --git a/src/chain-enums/currency.ts b/src/chain-enums/currency.ts index 1f9448db..ef05435f 100644 --- a/src/chain-enums/currency.ts +++ b/src/chain-enums/currency.ts @@ -2,21 +2,28 @@ import { ChainSlug } from "./chainSlug"; import { NativeTokens } from "./native-tokens"; export const Currency = { - [ChainSlug.BSC]: NativeTokens.binancecoin, - [ChainSlug.POLYGON_MAINNET]: NativeTokens["matic-network"], - [ChainSlug.SX_NETWORK_TESTNET]: NativeTokens["sx-network-2"], - [ChainSlug.SX_NETWORK]: NativeTokens["sx-network-2"], - [ChainSlug.MANTLE]: NativeTokens.mantle, - [ChainSlug.BSC_TESTNET]: NativeTokens["binancecoin"], - [ChainSlug.WINR]: NativeTokens["winr"], - [ChainSlug.NEOX_TESTNET]: NativeTokens["gas"], - [ChainSlug.NEOX_T4_TESTNET]: NativeTokens["gas"], - [ChainSlug.NEOX]: NativeTokens["gas"], - [ChainSlug.GNOSIS]: NativeTokens["dai"], - [ChainSlug.AVALANCHE]: NativeTokens["avalanche-2"], - [ChainSlug.XLAYER]: NativeTokens["okb"], - [ChainSlug.POLTER_TESTNET]: NativeTokens["aavegotchi"], - [ChainSlug.POLYGON_AMOY]: NativeTokens["matic-network"], - [ChainSlug.OPBNB]: NativeTokens["binancecoin"], - [ChainSlug.GEIST]: NativeTokens["aavegotchi"], + [ChainSlug.BSC]: NativeTokens.BINANCECOIN, + [ChainSlug.POLYGON_MAINNET]: NativeTokens.MATIC_NETWORK, + [ChainSlug.SX_NETWORK_TESTNET]: NativeTokens.SX_NETWORK_2, + [ChainSlug.SX_NETWORK]: NativeTokens.SX_NETWORK_2, + [ChainSlug.MANTLE]: NativeTokens.MANTLE, + [ChainSlug.BSC_TESTNET]: NativeTokens.BINANCECOIN, + [ChainSlug.WINR]: NativeTokens.WINR, + [ChainSlug.NEOX_TESTNET]: NativeTokens.GAS, + [ChainSlug.NEOX_T4_TESTNET]: NativeTokens.GAS, + [ChainSlug.NEOX]: NativeTokens.GAS, + [ChainSlug.GNOSIS]: NativeTokens.DAI, + [ChainSlug.AVALANCHE]: NativeTokens.AVALANCHE_2, + [ChainSlug.XLAYER]: NativeTokens.OKB, + [ChainSlug.POLTER_TESTNET]: NativeTokens.AAVEGOTCHI, + [ChainSlug.POLYGON_AMOY]: NativeTokens.MATIC_NETWORK, + [ChainSlug.OPBNB]: NativeTokens.BINANCECOIN, + [ChainSlug.GEIST]: NativeTokens.AAVEGOTCHI, + [ChainSlug.SONIC]: NativeTokens.SONIC_3, + [ChainSlug.HYPEREVM]: NativeTokens.HYPERLIQUID, + [ChainSlug.SEI]: NativeTokens.WRAPPED_SEI, + [ChainSlug.BERA]: NativeTokens.BERACHAIN_BERA, + [ChainSlug.FLOW]: NativeTokens.FLOW, + [ChainSlug.CAMP]: NativeTokens.CAMP_NETWORK, + [ChainSlug.PLUME]: NativeTokens.PLUME, }; diff --git a/src/chain-enums/ethLikeChains.ts b/src/chain-enums/ethLikeChains.ts index dde62f66..6d899a07 100644 --- a/src/chain-enums/ethLikeChains.ts +++ b/src/chain-enums/ethLikeChains.ts @@ -26,4 +26,8 @@ export const ethLikeChains = [ ChainSlug.POLYGON_AMOY, ChainSlug.INTEROP_ALPHA_0, ChainSlug.INTEROP_ALPHA_1, + ChainSlug.FLOW, + ChainSlug.CAMP, + ChainSlug.PLUME, + ChainSlug.RISE_TESTNET, ]; diff --git a/src/chain-enums/eventBlockRange.ts b/src/chain-enums/eventBlockRange.ts new file mode 100644 index 00000000..7ce76d20 --- /dev/null +++ b/src/chain-enums/eventBlockRange.ts @@ -0,0 +1,6 @@ +import { ChainSlug } from "./chainSlug"; + +export const ChainEventBlockRange = { + [ChainSlug.HYPEREVM]: 1000, + [ChainSlug.SEI]: 1000, +}; diff --git a/src/chain-enums/gasPriceType.ts b/src/chain-enums/gasPriceType.ts new file mode 100644 index 00000000..f79bb803 --- /dev/null +++ b/src/chain-enums/gasPriceType.ts @@ -0,0 +1,10 @@ +import { ChainSlug } from "./chainSlug"; +import { GasPriceType } from "../enums"; + +export const ChainGasPriceType = { + [ChainSlug.BSC]: GasPriceType.LEGACY, + [ChainSlug.LINEA]: GasPriceType.LEGACY, + [ChainSlug.MANTLE]: GasPriceType.LEGACY, + [ChainSlug.KATANA]: GasPriceType.LEGACY, + [ChainSlug.MAINNET]: GasPriceType.LEGACY, +}; diff --git a/src/chain-enums/hardhatChainName.ts b/src/chain-enums/hardhatChainName.ts index c74be92e..ebf5a4e7 100644 --- a/src/chain-enums/hardhatChainName.ts +++ b/src/chain-enums/hardhatChainName.ts @@ -57,4 +57,24 @@ export enum HardhatChainName { ZERO_SEPOLIA = "zero_sepolia", INTEROP_ALPHA_0 = "interop_alpha_0", INTEROP_ALPHA_1 = "interop_alpha_1", + ZERO = "zero", + ZKSYNC = "zksync", + ARENA_Z = "arena_z", + INK = "ink", + SONIC = "sonic", + BERA = "bera", + B3 = "b3", + UNICHAIN = "unichain", + MONAD_TESTNET = "monad_testnet", + SCROLL = "scroll", + SONEIUM = "soneium", + SWELLCHAIN = "swellchain", + WORLD_CHAIN = "world_chain", + KATANA = "katana", + HYPEREVM = "hyperevm", + SEI = "sei", + FLOW = "flow", + CAMP = "camp", + PLUME = "plume", + RISE_TESTNET = "rise_testnet", } diff --git a/src/chain-enums/hardhatChainNameToSlug.ts b/src/chain-enums/hardhatChainNameToSlug.ts index 110b45c9..b4fb455a 100644 --- a/src/chain-enums/hardhatChainNameToSlug.ts +++ b/src/chain-enums/hardhatChainNameToSlug.ts @@ -60,4 +60,24 @@ export const hardhatChainNameToSlug = { [HardhatChainName.ZERO_SEPOLIA]: ChainSlug.ZERO_SEPOLIA, [HardhatChainName.INTEROP_ALPHA_0]: ChainSlug.INTEROP_ALPHA_0, [HardhatChainName.INTEROP_ALPHA_1]: ChainSlug.INTEROP_ALPHA_1, + [HardhatChainName.ZERO]: ChainSlug.ZERO, + [HardhatChainName.ZKSYNC]: ChainSlug.ZKSYNC, + [HardhatChainName.ARENA_Z]: ChainSlug.ARENA_Z, + [HardhatChainName.INK]: ChainSlug.INK, + [HardhatChainName.SONIC]: ChainSlug.SONIC, + [HardhatChainName.BERA]: ChainSlug.BERA, + [HardhatChainName.B3]: ChainSlug.B3, + [HardhatChainName.UNICHAIN]: ChainSlug.UNICHAIN, + [HardhatChainName.MONAD_TESTNET]: ChainSlug.MONAD_TESTNET, + [HardhatChainName.SCROLL]: ChainSlug.SCROLL, + [HardhatChainName.SONEIUM]: ChainSlug.SONEIUM, + [HardhatChainName.SWELLCHAIN]: ChainSlug.SWELLCHAIN, + [HardhatChainName.WORLD_CHAIN]: ChainSlug.WORLD_CHAIN, + [HardhatChainName.KATANA]: ChainSlug.KATANA, + [HardhatChainName.HYPEREVM]: ChainSlug.HYPEREVM, + [HardhatChainName.SEI]: ChainSlug.SEI, + [HardhatChainName.FLOW]: ChainSlug.FLOW, + [HardhatChainName.CAMP]: ChainSlug.CAMP, + [HardhatChainName.PLUME]: ChainSlug.PLUME, + [HardhatChainName.RISE_TESTNET]: ChainSlug.RISE_TESTNET, }; diff --git a/src/chain-enums/mainnetIds.ts b/src/chain-enums/mainnetIds.ts index eaaeced7..573761af 100644 --- a/src/chain-enums/mainnetIds.ts +++ b/src/chain-enums/mainnetIds.ts @@ -29,4 +29,24 @@ export const MainnetIds: ChainSlug[] = [ ChainSlug.MANTA_PACIFIC, ChainSlug.OPBNB, ChainSlug.GEIST, + ChainSlug.FLOW, + ChainSlug.CAMP, + ChainSlug.PLUME, + ChainSlug.SONIC, + ChainSlug.KATANA, + ChainSlug.HYPEREVM, + ChainSlug.SEI, + ChainSlug.ZERO, + ChainSlug.ZKSYNC, + ChainSlug.ARENA_Z, + ChainSlug.INK, + ChainSlug.BERA, + ChainSlug.B3, + ChainSlug.UNICHAIN, + ChainSlug.SCROLL, + ChainSlug.SONEIUM, + ChainSlug.SWELLCHAIN, + ChainSlug.WORLD_CHAIN, + ChainSlug.FLOW, + ChainSlug.CAMP, ]; diff --git a/src/chain-enums/native-tokens.ts b/src/chain-enums/native-tokens.ts index 1e70d1bf..48e8c3e7 100644 --- a/src/chain-enums/native-tokens.ts +++ b/src/chain-enums/native-tokens.ts @@ -1,15 +1,25 @@ // add coingecko token id here export enum NativeTokens { - "ethereum" = "ethereum", - "matic-network" = "matic-network", - "binancecoin" = "binancecoin", - "sx-network-2" = "sx-network-2", - "mantle" = "mantle", - "winr" = "winr-protocol", - "no-token" = "no-token", - "gas" = "gas", - "dai" = "dai", - "avalanche-2" = "avalanche-2", - "okb" = "okb", - "aavegotchi" = "aavegotchi", + ETHEREUM = "ethereum", + MATIC_NETWORK = "matic-network", + BINANCECOIN = "binancecoin", + SX_NETWORK_2 = "sx-network-2", + MANTLE = "mantle", + WINR = "winr-protocol", + NO_TOKEN = "no-token", + GAS = "gas", + DAI = "dai", + XDAI = "xdai", + AVALANCHE_2 = "avalanche-2", + OKB = "okb", + AAVEGOTCHI = "aavegotchi", + POLYGON_ECOSYSTEM_TOKEN = "polygon-ecosystem-token", + SONIC_3 = "sonic-3", + HYPERLIQUID = "hyperliquid", + WRAPPED_SEI = "wrapped-sei", + BERACHAIN_BERA = "berachain-bera", + PLUME = "plume", + CAMP_NETWORK = "camp-network", + FLOW = "flow", + SEI = "sei", } diff --git a/src/chain-enums/opStackChains.ts b/src/chain-enums/opStackChains.ts index d1e6aa3e..e1a96fbf 100644 --- a/src/chain-enums/opStackChains.ts +++ b/src/chain-enums/opStackChains.ts @@ -21,4 +21,6 @@ export const opStackL2Chain = [ ChainSlug.MANTA_PACIFIC, ChainSlug.POLTER_TESTNET, ChainSlug.OPBNB, + ChainSlug.INK, + ChainSlug.UNICHAIN, ]; diff --git a/src/chain-enums/testnetIds.ts b/src/chain-enums/testnetIds.ts index efe3e6d4..beed80c4 100644 --- a/src/chain-enums/testnetIds.ts +++ b/src/chain-enums/testnetIds.ts @@ -30,4 +30,6 @@ export const TestnetIds: ChainSlug[] = [ ChainSlug.BASE_SEPOLIA, ChainSlug.INTEROP_ALPHA_0, ChainSlug.INTEROP_ALPHA_1, + ChainSlug.MONAD_TESTNET, + ChainSlug.RISE_TESTNET, ]; diff --git a/src/enums.ts b/src/enums.ts index e9b3f49b..ac982921 100644 --- a/src/enums.ts +++ b/src/enums.ts @@ -53,6 +53,7 @@ export enum Events { export enum Contracts { Socket = "Socket", FeesPlug = "FeesPlug", + SUSDC = "SUSDC", ContractFactoryPlug = "ContractFactoryPlug", FastSwitchboard = "FastSwitchboard", FastSwitchboardId = "FastSwitchboardId", @@ -75,6 +76,10 @@ export enum Contracts { FeesPool = "FeesPool", AsyncDeployer = "AsyncDeployer", DeployForwarder = "DeployForwarder", + Forwarder = "Forwarder", + ForwarderImpl = "ForwarderImpl", + AsyncPromise = "AsyncPromise", + AsyncPromiseImpl = "AsyncPromiseImpl", } export enum CallTypeNames { @@ -94,3 +99,8 @@ export enum FinalityBucketNames { MEDIUM = "MEDIUM", HIGH = "HIGH", } + +export enum GasPriceType { + LEGACY = "LEGACY", + EIP1559 = "EIP1559", +} diff --git a/src/finality.ts b/src/finality.ts index bbccd896..ef6cd5f1 100644 --- a/src/finality.ts +++ b/src/finality.ts @@ -19,15 +19,15 @@ export const finalityBlockOverrides: { [chainSlug in ChainSlug]?: ChainFinalityBlocks; } = { [ChainSlug.MAINNET]: { - [FinalityBucket.LOW]: 6, + [FinalityBucket.LOW]: 2, [FinalityBucket.MEDIUM]: "safe", [FinalityBucket.HIGH]: "finalized", }, [ChainSlug.POLYGON_MAINNET]: { - [FinalityBucket.LOW]: 256, - [FinalityBucket.MEDIUM]: 512, - [FinalityBucket.HIGH]: 1000, + [FinalityBucket.LOW]: 5, + [FinalityBucket.MEDIUM]: 5, + [FinalityBucket.HIGH]: 5, }, [ChainSlug.NEOX_TESTNET]: { [FinalityBucket.LOW]: 1, diff --git a/src/signer.ts b/src/signer.ts index 78a6d8a1..18658fbb 100644 --- a/src/signer.ts +++ b/src/signer.ts @@ -1,5 +1,5 @@ import { ethers } from "ethers"; - +import { v4 as uuidv4 } from "uuid"; export const signWatcherMultiCallMessage = async ( watcherContractAddress: string, evmxChainId: number, @@ -25,8 +25,7 @@ export const signWatcherMultiCallMessage = async ( }; export const getNonce = () => { - const timestamp = Date.now(); - const random = Math.floor(Math.random() * 1000); - const nonce = Number(String(timestamp) + String(random)); - return nonce; + const randomId = uuidv4(); + const nonceHex = randomId.replace(/-/g, ""); + return "0x" + nonceHex; }; diff --git a/src/types.ts b/src/types.ts index a603b158..1a961484 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { FinalityBucket } from "./enums"; +import { FinalityBucket, GasPriceType } from "./enums"; export enum ChainType { opStackL2Chain = "opStackL2Chain", @@ -19,14 +19,15 @@ export type ChainAddressesObj = { Socket: string; SocketBatcher: string; FastSwitchboard: string; - CCTPSwitchboard: string; - MessageSwitchboard: string; + CCTPSwitchboard?: string; + MessageSwitchboard?: string; FastSwitchboardId: string; - CCTPSwitchboardId: string; - MessageSwitchboardId: string; + CCTPSwitchboardId?: string; + MessageSwitchboardId?: string; ContractFactoryPlug: string; SocketFeesManager?: string; FeesPlug?: string; + SUSDC?: string; startBlock: number; SwitchboardIdToAddressMap: { [switchboardId: string]: string }; }; @@ -52,10 +53,14 @@ export type EVMxAddressesObj = { export type S3Config = { version: string; chains: { [chainSlug: number]: ChainConfig }; + tokens: TokenMap; supportedChainSlugs: number[]; testnetChainSlugs: number[]; evmxChainSlug: number; mainnetChainSlugs: number[]; + indexerHighChains: number[]; + indexerLowChains: number[]; + cronOnlyChains: number[]; }; export type ChainConfig = { @@ -67,6 +72,19 @@ export type ChainConfig = { addresses: ChainAddressesObj | EVMxAddressesObj; finalityBlocks: ChainFinalityBlocks; chainType: ChainType; + nativeToken: string; + gasPriceType: GasPriceType; }; export { FinalityBucket }; + +export type TokenMap = { + [key: string]: { + [chainSlug: number]: { + name: string; + symbol: string; + address: string; + decimals: number; + }[]; + }; +}; diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 303935a2..58d9bc21 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -35,6 +35,8 @@ import "../contracts/evmx/fees/FeesPool.sol"; import "../contracts/evmx/plugs/FeesPlug.sol"; import "../contracts/evmx/AuctionManager.sol"; import "../contracts/evmx/mocks/TestUSDC.sol"; +import "../contracts/evmx/plugs/SUSDC.sol"; + import "./mock/CCTPMessageTransmitter.sol"; import "solady/utils/ERC1967Factory.sol"; @@ -54,11 +56,11 @@ contract SetupStore is Test { uint32 optChainSlug = 11155420; uint32 evmxSlug = 1; - uint256 expiryTime = 864000; + uint256 expiryTime = 86400; uint256 bidTimeout = 86400; uint256 maxReAuctionCount = 10; uint256 auctionEndDelaySeconds = 0; - uint256 maxScheduleDelayInSeconds = 86400; + uint256 maxScheduleDelayInSeconds = 86500; uint256 maxMsgValueLimit = 1 ether; uint256 writeFees = 10000; @@ -87,6 +89,7 @@ contract SetupStore is Test { SocketBatcher socketBatcher; ContractFactoryPlug contractFactoryPlug; FeesPlug feesPlug; + SUSDC susdcPlug; TestUSDC testUSDC; } SocketContracts public arbConfig; @@ -100,6 +103,7 @@ contract SetupStore is Test { DeployForwarder deployForwarderImpl; Configurations configurationsImpl; RequestHandler requestHandlerImpl; + PromiseResolver promiseResolverImpl; WritePrecompile writePrecompileImpl; ERC1967Factory public proxyFactory; @@ -132,6 +136,31 @@ contract DeploySetup is SetupStore { optConfig = _deploySocket(optChainSlug); _configureChain(optChainSlug); + vm.startPrank(watcherEOA); + auctionManager.grantRole(TRANSMITTER_ROLE, transmitterEOA); + feesPool.grantRole(FEE_MANAGER_ROLE, address(feesManager)); + + // setup address resolver + addressResolver.setWatcher(address(watcher)); + addressResolver.setAsyncDeployer(address(asyncDeployer)); + addressResolver.setDefaultAuctionManager(address(auctionManager)); + addressResolver.setFeesManager(address(feesManager)); + addressResolver.setDeployForwarder(address(deployForwarder)); + + requestHandler.setPrecompile(WRITE, writePrecompile); + requestHandler.setPrecompile(READ, readPrecompile); + requestHandler.setPrecompile(SCHEDULE, schedulePrecompile); + + watcher.setCoreContracts( + address(requestHandler), + address(configurations), + address(promiseResolver) + ); + feesManager.setSusdcToken(arbChainSlug, toBytes32Format(address(arbConfig.susdcPlug))); + feesManager.setSusdcToken(optChainSlug, toBytes32Format(address(optConfig.susdcPlug))); + + vm.stopPrank(); + vm.startPrank(socketOwner); arbConfig.cctpSwitchboard.addRemoteEndpoint( optChainSlug, @@ -161,28 +190,6 @@ contract DeploySetup is SetupStore { // transfer eth to fees pool for native fee payouts vm.deal(address(feesPool), 100000 ether); - vm.startPrank(watcherEOA); - auctionManager.grantRole(TRANSMITTER_ROLE, transmitterEOA); - feesPool.grantRole(FEE_MANAGER_ROLE, address(feesManager)); - - // setup address resolver - addressResolver.setWatcher(address(watcher)); - addressResolver.setAsyncDeployer(address(asyncDeployer)); - addressResolver.setDefaultAuctionManager(address(auctionManager)); - addressResolver.setFeesManager(address(feesManager)); - addressResolver.setDeployForwarder(address(deployForwarder)); - - requestHandler.setPrecompile(WRITE, writePrecompile); - requestHandler.setPrecompile(READ, readPrecompile); - requestHandler.setPrecompile(SCHEDULE, schedulePrecompile); - - watcher.setCoreContracts( - address(requestHandler), - address(configurations), - address(promiseResolver) - ); - vm.stopPrank(); - _connectCorePlugs(); _setupTransmitter(); } @@ -195,15 +202,16 @@ contract DeploySetup is SetupStore { arbConfig.feesPlug.depositCreditAndNative( address(arbConfig.testUSDC), address(transmitterEOA), - 100 ether + 100 ether, + bytes("") ); - feesManager.approveAppGateway(address(auctionManager), true); + feesManager.approve(address(auctionManager), true); vm.stopPrank(); } function _connectCorePlugs() internal { - AppGatewayConfig[] memory configs = new AppGatewayConfig[](4); + AppGatewayConfig[] memory configs = new AppGatewayConfig[](6); configs[0] = AppGatewayConfig({ chainSlug: arbChainSlug, plug: toBytes32Format(address(arbConfig.feesPlug)), @@ -236,6 +244,22 @@ contract DeploySetup is SetupStore { switchboardId: optConfig.switchboard.switchboardId() }) }); + configs[4] = AppGatewayConfig({ + chainSlug: optChainSlug, + plug: toBytes32Format(address(optConfig.susdcPlug)), + plugConfig: PlugConfigGeneric({ + appGatewayId: toBytes32Format(address(feesManager)), + switchboardId: optConfig.switchboard.switchboardId() + }) + }); + configs[5] = AppGatewayConfig({ + chainSlug: arbChainSlug, + plug: toBytes32Format(address(arbConfig.susdcPlug)), + plugConfig: PlugConfigGeneric({ + appGatewayId: toBytes32Format(address(feesManager)), + switchboardId: arbConfig.switchboard.switchboardId() + }) + }); watcherMultiCall( address(configurations), @@ -269,6 +293,7 @@ contract DeploySetup is SetupStore { socketBatcher: new SocketBatcher(socketOwner, socket), contractFactoryPlug: new ContractFactoryPlug(address(socket), socketOwner), feesPlug: new FeesPlug(address(socket), socketOwner), + susdcPlug: new SUSDC(18, address(socketOwner), address(socket), "susdc", "SUSDC"), testUSDC: new TestUSDC("USDC", "USDC", 6, socketOwner, 1000000000000000000000000) }); } @@ -330,6 +355,14 @@ contract DeploySetup is SetupStore { toBytes32Format(address(contractFactoryPlug)) ); vm.stopPrank(); + + uint64 sbId = socketConfig.switchboard.switchboardId(); + hoax(socketOwner); + socketConfig.susdcPlug.connectSocket( + toBytes32Format(address(feesManager)), + address(socketConfig.socket), + sbId + ); } function _deployEVMxCore() internal { @@ -344,6 +377,7 @@ contract DeploySetup is SetupStore { auctionManagerImpl = new AuctionManager(); deployForwarderImpl = new DeployForwarder(); configurationsImpl = new Configurations(); + promiseResolverImpl = new PromiseResolver(); requestHandlerImpl = new RequestHandler(); writePrecompileImpl = new WritePrecompile(); @@ -364,6 +398,7 @@ contract DeploySetup is SetupStore { address(addressResolver), address(feesPool), watcherEOA, + writeFees, FAST ) ); @@ -451,8 +486,14 @@ contract DeploySetup is SetupStore { ); writePrecompile = WritePrecompile(writePrecompileProxy); + address promiseResolverProxy = _deployAndVerifyProxy( + address(promiseResolverImpl), + watcherEOA, + abi.encodeWithSelector(PromiseResolver.initialize.selector, address(watcher)) + ); + promiseResolver = PromiseResolver(promiseResolverProxy); + // non proxy contracts - promiseResolver = new PromiseResolver(address(watcher)); readPrecompile = new ReadPrecompile(address(watcher), readFees, expiryTime); schedulePrecompile = new SchedulePrecompile( address(watcher), @@ -553,45 +594,59 @@ contract FeesSetup is DeploySetup { _deploy(); depositNativeAndCredits(arbChainSlug, 100 ether, 100 ether, address(transmitterEOA)); - approveAppGateway(address(auctionManager), address(transmitterEOA)); + approve(address(auctionManager), address(transmitterEOA)); } - // mints test token and deposits the given native and credits to given `user_` function depositNativeAndCredits( uint32 chainSlug_, uint256 credits_, uint256 native_, address user_ + ) internal { + depositNativeAndCreditsWithData(chainSlug_, credits_, native_, user_, user_, bytes("")); + } + + // mints test token and deposits the given native and credits to given `user_` + function depositNativeAndCreditsWithData( + uint32 chainSlug_, + uint256 credits_, + uint256 native_, + address user_, + address receiver_, + bytes memory data_ ) internal { SocketContracts memory socketConfig = getSocketConfig(chainSlug_); TestUSDC token = socketConfig.testUSDC; - uint256 userBalance = token.balanceOf(user_); - uint256 feesPlugBalance = token.balanceOf(address(socketConfig.feesPlug)); + // uint256 userBalance = token.balanceOf(user_); + // uint256 feesPlugBalance = token.balanceOf(address(socketConfig.feesPlug)); token.mint(address(user_), 100 ether); - assertEq( - token.balanceOf(user_), - userBalance + 100 ether, - "User should have 100 more test tokens" - ); + // assertEq( + // token.balanceOf(user_), + // userBalance + 100 ether, + // "User should have 100 more test tokens" + // ); vm.startPrank(user_); token.approve(address(socketConfig.feesPlug), 100 ether); - socketConfig.feesPlug.depositCreditAndNative(address(token), address(user_), 100 ether); + socketConfig.feesPlug.depositCreditAndNative(address(token), user_, 100 ether, data_); vm.stopPrank(); - assertEq( - token.balanceOf(address(socketConfig.feesPlug)), - feesPlugBalance + 100 ether, - "Fees plug should have 100 more test tokens" - ); + // assertEq( + // token.balanceOf(address(socketConfig.feesPlug)), + // feesPlugBalance + 100 ether, + // "Fees plug should have 100 more test tokens" + // ); - uint256 currentCredits = feesManager.getAvailableCredits(user_); - uint256 currentNative = address(user_).balance; + // uint256 currentCredits = feesManager.balanceOf(user_); + // uint256 currentNative = address(user_).balance; + + hoax(watcherEOA); + feesManager.setWhitelistedReceiver(receiver_, true); vm.expectEmit(true, true, true, false); - emit Deposited(chainSlug_, address(token), user_, credits_, native_); + emit Deposited(chainSlug_, address(token), receiver_, credits_, native_); watcherMultiCall( address(feesManager), @@ -599,29 +654,27 @@ contract FeesSetup is DeploySetup { Credit.deposit.selector, chainSlug_, address(token), - user_, + receiver_, native_, - credits_ + credits_, + data_ ) ); - assertEq( - feesManager.getAvailableCredits(user_), - currentCredits + credits_, - "User should have more credits" - ); - assertEq(address(user_).balance, currentNative + native_, "User should have more native"); + // assertEq( + // feesManager.balanceOf(user_), + // currentCredits + credits_, + // "User should have more credits" + // ); + // assertEq(address(user_).balance, currentNative + native_, "User should have more native"); } - function approveAppGateway(address appGateway_, address user_) internal { + function approve(address appGateway_, address user_) internal { bool approval = feesManager.isApproved(user_, appGateway_); if (approval) return; - AppGatewayApprovals[] memory approvals = new AppGatewayApprovals[](1); - approvals[0] = AppGatewayApprovals({appGateway: appGateway_, approval: true}); - hoax(user_); - feesManager.approveAppGateways(approvals); + feesManager.approve(appGateway_, true); assertEq( feesManager.isApproved(user_, appGateway_), @@ -630,7 +683,7 @@ contract FeesSetup is DeploySetup { ); } - function approveAppGatewayWithSignature( + function approveWithSignature( address appGateway_, address user_, uint256 userPrivateKey_ @@ -650,7 +703,7 @@ contract FeesSetup is DeploySetup { bytes memory feeApprovalData = abi.encode(appGateway_, true, block.timestamp, signature); // Call whitelistAppGatewayWithSignature with approval data - feesManager.approveAppGatewayWithSignature(feeApprovalData); + feesManager.approveWithSignature(feeApprovalData); assertEq( feesManager.isApproved(user_, appGateway_), true, @@ -771,6 +824,10 @@ contract WatcherSetup is AuctionSetup { requestCount = watcher.getCurrentRequestCount(); requestCount = requestCount == 0 ? 0 : requestCount - 1; + executeRequest(requestCount); + } + + function executeRequest(uint40 requestCount) internal { RequestParams memory requestParams = requestHandler.getRequest(requestCount); uint40[] memory batches = requestHandler.getRequestBatchIds(requestCount); @@ -1130,21 +1187,45 @@ contract WatcherSetup is AuctionSetup { ) internal { // Count valid plugs first. In some cases we might have contractIds such that oly a subset is // deployed on a chain. for ex, vault on source, and supertoken on destination. - uint256 validPlugCount = 0; + uint256 validPlugCount = _countValidPlugs(appGateway_, contractIds_, chainSlug_); + + // Create array with exact size needed + AppGatewayConfig[] memory configs = new AppGatewayConfig[](validPlugCount); + _populateConfigs(configs, appGateway_, contractIds_, chainSlug_); + + // Only call watcher if we have valid configs + if (validPlugCount > 0) { + watcherMultiCall( + address(configurations), + abi.encodeWithSelector(Configurations.setAppGatewayConfigs.selector, configs) + ); + } + } + + function _countValidPlugs( + IAppGateway appGateway_, + bytes32[] memory contractIds_, + uint32 chainSlug_ + ) internal view returns (uint256 validCount) { for (uint i = 0; i < contractIds_.length; i++) { bytes32 plug = appGateway_.getOnChainAddress(contractIds_[i], chainSlug_); if (plug != bytes32(0)) { - validPlugCount++; + validCount++; } } + } - // Create array with exact size needed - AppGatewayConfig[] memory configs = new AppGatewayConfig[](validPlugCount); + function _populateConfigs( + AppGatewayConfig[] memory configs, + IAppGateway appGateway_, + bytes32[] memory contractIds_, + uint32 chainSlug_ + ) internal view { uint256 configIndex = 0; + uint64 switchboardId = configurations.switchboards(chainSlug_, appGateway_.sbType()); for (uint i = 0; i < contractIds_.length; i++) { bytes32 plug = appGateway_.getOnChainAddress(contractIds_[i], chainSlug_); - uint64 switchboardId = configurations.switchboards(chainSlug_, appGateway_.sbType()); if (plug != bytes32(0)) { configs[configIndex] = AppGatewayConfig({ plug: plug, @@ -1157,14 +1238,6 @@ contract WatcherSetup is AuctionSetup { configIndex++; } } - - // Only call watcher if we have valid configs - if (validPlugCount > 0) { - watcherMultiCall( - address(configurations), - abi.encodeWithSelector(Configurations.setAppGatewayConfigs.selector, configs) - ); - } } } diff --git a/test/SocketUSDC.sol b/test/SocketUSDC.sol new file mode 100644 index 00000000..987d5705 --- /dev/null +++ b/test/SocketUSDC.sol @@ -0,0 +1,30 @@ +import {ERC20} from "solady/tokens/ERC20.sol"; + +contract SocketUSDC is ERC20 { + string public _name; + string public _symbol; + uint8 public _decimals; + + constructor() ERC20() { + _name = "SocketUSDC"; + _symbol = "SUSDC"; + _decimals = 18; + _mint(msg.sender, 1000000000 ether); + } + + function name() public view override returns (string memory) { + return _name; + } + + function symbol() public view override returns (string memory) { + return _symbol; + } + + function decimals() public view override returns (uint8) { + return _decimals; + } + + function mint(address to, uint256 amount) public { + _mint(to, amount); + } +} diff --git a/test/Utils.t.sol b/test/Utils.t.sol new file mode 100644 index 00000000..ff8cef98 --- /dev/null +++ b/test/Utils.t.sol @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "forge-std/Test.sol"; +import "../contracts/utils/common/IdUtils.sol"; +import "../contracts/utils/common/Converters.sol"; + +/** + * @title IdUtilsTest + * @dev Tests for IdUtils utility functions + */ +contract IdUtilsTest is Test { + function testCreatePayloadId() public pure { + uint160 payloadPointer = 12345; + uint64 switchboardId = 67890; + uint32 chainSlug = 1; + + bytes32 payloadId = createPayloadId(payloadPointer, switchboardId, chainSlug); + + // Verify the structure + uint32 chainSlugFromId = uint32(uint256(payloadId) >> 224); + uint64 switchboardIdFromId = uint64(uint256(payloadId) >> 160); + uint160 payloadPointerFromId = uint160(uint256(payloadId)); + + assertEq(chainSlugFromId, chainSlug, "Chain slug should match"); + assertEq(switchboardIdFromId, switchboardId, "Switchboard ID should match"); + assertEq(payloadPointerFromId, payloadPointer, "Payload pointer should match"); + } + + function testCreatePayloadIdWithZeroValues() public pure { + bytes32 payloadId = createPayloadId(0, 0, 0); + + assertEq(payloadId, bytes32(0), "Payload ID should be zero for zero inputs"); + } + + function testCreatePayloadIdWithMaxValues() public pure { + uint160 maxPayloadPointer = type(uint160).max; + uint64 maxSwitchboardId = type(uint64).max; + uint32 maxChainSlug = type(uint32).max; + + bytes32 payloadId = createPayloadId(maxPayloadPointer, maxSwitchboardId, maxChainSlug); + + // Verify the structure + uint32 chainSlugFromId = uint32(uint256(payloadId) >> 224); + uint64 switchboardIdFromId = uint64(uint256(payloadId) >> 160); + uint160 payloadPointerFromId = uint160(uint256(payloadId)); + + assertEq(chainSlugFromId, maxChainSlug, "Chain slug should match"); + assertEq(switchboardIdFromId, maxSwitchboardId, "Switchboard ID should match"); + assertEq(payloadPointerFromId, maxPayloadPointer, "Payload pointer should match"); + } + + function testCreatePayloadIdFuzz( + uint160 payloadPointer, + uint64 switchboardId, + uint32 chainSlug + ) public pure { + bytes32 payloadId = createPayloadId(payloadPointer, switchboardId, chainSlug); + + // Verify the structure + uint32 chainSlugFromId = uint32(uint256(payloadId) >> 224); + uint64 switchboardIdFromId = uint64(uint256(payloadId) >> 160); + uint160 payloadPointerFromId = uint160(uint256(payloadId)); + + assertEq(chainSlugFromId, chainSlug, "Chain slug should match"); + assertEq(switchboardIdFromId, switchboardId, "Switchboard ID should match"); + assertEq(payloadPointerFromId, payloadPointer, "Payload pointer should match"); + } +} + +/** + * @title ConvertersTest + * @dev Tests for Converters utility functions + */ +contract ConvertersTest is Test { + function testToBytes32Format() public pure { + address testAddr = address(0x1234567890123456789012345678901234567890); + bytes32 result = toBytes32Format(testAddr); + + assertEq(result, bytes32(uint256(uint160(testAddr))), "Conversion should be correct"); + } + + function testToBytes32FormatWithZeroAddress() public pure { + bytes32 result = toBytes32Format(address(0)); + + assertEq(result, bytes32(0), "Zero address should convert to zero bytes32"); + } + + function testFromBytes32Format() public pure { + address originalAddr = address(0x1234567890123456789012345678901234567890); + bytes32 bytes32Format = toBytes32Format(originalAddr); + + address convertedAddr = fromBytes32Format(bytes32Format); + + assertEq(convertedAddr, originalAddr, "Conversion should be reversible"); + } + + function testFromBytes32FormatWithZeroAddress() public pure { + bytes32 zeroBytes32 = bytes32(0); + address convertedAddr = fromBytes32Format(zeroBytes32); + + assertEq(convertedAddr, address(0), "Zero bytes32 should convert to zero address"); + } + + function testFromBytes32FormatWithInvalidAddress() public { + // Create a bytes32 with non-zero upper bits + bytes32 invalidBytes32 = bytes32(uint256(1) << 160); + + try this.fromBytes32FormatWrapper(invalidBytes32) { + fail(); + } catch { + // Expected to revert + } + } + + function fromBytes32FormatWrapper( + bytes32 bytes32FormatAddress + ) external pure returns (address) { + return fromBytes32Format(bytes32FormatAddress); + } + + function testFromBytes32FormatWithMaxValidAddress() public pure { + address maxAddr = address(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF); + bytes32 bytes32Format = toBytes32Format(maxAddr); + + address convertedAddr = fromBytes32Format(bytes32Format); + + assertEq(convertedAddr, maxAddr, "Max address should convert correctly"); + } + + function testConvertersRoundTrip() public pure { + address originalAddr = address(0xabCDEF1234567890ABcDEF1234567890aBCDeF12); + + bytes32 bytes32Format = toBytes32Format(originalAddr); + address convertedAddr = fromBytes32Format(bytes32Format); + + assertEq(convertedAddr, originalAddr, "Round trip conversion should work"); + } + + function testConvertersFuzz(address addr) public pure { + // Skip addresses that would cause overflow + vm.assume(uint256(uint160(addr)) <= type(uint160).max); + + bytes32 bytes32Format = toBytes32Format(addr); + address convertedAddr = fromBytes32Format(bytes32Format); + + assertEq(convertedAddr, addr, "Fuzz test should pass"); + } +} diff --git a/test/Watcher.t.sol b/test/Watcher.t.sol deleted file mode 100644 index b3d0e960..00000000 --- a/test/Watcher.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "./SetupTest.t.sol"; - -contract WatcherTest is AppGatewayBaseSetup { - function setUp() public { - deploy(); - } - - function testWatcherDeployment() public { - deploy(); - - vm.assertEq(address(arbConfig.feesPlug.socket__()), address(arbConfig.socket)); - vm.assertEq(address(optConfig.feesPlug.socket__()), address(optConfig.socket)); - - vm.assertEq(address(arbConfig.contractFactoryPlug.socket__()), address(arbConfig.socket)); - vm.assertEq(address(optConfig.contractFactoryPlug.socket__()), address(optConfig.socket)); - } - - function testRevertInitSocketPlug() public { - address hackerEOA = address(0x123); - uint64 sbId = arbConfig.switchboard.switchboardId(); - - vm.expectRevert(abi.encodeWithSelector(SocketAlreadyInitialized.selector)); - arbConfig.feesPlug.initSocket(bytes32(0), address(hackerEOA), sbId); - } -} diff --git a/test/apps/ParallelCounter.t.sol b/test/apps/ParallelCounter.t.sol index 51763bb3..b71587fd 100644 --- a/test/apps/ParallelCounter.t.sol +++ b/test/apps/ParallelCounter.t.sol @@ -37,6 +37,11 @@ contract ParallelCounterTest is AppGatewayBaseSetup { chainSlugs[1] = optChainSlug; deployCounterApp(chainSlugs); + // Break down into smaller functions to avoid stack too deep + _testForwarderAddresses(); + } + + function _testForwarderAddresses() internal view { (bytes32 onChainArb1, address forwarderArb1) = getOnChainAndForwarderAddresses( arbChainSlug, counterId1, @@ -61,44 +66,55 @@ contract ParallelCounterTest is AppGatewayBaseSetup { parallelCounterGateway ); - assertEq( - IForwarder(forwarderArb1).getChainSlug(), - arbChainSlug, - "Forwarder chainSlug should be correct" - ); - assertEq( - IForwarder(forwarderArb1).getOnChainAddress(), + _assertForwarderAddresses( + forwarderArb1, onChainArb1, - "Forwarder onChainAddress should be correct" - ); - assertEq( - IForwarder(forwarderOpt1).getChainSlug(), - optChainSlug, - "Forwarder chainSlug should be correct" - ); - assertEq( - IForwarder(forwarderOpt1).getOnChainAddress(), - onChainOpt1, - "Forwarder onChainAddress should be correct" - ); - assertEq( - IForwarder(forwarderArb2).getChainSlug(), arbChainSlug, - "Forwarder chainSlug should be correct" - ); - assertEq( - IForwarder(forwarderArb2).getOnChainAddress(), + forwarderOpt1, + onChainOpt1, + optChainSlug, + forwarderArb2, onChainArb2, - "Forwarder onChainAddress should be correct" + arbChainSlug, + forwarderOpt2, + onChainOpt2, + optChainSlug ); + } + + function _assertForwarderAddresses( + address forwarderArb1, + bytes32 onChainArb1, + uint32 arbChainSlug, + address forwarderOpt1, + bytes32 onChainOpt1, + uint32 optChainSlug, + address forwarderArb2, + bytes32 onChainArb2, + uint32 arbChainSlug2, + address forwarderOpt2, + bytes32 onChainOpt2, + uint32 optChainSlug2 + ) internal view { + _assertForwarderAddress(forwarderArb1, onChainArb1, arbChainSlug); + _assertForwarderAddress(forwarderOpt1, onChainOpt1, optChainSlug); + _assertForwarderAddress(forwarderArb2, onChainArb2, arbChainSlug2); + _assertForwarderAddress(forwarderOpt2, onChainOpt2, optChainSlug2); + } + + function _assertForwarderAddress( + address forwarder, + bytes32 onChainAddress, + uint32 chainSlug + ) internal view { assertEq( - IForwarder(forwarderOpt2).getOnChainAddress(), - onChainOpt2, - "Forwarder onChainAddress should be correct" + IForwarder(forwarder).getChainSlug(), + chainSlug, + "Forwarder chainSlug should be correct" ); assertEq( - IForwarder(forwarderOpt2).getOnChainAddress(), - onChainOpt2, + IForwarder(forwarder).getOnChainAddress(), + onChainAddress, "Forwarder onChainAddress should be correct" ); } diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index 8615c82c..68ff3024 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -4,8 +4,9 @@ pragma solidity ^0.8.21; import "../../../../contracts/evmx/base/AppGatewayBase.sol"; import "./Counter.sol"; import "./ICounter.sol"; +import "../../../../contracts/evmx/interfaces/IReceiver.sol"; -contract CounterAppGateway is AppGatewayBase, Ownable { +contract CounterAppGateway is AppGatewayBase, Ownable, IReceiver { bytes32 public counter = _createContractId("counter"); bytes32 public counter1 = _createContractId("counter1"); @@ -14,6 +15,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { uint256 public optCounter; bool public incremented; + bool public feesManagerSwitch; event CounterScheduleResolved(uint256 creationTimestamp, uint256 executionTimestamp); @@ -119,8 +121,9 @@ contract CounterAppGateway is AppGatewayBase, Ownable { then(this.resolveSchedule.selector, abi.encode(block.timestamp)); } - function resolveSchedule(uint256 creationTimestamp_) external onlyPromises { - emit CounterScheduleResolved(creationTimestamp_, block.timestamp); + function resolveSchedule(bytes memory data, bytes memory) external onlyPromises { + uint256 creationTimestamp = abi.decode(data, (uint256)); + emit CounterScheduleResolved(creationTimestamp, block.timestamp); } // UTILS @@ -155,4 +158,9 @@ contract CounterAppGateway is AppGatewayBase, Ownable { function increaseFees(uint40 requestCount_, uint256 newMaxFees_) public { _increaseFees(requestCount_, newMaxFees_); } + + function onTransfer(uint32, address, uint256, uint256, bytes memory data_) public { + if (msg.sender != address(feesManager__())) revert("Only fees manager"); + feesManagerSwitch = abi.decode(data_, (bool)); + } } diff --git a/test/AuctionManager.t.sol b/test/evmx/AuctionManager.t.sol similarity index 92% rename from test/AuctionManager.t.sol rename to test/evmx/AuctionManager.t.sol index 3c3cebdf..c508431c 100644 --- a/test/AuctionManager.t.sol +++ b/test/evmx/AuctionManager.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "./SetupTest.t.sol"; -import "./apps/Counter.t.sol"; +import "../SetupTest.t.sol"; +import "../apps/Counter.t.sol"; contract AuctionManagerTest is AppGatewayBaseSetup { uint32 feesChainSlug = arbChainSlug; @@ -32,7 +32,7 @@ contract AuctionManagerTest is AppGatewayBaseSetup { function testExpireBid() public { depositNativeAndCredits(feesChainSlug, 1 ether, 0, user); - approveAppGateway(address(feesManager), user); + approve(address(feesManager), user); uint256 withdrawAmount = 0.5 ether; uint40 requestCount = watcher.getCurrentRequestCount(); diff --git a/test/FeesTest.t.sol b/test/evmx/FeesTest.t.sol similarity index 57% rename from test/FeesTest.t.sol rename to test/evmx/FeesTest.t.sol index 7fdf9d3e..e3286bd8 100644 --- a/test/FeesTest.t.sol +++ b/test/evmx/FeesTest.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "./apps/Counter.t.sol"; -import "./SetupTest.t.sol"; +import "../apps/Counter.t.sol"; +import "../SetupTest.t.sol"; contract FeesTest is AppGatewayBaseSetup { uint32 feesChainSlug = arbChainSlug; @@ -11,6 +11,7 @@ contract FeesTest is AppGatewayBaseSetup { address receiver = address(uint160(c++)); address user = address(uint160(c++)); + address counterPlug; SocketContracts feesConfig; CounterAppGateway counterGateway; @@ -19,8 +20,9 @@ contract FeesTest is AppGatewayBaseSetup { function setUp() public { deploy(); - feesConfig = getSocketConfig(feesChainSlug); + depositNativeAndCredits(feesChainSlug, 100 ether, 0, address(feesManager)); + counterGateway = new CounterAppGateway(address(addressResolver), feesAmount); depositNativeAndCredits(feesChainSlug, 100 ether, 0, address(counterGateway)); @@ -30,10 +32,116 @@ contract FeesTest is AppGatewayBaseSetup { // deploy counter app gateway counterGateway.deployContracts(feesChainSlug); executeDeploy(IAppGateway(counterGateway), feesChainSlug, contractIds); + + counterPlug = counterGateway.forwarderAddresses(contractIds[0], feesChainSlug); + } + + function testDepositAndMintSusdc() public { + address counterGatewayAddress = address(counterGateway); + // deposit usdc on fees plug and mint susdc on evmx with data execution + uint256 susdcBalanceBefore = feesManager.balanceOf(counterGatewayAddress); + assertFalse(counterGateway.feesManagerSwitch(), "should be false"); + depositNativeAndCreditsWithData( + feesChainSlug, + 100 ether, + 0, + user, + counterGatewayAddress, + abi.encode(true) + ); + + assertTrue(counterGateway.feesManagerSwitch(), "Fees manager should be called"); + assertEq( + feesManager.balanceOf(counterGatewayAddress), + susdcBalanceBefore + 100 ether, + "Susdc balance should be correct" + ); + + // burn susdc on evmx and mint susdc on chain + uint256 susdcChainBalanceBefore = feesConfig.susdcPlug.balanceOf(counterPlug); + + hoax(counterGatewayAddress); + feesManager.burn(feesChainSlug, address(counterPlug), 5 ether); + executeRequest(); + + assertEq( + feesManager.balanceOf(counterGatewayAddress), + susdcBalanceBefore + 95 ether, + "Susdc balance should be correct" + ); + assertEq( + feesConfig.susdcPlug.balanceOf(counterPlug), + susdcChainBalanceBefore + 5 ether, + "Susdc balance should be correct" + ); + + // burn susdc from chain and mint on evmx + uint256 burnAmount = 2 ether; + bytes32 triggerId = _encodeTriggerId(address(feesConfig.socket), feesChainSlug); + bytes memory payload = abi.encodeWithSelector( + Credit.mint.selector, + counterGatewayAddress, + burnAmount, + abi.encode(false) + ); + + assertTrue(counterGateway.feesManagerSwitch(), "switch should be true"); + + hoax(counterPlug); + feesConfig.susdcPlug.burn(counterGatewayAddress, burnAmount, abi.encode(false)); + + TriggerParams[] memory params = new TriggerParams[](1); + params[0] = TriggerParams({ + triggerId: triggerId, + chainSlug: feesChainSlug, + appGatewayId: toBytes32Format(address(feesManager)), + plug: toBytes32Format(address(feesConfig.susdcPlug)), + payload: payload, + overrides: bytes("") + }); + bytes memory data = abi.encode(params); + + WatcherMultiCallParams memory watcherParams = WatcherMultiCallParams({ + contractAddress: address(watcher), + data: data, + nonce: watcherNonce, + signature: _createWatcherSignature(address(watcher), data) + }); + watcherNonce++; + watcher.callAppGateways(watcherParams); + + assertFalse(counterGateway.feesManagerSwitch(), "switch should be false"); + assertEq( + feesManager.balanceOf(counterGatewayAddress), + susdcBalanceBefore + 95 ether + burnAmount, + "Susdc balance should be correct" + ); + assertEq( + feesConfig.susdcPlug.balanceOf(counterPlug), + susdcChainBalanceBefore + 5 ether - burnAmount, + "Susdc balance should be correct" + ); + + // burn susdc on evmx and withdraw usdc + uint256 withdrawAmount = 1 ether; + uint256 receiverBalanceBefore = feesConfig.testUSDC.balanceOf(receiver); + withdrawCredits(counterGatewayAddress, withdrawAmount); + + uint256 withdrawAmountInTokens = withdrawAmount / 10 ** (18 - 6); + assertEq( + receiverBalanceBefore + withdrawAmountInTokens, + feesConfig.testUSDC.balanceOf(receiver), + "Receiver Balance should be correct after burn" + ); + assertEq( + feesConfig.susdcPlug.balanceOf(counterPlug), + susdcChainBalanceBefore + 5 ether - burnAmount, + "Susdc balance should be correct after burn" + ); } function withdrawCredits(address from, uint256 withdrawAmount) public { - approveAppGateway(address(feesManager), from); + approve(address(feesManager), from); hoax(from); feesManager.withdrawCredits( @@ -48,7 +156,7 @@ contract FeesTest is AppGatewayBaseSetup { function testWithdrawTransmitterFees() public { uint256 transmitterReceiverBalanceBefore = feesConfig.testUSDC.balanceOf(receiver); - uint256 withdrawAmount = feesManager.getAvailableCredits(transmitterEOA); + uint256 withdrawAmount = feesManager.balanceOf(transmitterEOA); withdrawAmount = withdrawAmount - feesAmount; withdrawCredits(transmitterEOA, withdrawAmount); @@ -111,14 +219,14 @@ contract FeesTest is AppGatewayBaseSetup { abi.encodeWithSelector(Configurations.setAppGatewayConfigs.selector, configs) ); - approveAppGateway(address(feesManager), address(counterGateway)); + approve(address(feesManager), address(counterGateway)); uint256 withdrawAmount = 0.5 ether; vm.expectRevert(abi.encodeWithSelector(InvalidChainSlug.selector)); hoax(address(counterGateway)); feesManager.withdrawCredits( - arbChainSlug, - address(arbConfig.testUSDC), + feesChainSlug, + address(feesConfig.testUSDC), withdrawAmount, feesAmount, address(receiver) @@ -127,8 +235,6 @@ contract FeesTest is AppGatewayBaseSetup { function testMigrateFeesPlug() public { FeesPlug oldFeesPlug = arbConfig.feesPlug; - uint64 sbId = arbConfig.switchboard.switchboardId(); - // disconnect old fees plug hoax(socketOwner); oldFeesPlug.disconnectSocket(); @@ -166,26 +272,9 @@ contract FeesTest is AppGatewayBaseSetup { uint256 withdrawAmount = 0.5 ether; uint256 withdrawAmountInTokens = withdrawAmount / 10 ** (18 - 6); - approveAppGateway(address(feesManager), address(counterGateway)); + approve(address(feesManager), address(counterGateway)); uint256 receiverBalanceBefore = arbConfig.testUSDC.balanceOf(receiver); - - hoax(address(counterGateway)); - feesManager.withdrawCredits( - arbChainSlug, - address(arbConfig.testUSDC), - withdrawAmount, - feesAmount, - address(receiver) - ); - executeRequest(); - - assertEq( - arbConfig.testUSDC.balanceOf(receiver), - receiverBalanceBefore, - "Receiver balance should be same" - ); - arbConfig.testUSDC.mint(address(arbConfig.feesPlug), withdrawAmount); withdrawCredits(address(counterGateway), withdrawAmount); diff --git a/test/ProxyMigration.t.sol b/test/evmx/ProxyMigration.t.sol similarity index 99% rename from test/ProxyMigration.t.sol rename to test/evmx/ProxyMigration.t.sol index d05b2897..cb1acfa3 100644 --- a/test/ProxyMigration.t.sol +++ b/test/evmx/ProxyMigration.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.21; import "./ProxyStorage.t.sol"; -import "./mock/MockWatcherPrecompile.sol"; +import "../mock/MockWatcherPrecompile.sol"; contract MigrationTest is ProxyStorageAssertions { // ERC1967Factory emits this event with both proxy and implementation addresses diff --git a/test/ProxyStorage.t.sol b/test/evmx/ProxyStorage.t.sol similarity index 99% rename from test/ProxyStorage.t.sol rename to test/evmx/ProxyStorage.t.sol index 3533c6df..960f90f7 100644 --- a/test/ProxyStorage.t.sol +++ b/test/evmx/ProxyStorage.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "./SetupTest.t.sol"; +import "../SetupTest.t.sol"; contract ProxyStorageAssertions is AppGatewayBaseSetup { uint256 public constant FIRST_SLOT = 50; diff --git a/test/evmx/Watcher.t.sol b/test/evmx/Watcher.t.sol new file mode 100644 index 00000000..dafcfbee --- /dev/null +++ b/test/evmx/Watcher.t.sol @@ -0,0 +1,940 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../SetupTest.t.sol"; +import "../../contracts/evmx/watcher/Watcher.sol"; +import "../../contracts/evmx/watcher/RequestHandler.sol"; +import "../../contracts/evmx/watcher/Configurations.sol"; +import "../../contracts/evmx/watcher/PromiseResolver.sol"; +import "../../contracts/evmx/watcher/precompiles/ReadPrecompile.sol"; +import "../../contracts/evmx/watcher/precompiles/WritePrecompile.sol"; +import "../../contracts/evmx/watcher/precompiles/SchedulePrecompile.sol"; +import "../../contracts/evmx/interfaces/IWatcher.sol"; +import "../../contracts/evmx/interfaces/IRequestHandler.sol"; +import "../../contracts/evmx/interfaces/IConfigurations.sol"; +import "../../contracts/evmx/interfaces/IPromiseResolver.sol"; +import "../../contracts/evmx/interfaces/IPrecompile.sol"; +import "../../contracts/utils/common/Structs.sol"; +import "../../contracts/utils/common/Errors.sol"; +import "../../contracts/utils/common/Converters.sol"; +import "solady/auth/Ownable.sol"; +import "../apps/app-gateways/counter/CounterAppGateway.sol"; + +contract WatcherTest is AppGatewayBaseSetup { + uint256 private ownerPrivateKey = + 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef; + + address public owner = vm.addr(ownerPrivateKey); + address public nonOwner = vm.addr(c++); + address public user = vm.addr(c++); + bytes32 plug = toBytes32Format(vm.addr(c++)); + + CounterAppGateway public appGateway; + address public watcherAddress; + address public requestHandlerAddress; + address public configurationsAddress; + address public promiseResolverAddress; + + function setUp() public { + deploy(); + + watcherAddress = address(watcher); + requestHandlerAddress = address(requestHandler); + configurationsAddress = address(configurations); + promiseResolverAddress = address(promiseResolver); + + appGateway = new CounterAppGateway(address(addressResolver), writeFees); + depositNativeAndCredits(arbChainSlug, 1 ether, 0, address(appGateway)); + + hoax(address(appGateway)); + watcher.setIsValidPlug(true, arbConfig.chainSlug, plug); + } + + // ============ WATCHER ACCESS CONTROL TESTS ============ + + function testWatcherSetCoreContracts() public { + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(Ownable.Unauthorized.selector)); + watcher.setCoreContracts(address(0x1), address(0x2), address(0x3)); + + hoax(watcherEOA); + vm.expectEmit(true, true, true, true); + emit Watcher.CoreContractsSet(address(0x1), address(0x2), address(0x3)); + watcher.setCoreContracts(address(0x1), address(0x2), address(0x3)); + + assertEq(address(watcher.requestHandler__()), address(0x1)); + assertEq(address(watcher.configurations__()), address(0x2)); + assertEq(address(watcher.promiseResolver__()), address(0x3)); + } + + function testWatcherRescueFunds() public { + vm.expectRevert(abi.encodeWithSelector(InvalidSignature.selector)); + watcher.rescueFunds(ETH_ADDRESS, user, 100, watcherNonce, ""); + assertEq(user.balance, 0); + + bytes memory invalidSignature = _createWatcherSignature( + address(0), + abi.encode(ETH_ADDRESS, user, uint256(100)) + ); + + vm.expectRevert(abi.encodeWithSelector(InvalidSignature.selector)); + watcher.rescueFunds(ETH_ADDRESS, user, 100, watcherNonce, invalidSignature); + assertEq(user.balance, 0); + + bytes memory signature = _createWatcherSignature( + watcherAddress, + abi.encode(ETH_ADDRESS, user, uint256(100)) + ); + + vm.deal(watcherAddress, 100); + watcher.rescueFunds(ETH_ADDRESS, user, 100, watcherNonce, signature); + assertEq(user.balance, 100); + } + + function testWatcherSetTriggerFees() public { + uint256 newFees = 1000000; + + vm.expectRevert(abi.encodeWithSelector(InvalidSignature.selector)); + watcher.setTriggerFees(newFees, watcherNonce, ""); + assertEq(watcher.triggerFees(), triggerFees); + + bytes memory invalidSignature = _createWatcherSignature(address(0), abi.encode(newFees)); + vm.expectRevert(abi.encodeWithSelector(InvalidSignature.selector)); + watcher.setTriggerFees(newFees, watcherNonce, invalidSignature); + assertEq(watcher.triggerFees(), triggerFees); + + bytes memory signature = _createWatcherSignature(watcherAddress, abi.encode(newFees)); + vm.expectEmit(true, true, true, true); + emit Trigger.TriggerFeesSet(newFees); + watcher.setTriggerFees(newFees, watcherNonce, signature); + + assertEq(watcher.triggerFees(), newFees); + } + + function testWatcherMultiCall() public { + address contractAddress = address(writePrecompile); + bytes32 payloadId = keccak256(abi.encodePacked("random id")); + bytes32 digest = keccak256(abi.encodePacked("random digest")); + bytes memory proof = createSignature( + keccak256( + abi.encodePacked( + toBytes32Format(address(arbConfig.switchboard)), + arbConfig.chainSlug, + digest + ) + ), + watcherPrivateKey + ); + bytes memory data = abi.encodeWithSelector( + WritePrecompile.uploadProof.selector, + payloadId, + proof + ); + bytes memory signature = _createWatcherSignature(contractAddress, data); + + WatcherMultiCallParams[] memory params = new WatcherMultiCallParams[](1); + vm.expectRevert(abi.encodeWithSelector(InvalidContract.selector)); + watcher.watcherMultiCall(params); + + params[0] = WatcherMultiCallParams({ + contractAddress: contractAddress, + data: bytes(""), + nonce: watcherNonce, + signature: signature + }); + vm.expectRevert(abi.encodeWithSelector(InvalidData.selector)); + watcher.watcherMultiCall(params); + + params[0] = WatcherMultiCallParams({ + contractAddress: contractAddress, + data: data, + nonce: watcherNonce, + signature: bytes("") + }); + vm.expectRevert(abi.encodeWithSelector(InvalidSignature.selector)); + watcher.watcherMultiCall(params); + + bytes32 multiCallDigest = keccak256( + abi.encode(address(watcher), evmxSlug, watcherNonce, contractAddress, data) + ); + bytes memory invalidSignature = createSignature(multiCallDigest, ownerPrivateKey); + params[0] = WatcherMultiCallParams({ + contractAddress: contractAddress, + data: data, + nonce: watcherNonce, + signature: invalidSignature + }); + vm.expectRevert(abi.encodeWithSelector(InvalidSignature.selector)); + watcher.watcherMultiCall(params); + + params[0] = WatcherMultiCallParams({ + contractAddress: contractAddress, + data: data, + nonce: watcherNonce, + signature: signature + }); + vm.expectEmit(true, true, true, false); + emit WriteProofUploaded(payloadId, proof); + watcher.watcherMultiCall(params); + assertEq(writePrecompile.watcherProofs(payloadId), proof); + + vm.expectRevert(abi.encodeWithSelector(NonceUsed.selector)); + watcher.watcherMultiCall(params); + watcherNonce++; + } + + function testWatcherCallAppGateways() public { + TriggerParams[] memory params = new TriggerParams[](1); + params[0] = TriggerParams({ + triggerId: bytes32(0), + plug: plug, + appGatewayId: toBytes32Format(address(appGateway)), + chainSlug: arbConfig.chainSlug, + overrides: "", + payload: abi.encodeWithSelector( + CounterAppGateway.initializeOnChain.selector, + arbConfig.chainSlug + ) + }); + + bytes memory signature = _createWatcherSignature(address(watcher), abi.encode(params)); + bytes32 multiCallDigest = keccak256( + abi.encode(address(watcher), evmxSlug, watcherNonce, watcherAddress, abi.encode(params)) + ); + bytes memory invalidSignature = createSignature(multiCallDigest, ownerPrivateKey); + + WatcherMultiCallParams memory callParams = WatcherMultiCallParams({ + contractAddress: address(watcher), + data: abi.encode(params), + nonce: watcherNonce, + signature: invalidSignature + }); + vm.expectRevert(abi.encodeWithSelector(InvalidSignature.selector)); + watcher.callAppGateways(callParams); + + callParams.signature = signature; + vm.expectEmit(true, true, true, true); + emit Trigger.TriggerSucceeded( + 0x0000000000000000000000000000000000000000000000000000000000000000 + ); + watcher.callAppGateways(callParams); + + vm.expectRevert(abi.encodeWithSelector(NonceUsed.selector)); + watcher.callAppGateways(callParams); + } + + // // ============ REQUEST HANDLER ACCESS CONTROL TESTS ============ + + function testRequestHandlerSetPrecompile() public { + vm.expectRevert(abi.encodeWithSelector(Ownable.Unauthorized.selector)); + requestHandler.setPrecompile(bytes4(0x12345678), IPrecompile(address(0x1))); + + hoax(watcherEOA); + vm.expectEmit(true, true, true, true); + emit RequestHandler.PrecompileSet(bytes4(0x12345678), IPrecompile(address(0x1))); + requestHandler.setPrecompile(bytes4(0x12345678), IPrecompile(address(0x1))); + } + + function testRequestHandlerSetRequestPayloadCountLimit() public { + vm.expectRevert(abi.encodeWithSelector(Ownable.Unauthorized.selector)); + requestHandler.setRequestPayloadCountLimit(200); + + hoax(watcherEOA); + vm.expectEmit(true, true, true, true); + emit RequestHandler.RequestPayloadCountLimitSet(200); + requestHandler.setRequestPayloadCountLimit(200); + } + + function testRequestHandlerRescueFunds() public { + address rescueTo = address(0x2); + uint256 initialBalance = rescueTo.balance; + + vm.deal(address(requestHandler), 100); + hoax(watcherAddress); + requestHandler.rescueFunds(ETH_ADDRESS, rescueTo, 100); + + assertEq(rescueTo.balance, initialBalance + 100); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + requestHandler.rescueFunds(ETH_ADDRESS, rescueTo, 100); + } + + function testRequestHandlerSubmitRequest() public { + QueueParams[] memory queueParams = new QueueParams[](0); + + hoax(watcherAddress); + requestHandler.submitRequest( + 1000, + address(0x1), + address(0x2), + address(0x3), + queueParams, + "" + ); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + requestHandler.submitRequest( + 1000, + address(0x1), + address(0x2), + address(0x3), + queueParams, + "" + ); + } + + function testRequestHandlerIncreaseFees() public { + uint40 requestCount = 0; + appGateway.deployContracts(arbConfig.chainSlug); + + hoax(watcherAddress); + vm.expectRevert(abi.encodeWithSelector(OnlyAppGateway.selector)); + requestHandler.increaseFees(requestCount, writeFees + 100, address(vm.addr(c++))); + + hoax(watcherAddress); + vm.expectRevert( + abi.encodeWithSelector(NewMaxFeesLowerThanCurrent.selector, writeFees, writeFees) + ); + requestHandler.increaseFees(requestCount, writeFees, address(appGateway)); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + requestHandler.increaseFees(requestCount, writeFees, address(appGateway)); + + hoax(watcherAddress); + vm.expectRevert(abi.encodeWithSelector(InsufficientFees.selector)); + requestHandler.increaseFees(requestCount, 2 ether, address(appGateway)); + + hoax(watcherAddress); + requestHandler.increaseFees(requestCount, writeFees + 100, address(appGateway)); + + bytes32[] memory contractIds = new bytes32[](1); + contractIds[0] = appGateway.counter(); + requestCount = executeDeploy(appGateway, arbConfig.chainSlug, contractIds); + + hoax(watcherAddress); + vm.expectRevert(abi.encodeWithSelector(RequestAlreadySettled.selector)); + requestHandler.increaseFees(requestCount, writeFees + 100, address(appGateway)); + } + + function testRequestHandlerCancelRequestForReverts() public { + uint40 requestCount = 0; + appGateway.deployContracts(arbConfig.chainSlug); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(NotPromiseResolver.selector)); + requestHandler.cancelRequestForReverts(requestCount); + + hoax(promiseResolverAddress); + vm.expectEmit(true, true, true, true); + emit RequestHandler.RequestCancelled(requestCount); + emit RequestHandler.RequestSettled(requestCount, address(0)); + requestHandler.cancelRequestForReverts(requestCount); + + hoax(promiseResolverAddress); + vm.expectRevert(abi.encodeWithSelector(RequestAlreadyCancelled.selector)); + requestHandler.cancelRequestForReverts(requestCount); + } + + function testRequestHandlerHandleRevert() public { + uint40 requestCount = 0; + appGateway.deployContracts(arbConfig.chainSlug); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(NotPromiseResolver.selector)); + requestHandler.handleRevert(requestCount); + + hoax(promiseResolverAddress); + vm.expectEmit(true, true, true, true); + emit RequestHandler.RequestCancelled(requestCount); + emit RequestHandler.RequestSettled(requestCount, address(0)); + requestHandler.handleRevert(requestCount); + + hoax(promiseResolverAddress); + vm.expectRevert(abi.encodeWithSelector(RequestAlreadyCancelled.selector)); + requestHandler.handleRevert(requestCount); + } + + function testRequestHandlerCancelRequest() public { + uint40 requestCount = 0; + appGateway.deployContracts(arbConfig.chainSlug); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + requestHandler.cancelRequest(requestCount, address(appGateway)); + + hoax(watcherAddress); + vm.expectRevert(abi.encodeWithSelector(InvalidCaller.selector)); + requestHandler.cancelRequest(requestCount, address(0x01)); + + hoax(watcherAddress); + vm.expectEmit(true, true, true, true); + emit RequestHandler.RequestCancelled(requestCount); + emit RequestHandler.RequestSettled(requestCount, address(0)); + requestHandler.cancelRequest(requestCount, address(appGateway)); + + hoax(watcherAddress); + vm.expectRevert(abi.encodeWithSelector(RequestAlreadyCancelled.selector)); + requestHandler.cancelRequest(requestCount, address(appGateway)); + } + + function testRequestHandlerAssignTransmitter() public { + uint40 requestCount = 0; + appGateway.deployContracts(arbConfig.chainSlug); + Bid memory bid = Bid({fee: 100, transmitter: transmitterEOA, extraData: ""}); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(InvalidCaller.selector)); + requestHandler.assignTransmitter(1, bid); + + hoax(address(auctionManager)); + requestHandler.assignTransmitter(requestCount, bid); + + hoax(watcherAddress); + requestHandler.cancelRequest(requestCount, address(appGateway)); + hoax(address(auctionManager)); + vm.expectRevert(abi.encodeWithSelector(RequestAlreadyCancelled.selector)); + requestHandler.assignTransmitter(requestCount, bid); + } + + function testRequestHandlerUpdateRequestAndProcessBatch() public { + appGateway.deployContracts(arbConfig.chainSlug); + uint40 requestCount = 0; + uint40[] memory batches = requestHandler.getRequestBatchIds(requestCount); + bytes32[] memory payloadIds = requestHandler.getBatchPayloadIds(batches[0]); + bytes32 payloadId = payloadIds[0]; + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(NotPromiseResolver.selector)); + requestHandler.updateRequestAndProcessBatch(requestCount, payloadId); + + hoax(watcherAddress); + requestHandler.cancelRequest(requestCount, address(appGateway)); + hoax(address(promiseResolver)); + vm.expectRevert(abi.encodeWithSelector(RequestAlreadyCancelled.selector)); + requestHandler.updateRequestAndProcessBatch(requestCount, payloadId); + } + + // ============ CONFIGURATIONS ACCESS CONTROL TESTS ============ + + function testConfigurationsSetSocket() public { + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(Ownable.Unauthorized.selector)); + configurations.setSocket(1, bytes32(uint256(1))); + + hoax(watcherEOA); + vm.expectEmit(true, true, true, true); + emit Configurations.SocketSet(1, bytes32(uint256(1))); + configurations.setSocket(1, bytes32(uint256(1))); + } + + function testConfigurationsSetSwitchboard() public { + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(Ownable.Unauthorized.selector)); + configurations.setSwitchboard(1, bytes32(uint256(1)), 1); + + hoax(watcherEOA); + vm.expectEmit(true, true, true, true); + emit Configurations.SwitchboardSet(1, bytes32(uint256(1)), 1); + configurations.setSwitchboard(1, bytes32(uint256(1)), 1); + } + + function testConfigurationsSetAppGatewayConfigs() public { + AppGatewayConfig[] memory configs = new AppGatewayConfig[](1); + configs[0] = AppGatewayConfig({ + chainSlug: 1, + plug: bytes32(uint256(1)), + plugConfig: PlugConfigGeneric({appGatewayId: bytes32(uint256(1)), switchboardId: 1}) + }); + + hoax(watcherAddress); + vm.expectEmit(true, true, true, true); + emit Configurations.PlugAdded(bytes32(uint256(1)), 1, bytes32(uint256(1))); + configurations.setAppGatewayConfigs(configs); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + configurations.setAppGatewayConfigs(configs); + } + + function testConfigurationsSetIsValidPlug() public { + hoax(watcherAddress); + vm.expectEmit(true, true, true, true); + emit Configurations.IsValidPlugSet(true, 1, bytes32(uint256(1)), address(appGateway)); + configurations.setIsValidPlug(true, 1, bytes32(uint256(1)), address(appGateway)); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + configurations.setIsValidPlug(true, 1, bytes32(uint256(1)), address(appGateway)); + } + + function testConfigurationsRescueFunds() public { + address rescueTo = address(0x2); + uint256 initialBalance = rescueTo.balance; + + vm.deal(address(configurations), 100); + hoax(watcherAddress); + configurations.rescueFunds(ETH_ADDRESS, rescueTo, 100); + + assertEq(rescueTo.balance, initialBalance + 100); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + configurations.rescueFunds(ETH_ADDRESS, rescueTo, 100); + } + + // ============ PROMISE RESOLVER ACCESS CONTROL TESTS ============ + + function testPromiseResolverResolvePromises() public { + appGateway.deployContracts(arbConfig.chainSlug); + uint40 requestCount = 0; + uint40[] memory batches = requestHandler.getRequestBatchIds(requestCount); + bytes32[] memory payloadIds = requestHandler.getBatchPayloadIds(batches[0]); + bytes32 payloadId = payloadIds[0]; + Bid memory bid = Bid({fee: 100, transmitter: transmitterEOA, extraData: ""}); + hoax(address(auctionManager)); + requestHandler.assignTransmitter(requestCount, bid); + + PromiseReturnData[] memory promiseReturnData = new PromiseReturnData[](1); + promiseReturnData[0] = PromiseReturnData({ + exceededMaxCopy: false, + payloadId: payloadId, + returnData: abi.encode(vm.addr(c++)) + }); + + vm.expectEmit(true, true, true, true); + emit PromiseResolver.PromiseResolved( + payloadId, + watcher.getPayloadParams(payloadId).asyncPromise + ); + hoax(watcherAddress); + promiseResolver.resolvePromises(promiseReturnData); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + promiseResolver.resolvePromises(promiseReturnData); + } + + function testPromiseResolverMarkRevert() public { + PromiseReturnData memory resolvedPromise = PromiseReturnData({ + exceededMaxCopy: false, + payloadId: bytes32(uint256(1)), + returnData: "" + }); + + hoax(watcherAddress); + promiseResolver.markRevert(resolvedPromise, true); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + promiseResolver.markRevert(resolvedPromise, true); + } + + function testPromiseResolverRescueFunds() public { + address rescueTo = address(0x2); + uint256 initialBalance = rescueTo.balance; + + vm.deal(address(promiseResolver), 100); + hoax(watcherAddress); + promiseResolver.rescueFunds(ETH_ADDRESS, rescueTo, 100); + assertEq(rescueTo.balance, initialBalance + 100); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + promiseResolver.rescueFunds(ETH_ADDRESS, rescueTo, 100); + } + + // // ============ READ PRECOMPILE ACCESS CONTROL TESTS ============ + + function testReadPrecompileSetFees() public { + hoax(watcherAddress); + vm.expectEmit(true, true, true, true); + emit ReadPrecompile.ReadFeesSet(1000); + readPrecompile.setFees(1000); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + readPrecompile.setFees(1000); + } + + function testReadPrecompileSetExpiryTime() public { + hoax(watcherAddress); + vm.expectEmit(true, true, true, true); + emit ReadPrecompile.ExpiryTimeSet(3600); + readPrecompile.setExpiryTime(3600); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + readPrecompile.setExpiryTime(3600); + } + + function testReadPrecompileRescueFunds() public { + address rescueTo = address(0x2); + uint256 initialBalance = rescueTo.balance; + + vm.deal(address(readPrecompile), 100); + hoax(watcherAddress); + readPrecompile.rescueFunds(ETH_ADDRESS, rescueTo, 100); + + assertEq(rescueTo.balance, initialBalance + 100); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + readPrecompile.rescueFunds(ETH_ADDRESS, rescueTo, 100); + } + + function testReadPrecompileHandlePayload() public { + Transaction memory transaction = Transaction({ + chainSlug: 1, + target: bytes32(uint256(0x1)), + payload: abi.encode(vm.addr(c++)) + }); + PayloadParams memory payloadParams = PayloadParams({ + payloadPointer: 0, + callType: bytes4(0), + asyncPromise: address(0), + appGateway: address(0), + payloadId: bytes32(0), + precompileData: abi.encode(transaction, 0), + deadline: 0, + resolvedAt: 0 + }); + + hoax(address(requestHandler)); + vm.expectEmit(true, true, true, true); + emit ReadPrecompile.ReadRequested(transaction, 0, bytes32(0)); + readPrecompile.handlePayload(address(0x1), payloadParams); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyRequestHandlerAllowed.selector)); + readPrecompile.handlePayload(address(0x1), payloadParams); + } + + function testReadPrecompileResolvePayload() public { + PayloadParams memory payloadParams = PayloadParams({ + payloadPointer: 0, + callType: bytes4(0), + asyncPromise: address(0), + appGateway: address(0), + payloadId: bytes32(0), + precompileData: "", + deadline: 0, + resolvedAt: 0 + }); + + hoax(address(requestHandler)); + readPrecompile.resolvePayload(payloadParams); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyRequestHandlerAllowed.selector)); + readPrecompile.resolvePayload(payloadParams); + } + + // ============ WRITE PRECOMPILE ACCESS CONTROL TESTS ============ + + function testWritePrecompileSetFees() public { + hoax(watcherAddress); + vm.expectEmit(true, true, true, true); + emit WritePrecompile.FeesSet(1000); + writePrecompile.setFees(1000); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + writePrecompile.setFees(1000); + } + + function testWritePrecompileSetExpiryTime() public { + hoax(watcherAddress); + vm.expectEmit(true, true, true, true); + emit WritePrecompile.ExpiryTimeSet(3600); + writePrecompile.setExpiryTime(3600); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + writePrecompile.setExpiryTime(3600); + } + + function testWritePrecompileRescueFunds() public { + address rescueTo = address(0x2); + uint256 initialBalance = rescueTo.balance; + + vm.deal(address(writePrecompile), 100); + hoax(watcherAddress); + writePrecompile.rescueFunds(ETH_ADDRESS, rescueTo, 100); + assertEq(rescueTo.balance, initialBalance + 100); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + writePrecompile.rescueFunds(ETH_ADDRESS, rescueTo, 100); + } + + function testWritePrecompileUploadProof() public { + hoax(watcherAddress); + vm.expectEmit(true, true, true, true); + emit WritePrecompile.WriteProofUploaded(bytes32(uint256(1)), "proof"); + writePrecompile.uploadProof(bytes32(uint256(1)), "proof"); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + writePrecompile.uploadProof(bytes32(uint256(1)), "proof"); + } + + function testWritePrecompileUpdateChainMaxMsgValueLimits() public { + hoax(watcherEOA); + vm.expectEmit(true, true, true, true); + emit WritePrecompile.ChainMaxMsgValueLimitsUpdated(1, 1000); + writePrecompile.updateChainMaxMsgValueLimits(1, 1000); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(Ownable.Unauthorized.selector)); + writePrecompile.updateChainMaxMsgValueLimits(1, 1000); + } + + function testWritePrecompileSetContractFactoryPlugs() public { + hoax(watcherEOA); + vm.expectEmit(true, true, true, true); + emit WritePrecompile.ContractFactoryPlugSet(1, bytes32(uint256(1))); + writePrecompile.setContractFactoryPlugs(1, bytes32(uint256(1))); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(Ownable.Unauthorized.selector)); + writePrecompile.setContractFactoryPlugs(1, bytes32(uint256(1))); + } + + function testWritePrecompileHandlePayload() public { + Transaction memory transaction = Transaction({ + chainSlug: arbConfig.chainSlug, + target: bytes32(uint256(0x1)), + payload: abi.encode(vm.addr(c++)) + }); + PayloadParams memory payloadParams = PayloadParams({ + payloadPointer: 0, + callType: bytes4(0), + asyncPromise: address(0), + appGateway: address(appGateway), + payloadId: bytes32(0), + precompileData: abi.encode(appGateway, transaction, WriteFinality.LOW, 0, 0, 0), + deadline: 0, + resolvedAt: 0 + }); + + hoax(address(requestHandler)); + writePrecompile.handlePayload(address(transmitterEOA), payloadParams); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyRequestHandlerAllowed.selector)); + writePrecompile.handlePayload(address(transmitterEOA), payloadParams); + } + + function testWritePrecompileResolvePayload() public { + PayloadParams memory payloadParams = PayloadParams({ + payloadPointer: 0, + callType: bytes4(0), + asyncPromise: address(0), + appGateway: address(0), + payloadId: bytes32(0), + precompileData: "", + deadline: 0, + resolvedAt: 0 + }); + + hoax(address(requestHandler)); + writePrecompile.resolvePayload(payloadParams); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyRequestHandlerAllowed.selector)); + writePrecompile.resolvePayload(payloadParams); + } + + // ============ SCHEDULE PRECOMPILE ACCESS CONTROL TESTS ============ + + function testSchedulePrecompileSetMaxScheduleDelayInSeconds() public { + hoax(watcherAddress); + vm.expectEmit(true, true, true, true); + emit SchedulePrecompile.MaxScheduleDelayInSecondsSet(7200); + schedulePrecompile.setMaxScheduleDelayInSeconds(7200); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + schedulePrecompile.setMaxScheduleDelayInSeconds(7200); + } + + function testSchedulePrecompileSetScheduleFeesPerSecond() public { + hoax(watcherAddress); + vm.expectEmit(true, true, true, true); + emit SchedulePrecompile.ScheduleFeesPerSecondSet(100); + schedulePrecompile.setScheduleFeesPerSecond(100); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + schedulePrecompile.setScheduleFeesPerSecond(100); + } + + function testSchedulePrecompileSetScheduleCallbackFees() public { + hoax(watcherAddress); + vm.expectEmit(true, true, true, true); + emit SchedulePrecompile.ScheduleCallbackFeesSet(500); + schedulePrecompile.setScheduleCallbackFees(500); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + schedulePrecompile.setScheduleCallbackFees(500); + } + + function testSchedulePrecompileSetExpiryTime() public { + uint256 expiryTime = expiryTime + 100; + hoax(watcherAddress); + vm.expectEmit(true, true, true, true); + emit SchedulePrecompile.ExpiryTimeSet(expiryTime); + schedulePrecompile.setExpiryTime(expiryTime); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + schedulePrecompile.setExpiryTime(expiryTime); + } + + function testSchedulePrecompileRescueFunds() public { + address rescueTo = address(0x2); + uint256 initialBalance = rescueTo.balance; + + vm.deal(address(schedulePrecompile), 100); + hoax(watcherAddress); + schedulePrecompile.rescueFunds(ETH_ADDRESS, rescueTo, 100); + + assertEq(rescueTo.balance, initialBalance + 100); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyWatcherAllowed.selector)); + schedulePrecompile.rescueFunds(ETH_ADDRESS, rescueTo, 100); + } + + function testSchedulePrecompileHandlePayload() public { + appGateway.deployContracts(arbConfig.chainSlug); + uint40 requestCount = 0; + uint40[] memory batches = requestHandler.getRequestBatchIds(requestCount); + bytes32[] memory payloadIds = requestHandler.getBatchPayloadIds(batches[0]); + bytes32 payloadId = payloadIds[0]; + PayloadParams memory payloadParams = watcher.getPayloadParams(payloadId); + + hoax(address(requestHandler)); + schedulePrecompile.handlePayload(address(transmitterEOA), payloadParams); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyRequestHandlerAllowed.selector)); + schedulePrecompile.handlePayload(address(transmitterEOA), payloadParams); + } + + function testSchedulePrecompileResolvePayload() public { + PayloadParams memory payloadParams = PayloadParams({ + payloadPointer: 0, + callType: bytes4(0), + asyncPromise: address(0), + appGateway: address(0), + payloadId: bytes32(0), + precompileData: abi.encode(0, 0), + deadline: 0, + resolvedAt: 0 + }); + + hoax(address(requestHandler)); + vm.expectEmit(true, true, true, true); + emit SchedulePrecompile.ScheduleResolved(bytes32(0)); + schedulePrecompile.resolvePayload(payloadParams); + + hoax(nonOwner); + vm.expectRevert(abi.encodeWithSelector(OnlyRequestHandlerAllowed.selector)); + schedulePrecompile.resolvePayload(payloadParams); + } + + // ============ INVALID PLUG CONNECTION TESTS ============ + + function testInvalidPlugConnection() public { + uint32 chainSlug = 1; + bytes32 target = bytes32(uint256(0x123)); + address validAppGateway = address(0x456); + bytes32 switchboardType = bytes32(uint256(0x789)); + uint64 switchboardId = 123; + + AppGatewayConfig[] memory configs = new AppGatewayConfig[](1); + configs[0] = AppGatewayConfig({ + chainSlug: chainSlug, + plug: target, + plugConfig: PlugConfigGeneric({ + appGatewayId: toBytes32Format(validAppGateway), + switchboardId: switchboardId + }) + }); + + hoax(watcherAddress); + configurations.setAppGatewayConfigs(configs); + + hoax(watcherEOA); + configurations.setSwitchboard(chainSlug, switchboardType, switchboardId); + + address invalidAppGateway = address(0x999); + vm.expectRevert(InvalidGateway.selector); + configurations.verifyConnections(chainSlug, target, invalidAppGateway, switchboardType); + + bytes32 invalidSwitchboardType = bytes32(uint256(0x999)); + vm.expectRevert(InvalidSwitchboard.selector); + configurations.verifyConnections( + chainSlug, + target, + validAppGateway, + invalidSwitchboardType + ); + + bytes32 invalidTarget = bytes32(uint256(0x999)); + vm.expectRevert(InvalidGateway.selector); + configurations.verifyConnections( + chainSlug, + invalidTarget, + validAppGateway, + switchboardType + ); + + configurations.verifyConnections(chainSlug, target, validAppGateway, switchboardType); + } + + function testInvalidPlugConnectionWithUnconfiguredChain() public { + uint32 unconfiguredChainSlug = 999; + bytes32 target = bytes32(uint256(0x123)); + bytes32 switchboardType = bytes32(uint256(0x789)); + + vm.expectRevert(InvalidGateway.selector); + configurations.verifyConnections( + unconfiguredChainSlug, + target, + address(appGateway), + switchboardType + ); + } + + function testInvalidPlugConnectionWithZeroAddresses() public { + uint32 chainSlug = 1; + bytes32 target = bytes32(uint256(0x123)); + address zeroAppGateway = address(0); + bytes32 switchboardType = bytes32(uint256(0x789)); + + AppGatewayConfig[] memory configs = new AppGatewayConfig[](1); + configs[0] = AppGatewayConfig({ + chainSlug: chainSlug, + plug: target, + plugConfig: PlugConfigGeneric({ + appGatewayId: toBytes32Format(address(0x456)), + switchboardId: 123 + }) + }); + + hoax(watcherAddress); + configurations.setAppGatewayConfigs(configs); + + hoax(watcherEOA); + configurations.setSwitchboard(chainSlug, switchboardType, 123); + + vm.expectRevert(InvalidGateway.selector); + configurations.verifyConnections(chainSlug, target, zeroAppGateway, switchboardType); + } +} diff --git a/test/mock/MockERC721.sol b/test/mock/MockERC721.sol new file mode 100644 index 00000000..08461c4e --- /dev/null +++ b/test/mock/MockERC721.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +import {ERC721} from "solady/tokens/ERC721.sol"; + +contract MockERC721 is ERC721 { + string private _name = "MockERC721"; + string private _symbol = "MOCK721"; + + // Simple tokenId tracker for minting + uint256 private _nextTokenId = 1; + + function name() public view override returns (string memory) { + return _name; + } + + function symbol() public view override returns (string memory) { + return _symbol; + } + + /// @notice Mint a new token to `to` with a specific `tokenId` + function mint(address to, uint256 tokenId) public { + _mint(to, tokenId); + } + + /// @notice Mint a new token to `to` with auto-incremented tokenId + function mint(address to) public returns (uint256 tokenId) { + tokenId = _nextTokenId++; + _mint(to, tokenId); + } + + /// @notice Burn a token + function burn(uint256 tokenId) public { + // Only owner or approved can burn + if ( + msg.sender != ownerOf(tokenId) && + !isApprovedForAll(ownerOf(tokenId), msg.sender) && + getApproved(tokenId) != msg.sender + ) { + revert NotOwnerNorApproved(); + } + _burn(tokenId); + } + + function tokenURI(uint256 id) public view virtual override returns (string memory) { + return ""; + } +} diff --git a/test/mock/MockFastSwitchboard.sol b/test/mock/MockFastSwitchboard.sol index 24b31cd3..6ed61324 100644 --- a/test/mock/MockFastSwitchboard.sol +++ b/test/mock/MockFastSwitchboard.sol @@ -11,6 +11,8 @@ contract MockFastSwitchboard is ISwitchboard { // chain slug of deployed chain uint32 public immutable chainSlug; uint64 public switchboardId; + bool public attestCalled; + bool public isPayloadAllowed; /** * @dev Constructor of SwitchboardBase @@ -21,17 +23,26 @@ contract MockFastSwitchboard is ISwitchboard { chainSlug = chainSlug_; socket__ = ISocket(socket_); owner = owner_; + + isPayloadAllowed = true; } - function attest(bytes32, bytes calldata) external {} + function attest(bytes32, bytes calldata) external { + attestCalled = true; + } - function allowPayload(bytes32, bytes32) external pure returns (bool) { + function allowPayload(bytes32, bytes32) external view returns (bool) { // digest has enough attestations - return true; + return isPayloadAllowed; } - function registerSwitchboard() external { + function setIsPayloadAllowed(bool isPayloadAllowed_) external { + isPayloadAllowed = isPayloadAllowed_; + } + + function registerSwitchboard() external returns (uint64) { switchboardId = socket__.registerSwitchboard(); + return switchboardId; } function processTrigger( @@ -39,13 +50,16 @@ contract MockFastSwitchboard is ISwitchboard { bytes32 triggerId_, bytes calldata payload_, bytes calldata overrides_ - ) external payable override {} + ) external payable override { + // Simple implementation that just accepts the trigger + // In a real switchboard, this would process the trigger + } function getTransmitter( address sender_, - bytes32 payloadId_, - bytes calldata transmitterSignature_ - ) external view returns (address) { + bytes32, + bytes calldata + ) external pure returns (address) { return sender_; } } diff --git a/test/mock/MockFeesManager.sol b/test/mock/MockFeesManager.sol new file mode 100644 index 00000000..a63bffea --- /dev/null +++ b/test/mock/MockFeesManager.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../contracts/protocol/interfaces/ISocketFeeManager.sol"; +import "../../contracts/utils/common/Structs.sol"; + +/** + * @title MockFeeManager + * @dev Mock fee manager for testing + */ +contract MockFeeManager is ISocketFeeManager { + bool public payAndCheckFeesCalled = false; + ExecuteParams public lastExecuteParams; + TransmissionParams public lastTransmissionParams; + + function payAndCheckFees( + ExecuteParams memory executeParams_, + TransmissionParams memory transmissionParams_ + ) external payable override { + payAndCheckFeesCalled = true; + lastExecuteParams = executeParams_; + lastTransmissionParams = transmissionParams_; + } + + function getMinSocketFees() external pure override returns (uint256) { + return 0.001 ether; + } + + function setSocketFees(uint256) external override { + // Mock implementation - do nothing + } + + function socketFees() external pure override returns (uint256) { + return 0.001 ether; + } + + function getLastTransmissionParams() external view returns (TransmissionParams memory) { + return lastTransmissionParams; + } + + function reset() external { + payAndCheckFeesCalled = false; + } +} diff --git a/test/mock/MockPlug.sol b/test/mock/MockPlug.sol new file mode 100644 index 00000000..13b9dc9f --- /dev/null +++ b/test/mock/MockPlug.sol @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../contracts/protocol/interfaces/IPlug.sol"; +import "../../contracts/protocol/interfaces/ISocket.sol"; + +/** + * @title MockPlug + * @dev Mock plug for testing + */ +contract MockPlug is IPlug { + ISocket public socket__; + bytes32 public appGatewayId; + uint64 public switchboardId; + bytes public overridesData = hex"1234"; + bool public initSocketCalled = false; + + error CallFailed(); + + function initSocket( + bytes32 appGatewayId_, + address socket_, + uint64 switchboardId_ + ) external override { + appGatewayId = appGatewayId_; + socket__ = ISocket(socket_); + initSocketCalled = true; + + socket__.connect(appGatewayId_, switchboardId_); + } + + function disconnect() external { + socket__.disconnect(); + } + + function overrides() external view override returns (bytes memory) { + return overridesData; + } + + function setOverrides(bytes calldata newOverrides) external { + overridesData = newOverrides; + } + + function setSocket(address newSocket) external { + socket__ = ISocket(newSocket); + } + + // Test helper function to trigger socket calls + function triggerSocket(bytes calldata data) external payable returns (bytes memory) { + (bool success, bytes memory result) = address(socket__).call{value: msg.value}(data); + require(success, "Socket call failed"); + return result; + } + + // Test helper functions for simulation testing + function processPayload(bytes calldata payload) external payable returns (bool) { + return payload.length > 0; + } + + function failingFunction() external pure { + revert("Intentional failure"); + } + + function returnLargeData() external pure returns (bytes memory) { + // Return 3KB of data to test maxCopyBytes truncation (maxCopyBytes is 2KB) + return new bytes(3072); + } + + // Function to call mockTarget + function callMockTarget(address target, bytes calldata data) external payable returns (bool) { + (bool success, ) = target.call{value: msg.value}(data); + if (!success) revert CallFailed(); + return success; + } +} + +/** + * @title MockTarget + * @dev Mock target contract for execution testing + */ +contract MockTarget { + uint256 public counter = 0; + bytes public lastCallData; + uint256 public lastValue; + bool public shouldRevert = false; + + event Called(address caller, uint256 value, bytes data); + + function increment() external payable { + if (shouldRevert) { + revert(); + } + counter++; + lastCallData = msg.data; + lastValue = msg.value; + emit Called(msg.sender, msg.value, msg.data); + } + + function setShouldRevert(bool _shouldRevert) external { + shouldRevert = _shouldRevert; + } + + function reset() external { + counter = 0; + lastCallData = ""; + lastValue = 0; + shouldRevert = false; + } + + // Fallback to handle any call + fallback() external payable { + if (shouldRevert) { + revert("Mock revert"); + } + lastCallData = msg.data; + lastValue = msg.value; + emit Called(msg.sender, msg.value, msg.data); + } + + receive() external payable { + if (shouldRevert) { + revert("Mock revert"); + } + lastValue = msg.value; + emit Called(msg.sender, msg.value, ""); + } +} diff --git a/test/protocol/Socket.t.sol b/test/protocol/Socket.t.sol new file mode 100644 index 00000000..1a71ec20 --- /dev/null +++ b/test/protocol/Socket.t.sol @@ -0,0 +1,952 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {Test} from "forge-std/Test.sol"; +import {console} from "forge-std/console.sol"; + +import {MockFastSwitchboard} from "../mock/MockFastSwitchboard.sol"; +import {MockPlug, MockTarget} from "../mock/MockPlug.sol"; +import {MockFeeManager} from "../mock/MockFeesManager.sol"; +import {SuperToken} from "../apps/app-gateways/super-token/SuperToken.sol"; +import {MockERC721} from "../mock/MockERC721.sol"; + +import "../../contracts/protocol/Socket.sol"; +import "../../contracts/protocol/SocketUtils.sol"; +import "../../contracts/utils/common/Errors.sol"; +import "../../contracts/utils/common/Constants.sol"; +import "../../contracts/utils/common/Structs.sol"; + +/** + * @title SocketTestWrapper + * @dev Wrapper contract to expose internal functions for testing + */ +contract SocketTestWrapper is Socket { + constructor( + uint32 chainSlug_, + address owner_, + string memory version_ + ) Socket(chainSlug_, owner_, version_) {} + + // Expose internal functions for testing + function createDigest( + address transmitter_, + bytes32 payloadId_, + bytes32 appGatewayId_, + ExecuteParams calldata executeParams_ + ) external view returns (bytes32) { + return _createDigest(transmitter_, payloadId_, appGatewayId_, executeParams_); + } + + function encodeTriggerId() external returns (bytes32) { + return _encodeTriggerId(); + } + + function executeInternal( + bytes32 payloadId_, + ExecuteParams calldata executeParams_, + TransmissionParams calldata transmissionParams_ + ) external payable returns (bool, bytes memory) { + return _execute(payloadId_, executeParams_, transmissionParams_); + } +} + +/** + * @title SocketTestBase + * @dev Base contract for Socket protocol unit tests + * Provides common setup, utilities, and mock contracts + */ +contract SocketTestBase is Test { + uint256 c = 1; + string constant VERSION = "1.0.0"; + address public socketOwner = address(uint160(c++)); + address public transmitter = address(uint160(c++)); + address public testUser = address(uint160(c++)); + + uint32 constant TEST_CHAIN_SLUG = 1; + bytes32 constant TEST_APP_GATEWAY_ID = keccak256("TEST_APP_GATEWAY"); + bytes constant TEST_PAYLOAD = hex"1234567890abcdef"; + bytes constant TEST_OVERRIDES = hex"abcdef"; + + // Contracts + Socket public socket; + MockFastSwitchboard public mockSwitchboard; + MockPlug public mockPlug; + MockFeeManager public mockFeeManager; + SuperToken public mockToken; + MockTarget public mockTarget; + SocketTestWrapper public socketWrapper; + + uint64 public switchboardId; + ExecuteParams public executeParams; + TransmissionParams public transmissionParams; + + event ExecutionSuccess(bytes32 payloadId, bool exceededMaxCopy, bytes returnData); + event ExecutionFailed(bytes32 payloadId, bool exceededMaxCopy, bytes returnData); + + function setUp() public virtual { + socket = new Socket(TEST_CHAIN_SLUG, socketOwner, VERSION); + mockSwitchboard = new MockFastSwitchboard(TEST_CHAIN_SLUG, address(socket), socketOwner); + mockPlug = new MockPlug(); + mockFeeManager = new MockFeeManager(); + mockToken = new SuperToken("Test Token", "TEST", 18, testUser, 1000000000000000000); + mockTarget = new MockTarget(); + socketWrapper = new SocketTestWrapper(TEST_CHAIN_SLUG, socketOwner, VERSION); + mockToken.setOwner(socketOwner); + + // Set up initial state + vm.startPrank(socketOwner); + socket.grantRole(GOVERNANCE_ROLE, socketOwner); + socket.grantRole(RESCUE_ROLE, socketOwner); + socket.grantRole(SWITCHBOARD_DISABLER_ROLE, socketOwner); + + socket.setSocketFeeManager(address(mockFeeManager)); + mockToken.setSocket(address(socket)); + vm.stopPrank(); + + switchboardId = mockSwitchboard.registerSwitchboard(); + mockPlug.initSocket(TEST_APP_GATEWAY_ID, address(socket), switchboardId); + + executeParams = _createExecuteParams(); + transmissionParams = _createTransmissionParams(); + + vm.deal(transmitter, 100 ether); + vm.deal(testUser, 100 ether); + } + + function _createExecuteParams() internal view returns (ExecuteParams memory) { + return + ExecuteParams({ + callType: WRITE, + payloadPointer: 1, + deadline: block.timestamp + 1 hours, + gasLimit: 100000, + value: 0, + prevBatchDigestHash: bytes32(0), + target: address(mockPlug), + payload: TEST_PAYLOAD, + extraData: bytes("") + }); + } + + function _createTransmissionParams() internal view returns (TransmissionParams memory) { + return + TransmissionParams({ + socketFees: 0, + refundAddress: testUser, + extraData: bytes(""), + transmitterProof: bytes("") + }); + } + + function createSignature( + bytes32 digest_, + uint256 privateKey_ + ) public pure returns (bytes memory sig) { + bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest_)); + (uint8 sigV, bytes32 sigR, bytes32 sigS) = vm.sign(privateKey_, digest); + sig = new bytes(65); + bytes1 v32 = bytes1(sigV); + assembly { + mstore(add(sig, 96), v32) + mstore(add(sig, 32), sigR) + mstore(add(sig, 64), sigS) + } + } +} + +/** + * @title SocketExecuteTest + * @dev Tests for Socket execute function + */ +contract SocketExecuteTest is SocketTestBase { + function testConstructorWithValidParameters() public view { + assertEq(socket.chainSlug(), TEST_CHAIN_SLUG, "Chain slug should match"); + assertEq(socket.owner(), socketOwner, "Owner should match"); + assertEq(socket.version(), keccak256(bytes(VERSION)), "Version should match"); + assertEq(socket.gasLimitBuffer(), 105, "Gas limit buffer should be 105"); + } + + function testExecuteDeadlinePassed() public { + executeParams.deadline = block.timestamp - 1; // Past deadline + vm.expectRevert(DeadlinePassed.selector); + socket.execute{value: 1 ether}(executeParams, transmissionParams); + } + + function testExecutePlugNotFound() public { + executeParams.target = address(0x999); // Non-existent plug + vm.expectRevert(PlugNotFound.selector); + socket.execute{value: 1 ether}(executeParams, transmissionParams); + } + + function testExecuteInsufficientValue() public { + executeParams.value = 1 ether; + transmissionParams.socketFees = 0.5 ether; + + vm.expectRevert(Socket.InsufficientMsgValue.selector); + socket.execute{value: 0.5 ether}(executeParams, transmissionParams); + } + + function testExecuteInvalidSwitchboardDisabled() public { + hoax(socketOwner); + socket.disableSwitchboard(switchboardId); + + vm.expectRevert(InvalidSwitchboard.selector); + socket.execute{value: 1 ether}(executeParams, transmissionParams); + } + + function testExecuteWithInvalidCallType() public { + executeParams.callType = bytes4(0x12345678); // Invalid call type + + vm.expectRevert(InvalidCallType.selector); + socket.execute{value: 1 ether}(executeParams, transmissionParams); + } + + function testExecuteRefundIfExecutionFails() public { + executeParams.target = address(mockPlug); + executeParams.value = 0.5 ether; + executeParams.payload = abi.encodeWithSelector( + mockPlug.callMockTarget.selector, + address(mockTarget), + abi.encodeWithSelector(mockTarget.increment.selector) + ); + + // Set up mock target to revert + mockTarget.setShouldRevert(true); + + uint256 userBalance = testUser.balance; + transmissionParams.refundAddress = testUser; + + hoax(transmitter); + (bool success, ) = socket.execute{value: 1 ether}(executeParams, transmissionParams); + assertFalse(success, "Execution should fail"); + + // Check that refund was sent + assertEq(testUser.balance, userBalance + 1 ether, "Refund should be sent to user"); + + // Set up mock target to revert + mockTarget.setShouldRevert(false); + userBalance = testUser.balance; + + hoax(transmitter); + (success, ) = socket.execute{value: 1 ether}(executeParams, transmissionParams); + assertTrue(success, "Execution should succeed"); + + // Check that refund was sent + assertEq(testUser.balance, userBalance, "Refund should not be sent to user"); + } + + function testExecuteWithValidParameters() public { + // Use mockPlug as target since it's connected to socket + executeParams.target = address(mockPlug); + executeParams.payload = abi.encodeWithSelector( + mockPlug.processPayload.selector, + TEST_PAYLOAD + ); + + bytes32 payloadId = createPayloadId( + executeParams.payloadPointer, + switchboardId, + TEST_CHAIN_SLUG + ); + + vm.expectEmit(true, true, true, true, address(socket)); + emit ExecutionSuccess(payloadId, false, bytes(abi.encode(true))); + (bool success, ) = socket.execute{value: 1 ether}(executeParams, transmissionParams); + assertTrue(success, "Execution should succeed"); + } + + function testExecuteWithPayloadAlreadyExecuted() public { + executeParams.payload = abi.encodeWithSelector( + mockPlug.processPayload.selector, + TEST_PAYLOAD + ); + + bytes32 payloadId = createPayloadId( + executeParams.payloadPointer, + switchboardId, + TEST_CHAIN_SLUG + ); + + vm.expectEmit(true, true, true, true, address(socket)); + emit ExecutionSuccess(payloadId, false, bytes(abi.encode(true))); + socket.execute{value: 1 ether}(executeParams, transmissionParams); + + vm.expectRevert( + abi.encodeWithSelector(Socket.PayloadAlreadyExecuted.selector, ExecutionStatus.Executed) + ); + socket.execute{value: 1 ether}(executeParams, transmissionParams); + } + + function testExecuteWithVerificationFailed() public { + // Override the allowPayload function to return false + mockSwitchboard.setIsPayloadAllowed(false); + + vm.expectRevert(Socket.VerificationFailed.selector); + socket.execute{value: 1 ether}(executeParams, transmissionParams); + } + + function testExecuteWithFailedExecution() public { + executeParams.target = address(mockPlug); + executeParams.payload = abi.encodeWithSelector( + mockPlug.callMockTarget.selector, + address(mockTarget), + abi.encodeWithSelector(mockTarget.increment.selector) + ); + + // Set up mock target to revert + mockTarget.setShouldRevert(true); + + bytes32 payloadId = createPayloadId( + executeParams.payloadPointer, + switchboardId, + TEST_CHAIN_SLUG + ); + + vm.expectEmit(true, true, true, true, address(socket)); + emit ExecutionFailed( + payloadId, + false, + abi.encodeWithSelector(MockPlug.CallFailed.selector) + ); + (bool success, ) = socket.execute{value: 1 ether}(executeParams, transmissionParams); + assertFalse(success, "Execution should fail"); + assertEq(mockTarget.counter(), 0, "Target should not be called"); + } + + function testExecuteWithExceededMaxCopyBytes() public { + // Set up mock target to return large data + executeParams.target = address(mockPlug); + executeParams.payload = abi.encodeWithSelector(mockPlug.returnLargeData.selector); + + (bool success, bytes memory returnData) = socket.execute{value: 1 ether}( + executeParams, + transmissionParams + ); + + // The return data should be truncated to maxCopyBytes (2048 bytes) + assertEq(returnData.length, 2048, "Return data should be exactly maxCopyBytes"); + assertLt(returnData.length, 3072, "Return data should be truncated"); + assertTrue(success, "Execution should succeed even with large return data"); + } + + function testExecutionRetryIfFailing() public { + executeParams.target = address(mockPlug); + executeParams.payload = abi.encodeWithSelector( + mockPlug.callMockTarget.selector, + address(mockTarget), + abi.encodeWithSelector(mockTarget.increment.selector) + ); + + bytes32 payloadId = createPayloadId( + executeParams.payloadPointer, + switchboardId, + TEST_CHAIN_SLUG + ); + + mockTarget.setShouldRevert(true); + vm.expectEmit(true, true, true, true, address(socket)); + emit ExecutionFailed( + payloadId, + false, + abi.encodeWithSelector(MockPlug.CallFailed.selector) + ); + (bool success, ) = socket.execute{value: 1 ether}(executeParams, transmissionParams); + assertFalse(success, "First execution should fail"); + + mockTarget.setShouldRevert(false); + vm.expectEmit(true, true, true, true, address(socket)); + emit ExecutionSuccess(payloadId, false, bytes(abi.encode(true))); + (success, ) = socket.execute{value: 1 ether}(executeParams, transmissionParams); + assertTrue(success, "Second execution should succeed"); + } + + function testGasUsageForExecute() public { + executeParams.target = address(mockPlug); + executeParams.payload = abi.encodeWithSelector( + mockPlug.callMockTarget.selector, + address(mockTarget), + abi.encodeWithSelector(mockTarget.increment.selector) + ); + + uint256 gasBefore = gasleft(); + socket.execute{value: 1 ether}(executeParams, transmissionParams); + uint256 gasUsed = gasBefore - gasleft(); + console.log("gasUsed", gasUsed); + } + + function testExecuteLowGasLimit() public { + // set high gas limit + executeParams.gasLimit = 10000000; + + vm.expectRevert(Socket.LowGasLimit.selector); + socket.execute{value: 1 ether, gas: 100000}(executeParams, transmissionParams); + } +} + +/** + * @title SocketTriggerTest + * @dev Tests for Socket triggerAppGateway function + */ +contract SocketTriggerTest is SocketTestBase { + function testTriggerAppGatewayPlugNotFound() public { + bytes memory triggerData = abi.encodeWithSelector( + mockPlug.processPayload.selector, + TEST_PAYLOAD + ); + + hoax(testUser); + vm.expectRevert(PlugNotFound.selector); + socket.triggerAppGateway{value: 1 ether}(triggerData); + } + + function testTriggerAppGatewayWithInvalidSwitchboard() public { + // Give mockPlug some funds + vm.deal(address(mockPlug), 10 ether); + + hoax(socketOwner); + socket.disableSwitchboard(switchboardId); + + bytes memory triggerData = abi.encodeWithSelector( + mockPlug.processPayload.selector, + TEST_PAYLOAD + ); + + vm.expectRevert(InvalidSwitchboard.selector); + hoax(address(mockPlug)); + socket.triggerAppGateway{value: 1 ether}(triggerData); + } + + function testGasUsageForTriggerAppGateway() public { + // Give mockPlug some funds + vm.deal(address(mockPlug), 10 ether); + + bytes memory triggerData = abi.encodeWithSelector( + mockPlug.processPayload.selector, + TEST_PAYLOAD + ); + + uint256 gasBefore = gasleft(); + hoax(address(mockPlug)); + socket.triggerAppGateway{value: 1 ether}(triggerData); + uint256 gasUsed = gasBefore - gasleft(); + + // Gas usage should be reasonable + console.log("gasUsed", gasUsed); + } +} + +/** + * @title SocketConnectDisconnectTest + * @dev Tests for Socket connect and disconnect functions + */ +contract SocketConnectDisconnectTest is SocketTestBase { + function testConnectWithInvalidSwitchboard() public { + vm.expectRevert(InvalidSwitchboard.selector); + mockPlug.initSocket(TEST_APP_GATEWAY_ID, address(socket), switchboardId + 1); + } + + function testConnectWithNewSwitchboard() public { + // Create a new switchboard + MockFastSwitchboard newSwitchboard = new MockFastSwitchboard( + TEST_CHAIN_SLUG, + address(socket), + socketOwner + ); + uint64 newSwitchboardId = newSwitchboard.registerSwitchboard(); + mockPlug.initSocket(TEST_APP_GATEWAY_ID, address(socket), newSwitchboardId); + + (bytes32 appGatewayId, uint64 switchboardId) = socket.getPlugConfig(address(mockPlug)); + assertEq(appGatewayId, TEST_APP_GATEWAY_ID, "App gateway ID should match"); + assertEq(switchboardId, newSwitchboardId, "Switchboard ID should match"); + } + + // Try to disconnect a plug that was never connected + function testDisconnectWithPlugNotConnected() public { + MockPlug newPlug = new MockPlug(); + newPlug.setSocket(address(socket)); + + vm.expectRevert(SocketConfig.PlugNotConnected.selector); + newPlug.disconnect(); + } +} + +/** + * @title SocketSwitchboardManagementTest + * @dev Tests for Socket switchboard management functions + */ +contract SocketSwitchboardManagementTest is SocketTestBase { + function testRegisterSwitchboardWithExistingSwitchboard() public { + assertEq(mockSwitchboard.switchboardId(), socket.switchboardIds(address(mockSwitchboard))); + + // Try to register the same switchboard again + vm.expectRevert(SocketConfig.SwitchboardExists.selector); + mockSwitchboard.registerSwitchboard(); + } + + function testDisableSwitchboardWithGovernanceRole() public { + hoax(socketOwner); + socket.disableSwitchboard(switchboardId); + + // Try to register the same switchboard again + vm.expectRevert(SocketConfig.SwitchboardExists.selector); + mockSwitchboard.registerSwitchboard(); + + assertEq( + uint256(socket.isValidSwitchboard(switchboardId)), + uint256(SwitchboardStatus.DISABLED), + "Switchboard should be disabled" + ); + } + + function testEnableSwitchboardWithGovernanceRole() public { + // First disable the switchboard + hoax(socketOwner); + socket.disableSwitchboard(switchboardId); + assertEq( + uint256(socket.isValidSwitchboard(switchboardId)), + uint256(SwitchboardStatus.DISABLED), + "Switchboard should be disabled" + ); + + // Then enable it + hoax(socketOwner); + socket.enableSwitchboard(switchboardId); + assertEq( + uint256(socket.isValidSwitchboard(switchboardId)), + uint256(SwitchboardStatus.REGISTERED), + "Switchboard should be enabled" + ); + } + + function testSwitchboardStatusValidation() public { + // Test initial status + assertEq( + uint256(socket.isValidSwitchboard(switchboardId)), + uint256(SwitchboardStatus.REGISTERED), + "Switchboard should be registered initially" + ); + + // Test disabled status + hoax(socketOwner); + socket.disableSwitchboard(switchboardId); + assertEq( + uint256(socket.isValidSwitchboard(switchboardId)), + uint256(SwitchboardStatus.DISABLED), + "Switchboard should be disabled" + ); + + // Test enabled status + hoax(socketOwner); + socket.enableSwitchboard(switchboardId); + + assertEq( + uint256(socket.isValidSwitchboard(switchboardId)), + uint256(SwitchboardStatus.REGISTERED), + "Switchboard should be enabled" + ); + } +} + +/** + * @title SocketSetterTest + * @dev Tests for Socket setter functions + */ +contract SocketSetterTest is SocketTestBase { + function testSetGasLimitBuffer() public { + uint256 newBuffer = 110; + + hoax(testUser); + vm.expectRevert(abi.encodeWithSelector(AccessControl.NoPermit.selector, GOVERNANCE_ROLE)); + socket.setGasLimitBuffer(newBuffer); + + hoax(socketOwner); + socket.setGasLimitBuffer(newBuffer); + + assertEq(socket.gasLimitBuffer(), newBuffer, "Gas limit buffer should be updated"); + } + + function testSetMaxCopyBytes() public { + uint16 newMaxCopyBytes = 4096; + + hoax(testUser); + vm.expectRevert(abi.encodeWithSelector(AccessControl.NoPermit.selector, GOVERNANCE_ROLE)); + socket.setMaxCopyBytes(newMaxCopyBytes); + + hoax(socketOwner); + socket.setMaxCopyBytes(newMaxCopyBytes); + assertEq(socket.maxCopyBytes(), newMaxCopyBytes, "Max copy bytes should be updated"); + } + + function testSetSocketFeeManager() public { + address newFeeManager = address(0x123); + + hoax(testUser); + vm.expectRevert(abi.encodeWithSelector(AccessControl.NoPermit.selector, GOVERNANCE_ROLE)); + socket.setSocketFeeManager(newFeeManager); + + hoax(socketOwner); + socket.setSocketFeeManager(newFeeManager); + assertEq( + address(socket.socketFeeManager()), + newFeeManager, + "Socket fee manager should be updated" + ); + } + + function testConfigurationValidation() public { + // Test initial configuration + assertEq(socket.gasLimitBuffer(), 105, "Initial gas limit buffer should be 105"); + assertEq(socket.maxCopyBytes(), 2048, "Initial max copy bytes should be 2048"); + assertEq( + address(socket.socketFeeManager()), + address(mockFeeManager), + "Initial fee manager should be mockFeeManager" + ); + + MockFeeManager newFeeManager = new MockFeeManager(); + // Test configuration updates + vm.startPrank(socketOwner); + socket.setGasLimitBuffer(120); + socket.setMaxCopyBytes(4096); + socket.setSocketFeeManager(address(newFeeManager)); + vm.stopPrank(); + + assertEq(socket.gasLimitBuffer(), 120, "Gas limit buffer should be updated"); + assertEq(socket.maxCopyBytes(), 4096, "Max copy bytes should be updated"); + assertEq( + address(socket.socketFeeManager()), + address(newFeeManager), + "Fee manager should be updated" + ); + } +} + +/** + * @title SocketDigestTest + * @dev Tests for digest creation functionality + */ +contract SocketDigestTest is SocketTestBase { + function testCreateDigestWithBasicPayload() public view { + ExecuteParams memory params = ExecuteParams({ + target: address(mockTarget), + value: 1 ether, + gasLimit: 100000, + deadline: block.timestamp + 3600, + callType: WRITE, + payload: TEST_PAYLOAD, + payloadPointer: uint160(1), + prevBatchDigestHash: bytes32(uint256(0)), + extraData: bytes("") + }); + + bytes32 digest = socketWrapper.createDigest( + transmitter, + bytes32(uint256(0x123)), + TEST_APP_GATEWAY_ID, + params + ); + + assertTrue(digest != bytes32(0), "Digest should not be zero"); + } + + function testCreateDigestWithLargePayload() public view { + bytes memory largePayload = new bytes(1000); + for (uint256 i = 0; i < 1000; i++) { + largePayload[i] = bytes1(uint8(i % 256)); + } + + ExecuteParams memory params = ExecuteParams({ + target: address(mockTarget), + value: 2 ether, + gasLimit: 200000, + deadline: block.timestamp + 7200, + callType: WRITE, + payload: largePayload, + payloadPointer: uint160(1), + prevBatchDigestHash: bytes32(uint256(0)), + extraData: bytes("") + }); + + bytes32 digest = socketWrapper.createDigest( + transmitter, + bytes32(uint256(0xdef)), + TEST_APP_GATEWAY_ID, + params + ); + + assertTrue(digest != bytes32(0), "Digest should not be zero"); + } + + function testCreateDigestWithDifferentTransmitters() public view { + ExecuteParams memory params = ExecuteParams({ + target: address(mockTarget), + value: 1 ether, + gasLimit: 100000, + deadline: block.timestamp + 3600, + callType: WRITE, + payload: TEST_PAYLOAD, + payloadPointer: uint160(1), + prevBatchDigestHash: bytes32(0), + extraData: bytes("") + }); + + bytes32 digest1 = socketWrapper.createDigest( + transmitter, + bytes32(uint256(0x123)), + TEST_APP_GATEWAY_ID, + params + ); + + bytes32 digest2 = socketWrapper.createDigest( + address(uint160(0x456)), + bytes32(uint256(0x123)), + TEST_APP_GATEWAY_ID, + params + ); + + assertTrue(digest1 != digest2, "Digests should be different for different transmitters"); + } + + function testCreateDigestWithDifferentPayloads() public view { + ExecuteParams memory params1 = ExecuteParams({ + target: address(mockTarget), + value: 1 ether, + gasLimit: 100000, + deadline: block.timestamp + 3600, + callType: WRITE, + payload: TEST_PAYLOAD, + payloadPointer: uint160(1), + prevBatchDigestHash: bytes32(0), + extraData: bytes("") + }); + + ExecuteParams memory params2 = ExecuteParams({ + target: address(mockTarget), + value: 1 ether, + gasLimit: 100000, + deadline: block.timestamp + 3600, + callType: WRITE, + payload: hex"abcdef", + payloadPointer: uint160(1), + prevBatchDigestHash: bytes32(0), + extraData: bytes("") + }); + + bytes32 digest1 = socketWrapper.createDigest( + transmitter, + bytes32(uint256(0x123)), + TEST_APP_GATEWAY_ID, + params1 + ); + + bytes32 digest2 = socketWrapper.createDigest( + transmitter, + bytes32(uint256(0x123)), + TEST_APP_GATEWAY_ID, + params2 + ); + + assertTrue(digest1 != digest2, "Digests should be different for different payloads"); + } +} + +/** + * @title SocketTriggerIdTest + * @dev Tests for trigger ID encoding and uniqueness + */ +contract SocketTriggerIdTest is SocketTestBase { + function testEncodeTriggerIdIncrementsCounter() public { + bytes32 triggerId1 = socketWrapper.encodeTriggerId(); + bytes32 triggerId2 = socketWrapper.encodeTriggerId(); + bytes32 triggerId3 = socketWrapper.encodeTriggerId(); + + assertTrue(triggerId1 != triggerId2, "Trigger IDs should be different"); + assertTrue(triggerId2 != triggerId3, "Trigger IDs should be different"); + assertTrue(triggerId1 != triggerId3, "Trigger IDs should be different"); + } + + function testTriggerIdUniqueness() public { + bytes32[] memory triggerIds = new bytes32[](100); + + for (uint256 i = 0; i < 100; i++) { + triggerIds[i] = socketWrapper.encodeTriggerId(); + } + + // Check for uniqueness + for (uint256 i = 0; i < 100; i++) { + for (uint256 j = i + 1; j < 100; j++) { + assertTrue(triggerIds[i] != triggerIds[j], "Trigger IDs should be unique"); + assertEq( + uint32(uint256(triggerIds[i]) >> 224), + TEST_CHAIN_SLUG, + "Chain slug should match" + ); + assertEq( + address(uint160(uint256(triggerIds[i]) >> 64)), + address(socketWrapper), + "Socket address should match" + ); + assertEq(uint64(uint256(triggerIds[i])), i, "Counter should increment"); + } + } + } + + function testTriggerIdFormatFuzz(uint64 counter) public { + vm.assume(counter < type(uint64).max - 1000); + + // Set the counter to a specific value + uint256 counterSlot = uint256(57); + vm.store(address(socketWrapper), bytes32(counterSlot), bytes32(uint256(counter))); + + bytes32 triggerId = socketWrapper.encodeTriggerId(); + uint32 chainSlugFromId = uint32(uint256(triggerId) >> 224); + address socketAddressFromId = address(uint160(uint256(triggerId) >> 64)); + uint64 counterFromId = uint64(uint256(triggerId)); + + assertEq(chainSlugFromId, TEST_CHAIN_SLUG, "Chain slug should match"); + assertEq(socketAddressFromId, address(socketWrapper), "Socket address should match"); + assertEq(counterFromId, counter, "Counter should match"); + } +} + +/** + * @title SocketSimulationTest + * @dev Tests for simulation functionality + */ +contract SocketSimulationTest is SocketTestBase { + function testSimulationModifier() public { + SocketUtils.SimulateParams[] memory params = new SocketUtils.SimulateParams[](1); + params[0] = SocketUtils.SimulateParams({ + target: address(mockTarget), + value: 1 ether, + gasLimit: 100000, + payload: TEST_PAYLOAD + }); + + // Should revert when called by non-off-chain caller + vm.expectRevert(SocketUtils.OnlyOffChain.selector); + socket.simulate(params); + } +} + +/** + * @title SocketRescueTest + * @dev Tests for rescue functionality + */ +contract SocketRescueTest is SocketTestBase { + function testRescueFunds() public { + // Send some ETH to the socket + vm.deal(address(socket), 10 ether); + uint256 balanceBefore = testUser.balance; + + hoax(socketOwner); + socket.rescueFunds(ETH_ADDRESS, testUser, 5 ether); + + uint256 balanceAfter = testUser.balance; + assertEq(balanceAfter - balanceBefore, 5 ether, "User should receive rescued ETH"); + } + + function testRescueFundsWithNonRescueRole() public { + vm.deal(address(socket), 10 ether); + + hoax(testUser); + vm.expectRevert(abi.encodeWithSelector(AccessControl.NoPermit.selector, RESCUE_ROLE)); + socket.rescueFunds(address(0), testUser, 5 ether); + } + + function testRescueTokenFunds() public { + // Transfer some tokens to the socket + hoax(address(socket)); + mockToken.mint(address(socket), 1000); + uint256 balanceBefore = mockToken.balanceOf(testUser); + + hoax(socketOwner); + socket.rescueFunds(address(mockToken), testUser, 500); + + uint256 balanceAfter = mockToken.balanceOf(testUser); + assertEq(balanceAfter - balanceBefore, 500, "User should receive rescued tokens"); + } + + function testSendingEthToSocket() public { + vm.expectRevert("Socket does not accept ETH"); + (bool success, ) = address(socket).call{value: 1 ether}(""); + } + + function testRescueNFT() public { + // Deploy a mock ERC721 NFT and mint one to this test contract + MockERC721 mockNFT = new MockERC721(); + uint256 tokenId = 1; + mockNFT.mint(address(socket), tokenId); + assertEq(mockNFT.ownerOf(tokenId), address(socket), "Socket should own the NFT"); + + hoax(socketOwner); + socket.rescueFunds(address(mockNFT), testUser, tokenId); + + // Check that testUser received the NFT + assertEq(mockNFT.ownerOf(tokenId), testUser, "User should receive rescued NFT"); + } +} + +/** + * @title SocketFeeManagerTest + * @dev Tests for fee manager functionality + */ +contract SocketFeeManagerTest is SocketTestBase { + function testFeeCollectedIfExecutionSuccess() public { + // Set up execution parameters with fees + executeParams.gasLimit = 100000; + transmissionParams.socketFees = 0.1 ether; + executeParams.target = address(mockPlug); + executeParams.payload = abi.encodeWithSelector( + mockPlug.processPayload.selector, + TEST_PAYLOAD + ); + + // Execute with fees + socket.execute{value: 1.1 ether}(executeParams, transmissionParams); + + // Check that fees were collected + assertEq(address(mockFeeManager).balance, 0.1 ether, "Fee manager should receive fees"); + } + + function testGasUsage() public { + executeParams.gasLimit = 100000; + transmissionParams.socketFees = 0.1 ether; + + // mockSwitchboard.setTransmitter(transmitter); + + uint256 gasBefore = gasleft(); + + vm.deal(testUser, 2 ether); + hoax(testUser); + socket.execute{value: 1.1 ether}(executeParams, transmissionParams); + + uint256 gasUsed = gasBefore - gasleft(); + console.log("Gas used for execution with fees:", gasUsed); + + assertTrue(gasUsed > 0, "Gas should be used"); + } + + function testFeeManagerNotSet() public { + // Remove fee manager + hoax(socketOwner); + socket.setSocketFeeManager(address(0)); + + executeParams.gasLimit = 100000; + transmissionParams.socketFees = 0.1 ether; + + // mockSwitchboard.setTransmitter(transmitter); + + // Should still execute successfully without fee manager + vm.deal(testUser, 2 ether); + hoax(testUser); + socket.execute{value: 1.1 ether}(executeParams, transmissionParams); + + // No fees should be collected + assertEq( + address(mockFeeManager).balance, + 0, + "No fees should be collected when fee manager is not set" + ); + } +} diff --git a/test/SocketFeeManager.t.sol b/test/protocol/SocketFeeManager.t.sol similarity index 96% rename from test/SocketFeeManager.t.sol rename to test/protocol/SocketFeeManager.t.sol index e696b95e..19db0329 100644 --- a/test/SocketFeeManager.t.sol +++ b/test/protocol/SocketFeeManager.t.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {SocketFeeManager} from "../contracts/protocol/SocketFeeManager.sol"; -import {MockFastSwitchboard} from "./mock/MockFastSwitchboard.sol"; -import "./SetupTest.t.sol"; -import "./apps/Counter.t.sol"; +import {SocketFeeManager} from "../../contracts/protocol/SocketFeeManager.sol"; +import {MockFastSwitchboard} from "../mock/MockFastSwitchboard.sol"; +import "../SetupTest.t.sol"; +import "../apps/Counter.t.sol"; contract SocketFeeManagerTest is AppGatewayBaseSetup { Counter public counter; diff --git a/test/TriggerTest.t.sol b/test/protocol/TriggerTest.t.sol similarity index 95% rename from test/TriggerTest.t.sol rename to test/protocol/TriggerTest.t.sol index eb4c0ea0..24f475e7 100644 --- a/test/TriggerTest.t.sol +++ b/test/protocol/TriggerTest.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {CounterAppGateway} from "./apps/Counter.t.sol"; -import {Counter} from "./apps/Counter.t.sol"; -import "./SetupTest.t.sol"; +import {CounterAppGateway} from "../apps/Counter.t.sol"; +import {Counter} from "../apps/Counter.t.sol"; +import "../SetupTest.t.sol"; contract TriggerTest is AppGatewayBaseSetup { uint256 constant feesAmount = 0.01 ether; diff --git a/test/protocol/switchboards/FastSwitchboardTest.t.sol b/test/protocol/switchboards/FastSwitchboardTest.t.sol new file mode 100644 index 00000000..f27ab1fb --- /dev/null +++ b/test/protocol/switchboards/FastSwitchboardTest.t.sol @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../SetupTest.t.sol"; +import {CounterAppGateway} from "../../apps/app-gateways/counter/CounterAppGateway.sol"; +import {FastSwitchboard} from "../../../contracts/protocol/switchboard/FastSwitchboard.sol"; +import {WATCHER_ROLE} from "../../../contracts/utils/common/AccessRoles.sol"; +import {toBytes32Format} from "../../../contracts/utils/common/Converters.sol"; + +contract FastSwitchboardExtended is FastSwitchboard { + event TriggerProcessed( + address indexed plug, + bytes32 indexed triggerId, + bytes payload, + bytes overrides + ); + + constructor( + uint32 chainSlug_, + ISocket socket_, + address owner_ + ) FastSwitchboard(chainSlug_, socket_, owner_) {} + + function processTrigger( + address plug_, + bytes32 triggerId_, + bytes calldata payload_, + bytes calldata overrides_ + ) external payable override { + emit TriggerProcessed(plug_, triggerId_, payload_, overrides_); + } +} + +contract FastSwitchboardTest is AppGatewayBaseSetup { + CounterAppGateway public appGateway; + FastSwitchboard public fastSwitchboard; + bytes32 public testDigest = keccak256(abi.encodePacked("test payload")); + bytes32 public sigDigest; + bytes public validProof; + + function setUp() public { + _deploy(); + appGateway = new CounterAppGateway(address(addressResolver), writeFees); + fastSwitchboard = getSocketConfig(arbChainSlug).switchboard; + + // Create valid proof from watcher + sigDigest = keccak256( + abi.encodePacked(toBytes32Format(address(fastSwitchboard)), arbChainSlug, testDigest) + ); + validProof = createSignature(sigDigest, watcherPrivateKey); + } + + function testAttestWithValidWatcherSignature() public { + assertTrue( + fastSwitchboard.hasRole(WATCHER_ROLE, watcherEOA), + "Watcher should have WATCHER_ROLE" + ); + + vm.expectEmit(true, true, true, false); + emit FastSwitchboard.Attested(testDigest, watcherEOA); + fastSwitchboard.attest(testDigest, validProof); + + assertTrue(fastSwitchboard.isAttested(testDigest), "Payload should be attested"); + } + + function testAttestWithAlreadyAttestedPayload() public { + fastSwitchboard.attest(testDigest, validProof); + assertTrue(fastSwitchboard.isAttested(testDigest), "Payload should be attested"); + + vm.expectRevert(FastSwitchboard.AlreadyAttested.selector); + fastSwitchboard.attest(testDigest, validProof); + } + + function testAllowPayloadReturnsCorrectStatus() public { + assertFalse( + fastSwitchboard.allowPayload(testDigest, bytes32(0)), + "Payload should not be allowed initially" + ); + + fastSwitchboard.attest(testDigest, validProof); + assertTrue( + fastSwitchboard.allowPayload(testDigest, bytes32(0)), + "Payload should be allowed after attestation" + ); + } + + function testAttestWithNonWatcherAddress() public { + // Create proof from a non-watcher address + uint256 nonWatcherPrivateKey = 0x1234567890123456789012345678901234567890123456789012345678901234; + address nonWatcherAddress = vm.addr(nonWatcherPrivateKey); + bytes memory nonWatcherProof = createSignature(sigDigest, nonWatcherPrivateKey); + + // Verify non-watcher doesn't have WATCHER_ROLE + assertFalse( + fastSwitchboard.hasRole(WATCHER_ROLE, nonWatcherAddress), + "Non-watcher should not have WATCHER_ROLE" + ); + + // Try to attest with non-watcher proof + vm.expectRevert(FastSwitchboard.WatcherNotFound.selector); + fastSwitchboard.attest(testDigest, nonWatcherProof); + } + + function testMultipleAttestationsForDifferentDigests() public { + bytes32 digest1 = keccak256(abi.encodePacked("payload 1")); + bytes32 digest2 = keccak256(abi.encodePacked("payload 2")); + + // Create proofs for both digests + bytes32 sigDigest1 = keccak256( + abi.encodePacked(toBytes32Format(address(fastSwitchboard)), arbChainSlug, digest1) + ); + bytes32 sigDigest2 = keccak256( + abi.encodePacked(toBytes32Format(address(fastSwitchboard)), arbChainSlug, digest2) + ); + + bytes memory proof1 = createSignature(sigDigest1, watcherPrivateKey); + bytes memory proof2 = createSignature(sigDigest2, watcherPrivateKey); + + // Attest both payloads + fastSwitchboard.attest(digest1, proof1); + fastSwitchboard.attest(digest2, proof2); + + // Verify both are attested + assertTrue(fastSwitchboard.isAttested(digest1), "Digest1 should be attested"); + assertTrue(fastSwitchboard.isAttested(digest2), "Digest2 should be attested"); + + // Verify both are allowed + assertTrue(fastSwitchboard.allowPayload(digest1, bytes32(0)), "Digest1 should be allowed"); + assertTrue(fastSwitchboard.allowPayload(digest2, bytes32(0)), "Digest2 should be allowed"); + } + + function testProcessTriggerDoesNothing() public { + FastSwitchboardExtended fastSwitchboardExtended = new FastSwitchboardExtended( + arbChainSlug, + getSocketConfig(arbChainSlug).socket, + socketOwner + ); + + vm.expectEmit(true, true, true, true); + emit FastSwitchboardExtended.TriggerProcessed( + address(0x123), + bytes32(uint256(0x456)), + bytes("test payload"), + bytes("test overrides") + ); + fastSwitchboardExtended.processTrigger( + address(0x123), + bytes32(uint256(0x456)), + bytes("test payload"), + bytes("test overrides") + ); + } + + function testFuzzLargeProofs(bytes32 digest, uint256 proofSize) public { + vm.assume(digest != bytes32(0)); + vm.assume(proofSize >= 65 && proofSize <= 1000); // Reasonable proof sizes + + // Create a large proof + bytes memory largeProof = new bytes(proofSize); + for (uint256 i = 0; i < proofSize; i++) { + largeProof[i] = bytes1(uint8(i % 256)); + } + + vm.expectRevert(InvalidSignature.selector); + fastSwitchboard.attest(digest, largeProof); + } + + function testFuzzAttestWithRandomDigests(bytes32 digest) public { + // Skip zero digest to avoid edge cases + vm.assume(digest != bytes32(0)); + + // Create valid proof for the digest + sigDigest = keccak256( + abi.encodePacked(toBytes32Format(address(fastSwitchboard)), arbChainSlug, digest) + ); + bytes memory proof = createSignature(sigDigest, watcherPrivateKey); + + // Expect success and event emission + vm.expectEmit(true, true, true, false); + emit FastSwitchboard.Attested(digest, watcherEOA); + + fastSwitchboard.attest(digest, proof); + + // Verify attestation + assertTrue(fastSwitchboard.isAttested(digest), "Digest should be attested"); + assertTrue(fastSwitchboard.allowPayload(digest, bytes32(0)), "Payload should be allowed"); + } +} diff --git a/test/MessageSwitchboardTest.t.sol b/test/protocol/switchboards/MessageSwitchboardTest.t copy.sol similarity index 96% rename from test/MessageSwitchboardTest.t.sol rename to test/protocol/switchboards/MessageSwitchboardTest.t copy.sol index 36fe93b0..73398fcd 100644 --- a/test/MessageSwitchboardTest.t.sol +++ b/test/protocol/switchboards/MessageSwitchboardTest.t copy.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "./SetupTest.t.sol"; -import {CounterPlug} from "./apps/app-gateways/counter/MessageCounter.sol"; +import "../../SetupTest.t.sol"; +import {CounterPlug} from "../../apps/app-gateways/counter/MessageCounter.sol"; contract MessageSwitchboardTest is MessageSwitchboardSetup { CounterPlug public arbPlug; diff --git a/tsconfig.json b/tsconfig.json index 7356b140..5afc3d90 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,17 +12,17 @@ "sourceMap": true, "declaration": true, - "alwaysStrict": true, + "alwaysStrict": false, "forceConsistentCasingInFileNames": true, "removeComments": true, - "noImplicitAny": true, - "strictNullChecks": true, - "strictFunctionTypes": true, + "noImplicitAny": false, + "strictNullChecks": false, + "strictFunctionTypes": false, "noImplicitThis": true, "noUnusedLocals": false, "noUnusedParameters": false, "noImplicitReturns": true, - "strict": true, + "strict": false, "noFallthroughCasesInSwitch": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, diff --git a/yarn.lock b/yarn.lock index a9f749d2..3f01d8df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1428,10 +1428,10 @@ mcl-wasm "^0.7.1" rustbn.js "~0.2.0" -"@nomicfoundation/hardhat-verify@^2.0.12": - version "2.0.13" - resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.13.tgz#41691adc32e01dc5cf6b725615f64958fba2100b" - integrity sha512-i57GX1sC0kYGyRVnbQrjjyBTpWTKgrvKC+jH8CMKV6gHp959Upb8lKaZ58WRHIU0espkulTxLnacYeUDirwJ2g== +"@nomicfoundation/hardhat-verify@^2.0.14": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.1.1.tgz#0af5fc4228df860062865fcafb4a01bc0b89f8a3" + integrity sha512-K1plXIS42xSHDJZRkrE2TZikqxp9T4y6jUMUNI/imLgN5uCcEQokmfU0DlyP9zzHncYK92HlT5IWP35UVCLrPw== dependencies: "@ethersproject/abi" "^5.1.2" "@ethersproject/address" "^5.0.2" @@ -2222,6 +2222,11 @@ dependencies: "@types/node" "*" +"@types/uuid@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-10.0.0.tgz#e9c07fe50da0f53dc24970cca94d619ff03f6f6d" + integrity sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ== + "@types/validator@^13.7.17": version "13.12.2" resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.12.2.tgz#760329e756e18a4aab82fc502b51ebdfebbe49f5"