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 9f8047f5..2acd69a3 100644 --- a/Errors.md +++ b/Errors.md @@ -16,13 +16,6 @@ | `PromiseRevertFailed()` | `0x0175b9de` | | `NotLatestPromise()` | `0x39ca95d3` | -## evmx/helpers/ForwarderSolana.sol - -| Error | Signature | -|-------|-----------| -| `InvalidSolanaChainSlug()` | `0xe37803ab` | -| `AddressResolverNotSet()` | `0x6d55276d` | - ## evmx/plugs/ContractFactoryPlug.sol | Error | Signature | @@ -39,7 +32,6 @@ | `InvalidDepositAmount()` | `0xfe9ba5cd` | | `TokenNotWhitelisted(address)` | `0xea3bff2e` | - ## evmx/watcher/RequestHandler.sol | Error | Signature | @@ -57,10 +49,10 @@ ## protocol/SocketConfig.sol -| Error | Signature | -| ------------------------------- | ------------ | -| `SwitchboardExists()` | `0x2dff8555` | -| `SwitchboardExistsOrDisabled()` | `0x1c7d2487` | +| Error | Signature | +| --------------------- | ------------ | +| `SwitchboardExists()` | `0x2dff8555` | +| `PlugNotConnected()` | `0x411d0255` | ## protocol/SocketFeeManager.sol @@ -76,6 +68,23 @@ | `OnlyOffChain()` | `0x9cbfe066` | | `SimulationFailed()` | `0x2fbab3ac` | +## protocol/base/MessagePlugBase.sol + +| Error | Signature | +| ---------------- | ------------ | +| `NotSupported()` | `0xa0387940` | + +## protocol/switchboard/CCTPSwitchboard.sol + +| Error | Signature | +| ------------------------------- | ------------ | +| `RemoteExecutionNotFound()` | `0xbd506972` | +| `PrevBatchDigestHashMismatch()` | `0xc9864e9d` | +| `NotAttested()` | `0x99efb890` | +| `NotExecuted()` | `0xec84b1da` | +| `InvalidSender()` | `0xddb5de5e` | +| `OnlyMessageTransmitter()` | `0x935ac89c` | + ## protocol/switchboard/FastSwitchboard.sol | Error | Signature | @@ -83,6 +92,16 @@ | `AlreadyAttested()` | `0x35d90805` | | `WatcherNotFound()` | `0xa278e4ad` | +## protocol/switchboard/MessageSwitchboard.sol + +| Error | Signature | +| ----------------------------- | ------------ | +| `AlreadyAttested()` | `0x35d90805` | +| `WatcherNotFound()` | `0xa278e4ad` | +| `SiblingNotFound()` | `0xb3b47851` | +| `InvalidTargetVerification()` | `0xe9377a19` | +| `InvalidMsgValue()` | `0x1841b4e1` | + ## utils/AccessControl.sol | Error | Signature | @@ -154,3 +173,6 @@ | `InvalidData()` | `0x5cb045db` | | `InvalidSignature()` | `0x8baa579f` | | `DeadlinePassed()` | `0x70f65caa` | +| `OnlyRequestHandlerAllowed()` | `0x5c1aa683` | +| `OnlyPromiseResolverAllowed()` | `0x2392c25e` | +| `InvalidReceiver()` | `0x1e4ec46b` | diff --git a/EventTopics.md b/EventTopics.md index c860edeb..9c39c004 100644 --- a/EventTopics.md +++ b/EventTopics.md @@ -2,275 +2,335 @@ ## AuctionManager -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `AuctionEndDelaySecondsSet` | `(auctionEndDelaySeconds: uint256)` | `0xf38f0d9dc8459cf5426728c250d115196a4c065ebc1a6c29da24764a8c0da722` | -| `AuctionEnded` | `(requestCount: uint40, winningBid: tuple)` | `0xede4ec1efc469fac10dcb4930f70be4cd21f3700ed61c91967c19a7cd7c0d86e` | -| `AuctionRestarted` | `(requestCount: uint40)` | `0x071867b21946ec4655665f0d4515d3757a5a52f144c762ecfdfb11e1da542b82` | -| `AuctionStarted` | `(requestCount: uint40)` | `0xcd040613cf8ef0cfcaa3af0d711783e827a275fc647c116b74595bf17cb9364f` | -| `BidPlaced` | `(requestCount: uint40, bid: tuple)` | `0x7f79485e4c9aeea5d4899bc6f7c63b22ac1f4c01d2d28c801e94732fee657b5d` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `MaxReAuctionCountSet` | `(maxReAuctionCount: uint256)` | `0x2f6fadde7ab8ab83d21ab10c3bc09dde179f8696d47c4176581facf0c6f96bbf` | -| `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` | +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------- | -------------------------------------------------------------------- | +| `AuctionEndDelaySecondsSet` | `(auctionEndDelaySeconds: uint256)` | `0xf38f0d9dc8459cf5426728c250d115196a4c065ebc1a6c29da24764a8c0da722` | +| `AuctionEnded` | `(requestCount: uint40, winningBid: tuple)` | `0xede4ec1efc469fac10dcb4930f70be4cd21f3700ed61c91967c19a7cd7c0d86e` | +| `AuctionRestarted` | `(requestCount: uint40)` | `0x071867b21946ec4655665f0d4515d3757a5a52f144c762ecfdfb11e1da542b82` | +| `AuctionStarted` | `(requestCount: uint40)` | `0xcd040613cf8ef0cfcaa3af0d711783e827a275fc647c116b74595bf17cb9364f` | +| `BidPlaced` | `(requestCount: uint40, bid: tuple)` | `0x7f79485e4c9aeea5d4899bc6f7c63b22ac1f4c01d2d28c801e94732fee657b5d` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `MaxReAuctionCountSet` | `(maxReAuctionCount: uint256)` | `0x2f6fadde7ab8ab83d21ab10c3bc09dde179f8696d47c4176581facf0c6f96bbf` | +| `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` | ## Socket +| Event | Arguments | Topic | +| ---------------------------- | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `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` | +| `PlugConnected` | `(plug: address, appGatewayId: bytes32, switchboardId: uint64)` | `0xb2a45daaee4fc6ced936700efec176684095e7b77c4cb1419b578ecc6f2ebce6` | +| `PlugDisconnected` | `(plug: address)` | `0x474a53f61630e976f47075b6029ba8d55d0563151bdb9222c5dbdc88f7af6f51` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `SocketFeeManagerUpdated` | `(oldSocketFeeManager: address, newSocketFeeManager: address)` | `0xdcb02e10d5220346a4638aa2826eaab1897306623bc40a427049e4ebd12255b4` | +| `SwitchboardAdded` | `(switchboard: address, switchboardId: uint64)` | `0x2f945cce0a82eacc4841d996b3d0429e01c7c603f3f900253d21b428c760dce1` | +| `SwitchboardDisabled` | `(switchboardId: uint64)` | `0x9ab25a32266417ee52a390121ebca0463374e76cecb25596a0f68e9d96a9e0ff` | +| `SwitchboardEnabled` | `(switchboardId: uint64)` | `0xa1cea6c3e73c288db1f2e2d7f04d9fd5f12463c30019b4ed354ba8bc7bc26f28` | + +## IFastSwitchboard + | Event | Arguments | Topic | | ----- | --------- | ----- | -| `AppGatewayCallRequested` | `(triggerId: bytes32, appGatewayId: bytes32, switchboard: bytes32, plug: bytes32, overrides: bytes, payload: bytes)` | `0xf83cee1d13047d8a1785495ac352da7c9ac5725641f76506899def19750c7696` | -| `ExecutionFailed` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x385334bc68a32c4d164625189adc7633e6074eb1b837fb4d11d768245151e4ce` | -| `ExecutionSuccess` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x324d63a433b21a12b90e79cd2ba736b2a5238be6165e03b750fa4a7d5193d5d9` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PlugConnected` | `(plug: address, appGatewayId: bytes32, switchboard: address)` | `0x90c5924e27cfb6e3a688e729083681f30494ae2615ae14aac3bc807a0c436a88` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -| `SocketFeeManagerUpdated` | `(oldSocketFeeManager: address, newSocketFeeManager: address)` | `0xdcb02e10d5220346a4638aa2826eaab1897306623bc40a427049e4ebd12255b4` | -| `SwitchboardAdded` | `(switchboard: address)` | `0x1595852923edfbbf906f09fc8523e4cfb022a194773c4d1509446b614146ee88` | -| `SwitchboardDisabled` | `(switchboard: address)` | `0x1b4ee41596b4e754e5665f01ed6122b356f7b36ea0a02030804fac7fa0fdddfc` | -| `SwitchboardEnabled` | `(switchboard: address)` | `0x6909a9974e3eec619bc479ba882d30a5ef1219b72ab1ce6a354516e91be317b8` | ## SocketBatcher -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## SocketFeeManager -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `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` | -| `SocketFeesUpdated` | `(oldFees: uint256, newFees: uint256)` | `0xcbd4d756fb6198bbcc2e4013cce929f504ad46e9d97c543ef9a8dfea3e407053` | +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `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` | +| `SocketFeesUpdated` | `(oldFees: uint256, newFees: uint256)` | `0xcbd4d756fb6198bbcc2e4013cce929f504ad46e9d97c543ef9a8dfea3e407053` | ## FeesManager -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `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` | -| `CreditsWrapped` | `(consumeFrom: address, amount: uint256)` | `0x40246503613721eb4acf4020c6c56b6a16e5d08713316db0bea5210e8819c592` | -| `Deposited` | `(chainSlug: uint32, token: address, depositTo: address, creditAmount: uint256, nativeAmount: uint256)` | `0x72aedd284699bbd7a987e6942b824cfd6c627e354cb5a0760ac5768acd473f4a` | -| `FeesPlugSet` | `(chainSlug: uint32, feesPlug: bytes32)` | `0x677a00737c8099aa9e6c554104ca7941deb59125335cfb3d0d9f604f178db59c` | -| `FeesPoolSet` | `(feesPool: address)` | `0xd07af3fd70b48ab3c077a8d45c3a288498d905d0e3d1e65bc171f6c2e890d8ef` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `WithdrawFailed` | `(payloadId: bytes32)` | `0xea147eb2109f71b4bda9e57528ba08b84821087a31cb43a7851dc6ff743d9be7` | +| Event | Arguments | Topic | +| ----------------------------- | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `Approval` | `(owner: address, spender: address, amount: uint256)` | `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925` | +| `CreditsBlocked` | `(requestCount: uint40, consumeFrom: address, amount: uint256)` | `0xf037c15aef41440aa823cf1fdeaea332105d8b23d52557f6670189b5d76f1eed` | +| `CreditsUnblocked` | `(requestCount: uint40, consumeFrom: address)` | `0x45db29ef2701319155cac058aa2f56ce1f73e0e238161d3db9f8c9a47655210d` | +| `CreditsUnblockedAndAssigned` | `(requestCount: uint40, consumeFrom: address, transmitter: address, amount: uint256)` | `0x38fd327622576a468e1b2818b00f50c8854703633ef8e583e1f31662888ffac2` | +| `CreditsUnwrapped` | `(consumeFrom: address, amount: uint256)` | `0xdcc9473b722b4c953617ab373840b365298a520bc7f20ce94fa7314f4a857774` | +| `CreditsWrapped` | `(consumeFrom: address, amount: uint256)` | `0x40246503613721eb4acf4020c6c56b6a16e5d08713316db0bea5210e8819c592` | +| `Deposited` | `(chainSlug: uint32, token: address, depositTo: address, creditAmount: uint256, nativeAmount: uint256)` | `0x72aedd284699bbd7a987e6942b824cfd6c627e354cb5a0760ac5768acd473f4a` | +| `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 -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `NativeDeposited` | `(from: address, amount: uint256)` | `0xb5d7700fb0cf415158b8db7cc7c39f0eab16a825c92e221404b4c8bb099b4bbb` | -| `NativeWithdrawn` | `(success: bool, to: address, amount: uint256)` | `0xa81f1c8490022ee829d2e1a231053f5dbecad46caee71f6ea38a9db663a3f12b` | -| `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` | +| Event | Arguments | Topic | +| ---------------------------- | ----------------------------------------------- | -------------------------------------------------------------------- | +| `NativeDeposited` | `(from: address, amount: uint256)` | `0xb5d7700fb0cf415158b8db7cc7c39f0eab16a825c92e221404b4c8bb099b4bbb` | +| `NativeWithdrawn` | `(success: bool, to: address, amount: uint256)` | `0xa81f1c8490022ee829d2e1a231053f5dbecad46caee71f6ea38a9db663a3f12b` | +| `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` | ## AddressResolver -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `AsyncDeployerUpdated` | `(asyncDeployer_: address)` | `0x4df9cdd01544e8f6b0326650bc0b55611f47ce5ba2faa522d21fb675e9fc1f73` | -| `ContractAddressUpdated` | `(contractId_: bytes32, contractAddress_: address)` | `0xdf5ec2c15e11ce657bb21bc09c0b5ba95e315b4dba9934c6e311f47559babf28` | -| `DefaultAuctionManagerUpdated` | `(defaultAuctionManager_: address)` | `0x60f296739208a505ead7fb622df0f76b7791b824481b120a2300bdaf85e3e3d6` | -| `DeployForwarderUpdated` | `(deployForwarder_: address)` | `0x237b9bc9fef7508a02ca9ccca81f6965e500064a58024cae1218035da865fd2b` | -| `FeesManagerUpdated` | `(feesManager_: address)` | `0x94e67aa1341a65767dfde81e62fd265bfbade1f5744bfd3cd73f99a6eca0572a` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `WatcherUpdated` | `(watcher_: address)` | `0xc13081d38d92b454cdb6ca20bbc65c12fa43a7a14a1529204ced5b6350052bb0` | +| Event | Arguments | Topic | +| ------------------------------ | --------------------------------------------------- | -------------------------------------------------------------------- | +| `AsyncDeployerUpdated` | `(asyncDeployer_: address)` | `0x4df9cdd01544e8f6b0326650bc0b55611f47ce5ba2faa522d21fb675e9fc1f73` | +| `ContractAddressUpdated` | `(contractId_: bytes32, contractAddress_: address)` | `0xdf5ec2c15e11ce657bb21bc09c0b5ba95e315b4dba9934c6e311f47559babf28` | +| `DefaultAuctionManagerUpdated` | `(defaultAuctionManager_: address)` | `0x60f296739208a505ead7fb622df0f76b7791b824481b120a2300bdaf85e3e3d6` | +| `DeployForwarderUpdated` | `(deployForwarder_: address)` | `0x237b9bc9fef7508a02ca9ccca81f6965e500064a58024cae1218035da865fd2b` | +| `FeesManagerUpdated` | `(feesManager_: address)` | `0x94e67aa1341a65767dfde81e62fd265bfbade1f5744bfd3cd73f99a6eca0572a` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `WatcherUpdated` | `(watcher_: address)` | `0xc13081d38d92b454cdb6ca20bbc65c12fa43a7a14a1529204ced5b6350052bb0` | ## AsyncDeployer -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `AsyncPromiseDeployed` | `(newAsyncPromise: address, salt: bytes32)` | `0xb6c5491cf83e09749b1a4dd6a9f07b0e925fcb0a915ac8c2b40e8ab28191c270` | -| `ForwarderDeployed` | `(newForwarder: address, salt: bytes32)` | `0x4dbbecb9cf9c8b93da9743a2b48ea52efe68d69230ab1c1b711891d9d223b29f` | -| `ImplementationUpdated` | `(contractName: string, newImplementation: address)` | `0xa1e41aa2c2f3f20d9b63ac06b634d2788768d6034f3d9192cdf7d07374bb16f4` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------- | +| `AsyncPromiseDeployed` | `(newAsyncPromise: address, salt: bytes32)` | `0xb6c5491cf83e09749b1a4dd6a9f07b0e925fcb0a915ac8c2b40e8ab28191c270` | +| `ForwarderDeployed` | `(newForwarder: address, salt: bytes32)` | `0x4dbbecb9cf9c8b93da9743a2b48ea52efe68d69230ab1c1b711891d9d223b29f` | +| `ImplementationUpdated` | `(contractName: string, newImplementation: address)` | `0xa1e41aa2c2f3f20d9b63ac06b634d2788768d6034f3d9192cdf7d07374bb16f4` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## AsyncPromise -| Event | Arguments | Topic | -| ----- | --------- | ----- | +| Event | Arguments | Topic | +| ------------- | ------------------- | -------------------------------------------------------------------- | | `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | ## DeployForwarder -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## Forwarder -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | - -## ForwarderSolana - -| Event | Arguments | Topic | -| ----- | --------- | ----- | +| Event | Arguments | Topic | +| ------------- | ------------------- | -------------------------------------------------------------------- | | `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | ## ProxyFactory -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `AdminChanged` | `(proxy: address, admin: address)` | `0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f` | -| `Deployed` | `(proxy: address, implementation: address, admin: address)` | `0xc95935a66d15e0da5e412aca0ad27ae891d20b2fb91cf3994b6a3bf2b8178082` | -| `Upgraded` | `(proxy: address, implementation: address)` | `0x5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c7` | +| Event | Arguments | Topic | +| -------------- | ----------------------------------------------------------- | -------------------------------------------------------------------- | +| `AdminChanged` | `(proxy: address, admin: address)` | `0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f` | +| `Deployed` | `(proxy: address, implementation: address, admin: address)` | `0xc95935a66d15e0da5e412aca0ad27ae891d20b2fb91cf3994b6a3bf2b8178082` | +| `Upgraded` | `(proxy: address, implementation: address)` | `0x5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c7` | ## TestUSDC -| Event | Arguments | Topic | -| ----- | --------- | ----- | +| Event | Arguments | Topic | +| ---------- | ----------------------------------------------------- | -------------------------------------------------------------------- | | `Approval` | `(owner: address, spender: address, amount: uint256)` | `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925` | -| `Transfer` | `(from: address, to: address, amount: uint256)` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | +| `Transfer` | `(from: address, to: address, amount: uint256)` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | ## ContractFactoryPlug -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | -| `Deployed` | `(addr: address, salt: bytes32, returnData: bytes)` | `0x1246c6f8fd9f4abc542c7c8c8f793cfcde6b67aed1976a38aa134fc24af2dfe3` | -| `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` | +| Event | Arguments | Topic | +| ---------------------------- | --------------------------------------------------- | -------------------------------------------------------------------- | +| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | +| `Deployed` | `(addr: address, salt: bytes32, returnData: bytes)` | `0x1246c6f8fd9f4abc542c7c8c8f793cfcde6b67aed1976a38aa134fc24af2dfe3` | +| `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` | ## 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` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PlugAdded` | `(appGatewayId: bytes32, chainSlug: uint32, plug: bytes32)` | `0x3734a2406c5c2f2556c82a0819c51e42a135dd102465cc9856594481ea2f1637` | -| `SocketSet` | `(chainSlug: uint32, socket: bytes32)` | `0x3200bf6ad2ab31b9220ed9d2f83089d7a1332f55aaa3825c57510743a315165b` | -| `SwitchboardSet` | `(chainSlug: uint32, sbType: bytes32, switchboard: bytes32)` | `0xcdfbfa261040f4dffb03c7d9493f74b575f2ae533bb43fd7b5d5b24ac9d804f4` | -| `VerifyConnectionsSB` | `(switchboard: bytes32, switchboardExpected: bytes32)` | `0xf55cb41249952cf17b38f1473238606bcd5048a5202d544f5d401c24a1208403` | +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------- | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `IsValidPlugSet` | `(isValid: bool, chainSlug: uint32, plug: bytes32, appGateway: address)` | `0xdd99f9f3d0179d3845b6c9b5e020d80c32ca46007e43c43c6ab6a86cb259ed28` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PlugAdded` | `(appGatewayId: bytes32, chainSlug: uint32, plug: bytes32)` | `0x3734a2406c5c2f2556c82a0819c51e42a135dd102465cc9856594481ea2f1637` | +| `SocketSet` | `(chainSlug: uint32, socket: bytes32)` | `0x3200bf6ad2ab31b9220ed9d2f83089d7a1332f55aaa3825c57510743a315165b` | +| `SwitchboardSet` | `(chainSlug: uint32, sbType: bytes32, switchboardId: uint64)` | `0x5aeb296e3ed47512d11032a96d11f93d8538b9eb87aa1db45d412e7165d6850a` | ## PromiseResolver -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `MarkedRevert` | `(payloadId: bytes32, isRevertingOnchain: bool)` | `0xcf1fd844cb4d32cbebb5ca6ce4ac834fe98da3ddac44deb77fffd22ad933824c` | -| `PromiseNotResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0xbcf0d0c678940566e9e64f0c871439395bd5fb5c39bca3547b126fe6ee467937` | -| `PromiseResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0x1b1b5810494fb3e17f7c46547e6e67cd6ad3e6001ea6fb7d12ea0241ba13c4ba` | +| Event | Arguments | Topic | +| -------------------- | ------------------------------------------------ | -------------------------------------------------------------------- | +| `MarkedRevert` | `(payloadId: bytes32, isRevertingOnchain: bool)` | `0xcf1fd844cb4d32cbebb5ca6ce4ac834fe98da3ddac44deb77fffd22ad933824c` | +| `PromiseNotResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0xbcf0d0c678940566e9e64f0c871439395bd5fb5c39bca3547b126fe6ee467937` | +| `PromiseResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0x1b1b5810494fb3e17f7c46547e6e67cd6ad3e6001ea6fb7d12ea0241ba13c4ba` | ## 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[])` | `0x762bac43d5d7689b8911c5654a9d5550804373cead33bc98282067e6166e518f` | +| 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` | +| `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 + | Event | Arguments | Topic | | ----- | --------- | ----- | -| `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` | -## FastSwitchboard +## ICCTPSwitchboard | Event | Arguments | Topic | | ----- | --------- | ----- | -| `Attested` | `(payloadId_: bytes32, watcher: address)` | `0x3d83c7bc55c269e0bc853ddc0d7b9fca30216ecc43779acb4e36b7e0ad1c71e4` | -| `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` | + +## CCTPSwitchboard + +| Event | Arguments | Topic | +| ---------------------------- | ----------------------------------------- | -------------------------------------------------------------------- | +| `Attested` | `(payloadId_: bytes32, watcher: address)` | `0x3d83c7bc55c269e0bc853ddc0d7b9fca30216ecc43779acb4e36b7e0ad1c71e4` | +| `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` | + +## FastSwitchboard + +| Event | Arguments | Topic | +| ---------------------------- | ----------------------------------------- | -------------------------------------------------------------------- | +| `Attested` | `(payloadId_: bytes32, watcher: address)` | `0x3d83c7bc55c269e0bc853ddc0d7b9fca30216ecc43779acb4e36b7e0ad1c71e4` | +| `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` | + +## MessageSwitchboard + +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `Attested` | `(payloadId: bytes32, digest: bytes32, watcher: address)` | `0x2f8e66b1207a4b70274a2a3da88ffb5737c8214576490da1b35acc38b2d62db6` | +| `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` | +| `SiblingConfigSet` | `(chainSlug: uint32, fee: uint256, socket: bytes32, switchboard: bytes32)` | `0xc34c3d0f0300f406c0f0608f6f6d70b36f5e90ccd1f1e1065bbe899f64cc81f0` | +| `SiblingRegistered` | `(chainSlug: uint32, plugAddress: address, siblingPlug: bytes32)` | `0xbb232aa6c0cb95b30a887c06b678538c818d3eac0dfd4d83299a18867cae220b` | +| `SwitchboardFeesSet` | `(chainSlug: uint32, feeAmount: uint256)` | `0x5e544c79c5017ebf2ea6aa546cd1c37272d5b4335247f0ceaabef51903dc5260` | +| `TriggerProcessed` | `(dstChainSlug: uint32, switchboardFees: uint256, digest: bytes32, digestParams: tuple)` | `0x0d585f64e2ebf6cc2b04ccbbaf63459f3b52c84111559988d28d6872185caa32` | ## ReadPrecompile -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | -| `ReadFeesSet` | `(readFees: uint256)` | `0xc674cb6dde3a59f84dbf226832e606ffc54ac8a169e1568fc834c7813010f926` | +| Event | Arguments | Topic | +| --------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `ReadFeesSet` | `(readFees: uint256)` | `0xc674cb6dde3a59f84dbf226832e606ffc54ac8a169e1568fc834c7813010f926` | | `ReadRequested` | `(transaction: tuple, readAtBlockNumber: uint256, payloadId: bytes32)` | `0xbcad63ac625c0f3cb23b62b126567728fcf5950ca8e559150e764eced73e794a` | ## 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 -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `ChainMaxMsgValueLimitsUpdated` | `(chainSlug: uint32, maxMsgValueLimit: uint256)` | `0x439087d094fe7dacbba3f0c67032041952d8bd58a891e15af10ced28fed0eb91` | -| `ContractFactoryPlugSet` | `(chainSlug: uint32, contractFactoryPlug: bytes32)` | `0xfad552a6feb82bef23201b8dce04b2460bff41b00f26fef3d791572cfdab49c2` | -| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | -| `FeesSet` | `(writeFees: uint256)` | `0x3346af6da1932164d501f2ec28f8c5d686db5828a36b77f2da4332d89184fe7b` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `WriteProofRequested` | `(transmitter: address, digest: bytes32, prevBatchDigestHash: bytes32, deadline: uint256, payloadParams: tuple)` | `0x3247df5b4e8df4ac60c2c1f803b404ee16bc9d84a6b7649865464a8a397b9acb` | -| `WriteProofUploaded` | `(payloadId: bytes32, proof: bytes)` | `0xd8fe3a99a88c9630360418877afdf14e3e79f0f25fee162aeb230633ea740156` | - +| Event | Arguments | Topic | +| ------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `ChainMaxMsgValueLimitsUpdated` | `(chainSlug: uint32, maxMsgValueLimit: uint256)` | `0x439087d094fe7dacbba3f0c67032041952d8bd58a891e15af10ced28fed0eb91` | +| `ContractFactoryPlugSet` | `(chainSlug: uint32, contractFactoryPlug: bytes32)` | `0xfad552a6feb82bef23201b8dce04b2460bff41b00f26fef3d791572cfdab49c2` | +| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `FeesSet` | `(writeFees: uint256)` | `0x3346af6da1932164d501f2ec28f8c5d686db5828a36b77f2da4332d89184fe7b` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `WriteProofRequested` | `(transmitter: address, digest: bytes32, prevBatchDigestHash: bytes32, deadline: uint256, payloadParams: tuple)` | `0xe3e3e322b3c2964670f4b62d06647c2f711440be782105fc1c0a60cc934bb40a` | +| `WriteProofUploaded` | `(payloadId: bytes32, proof: bytes)` | `0xd8fe3a99a88c9630360418877afdf14e3e79f0f25fee162aeb230633ea740156` | diff --git a/FunctionSignatures.md b/FunctionSignatures.md index 6663b725..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` | @@ -33,7 +33,7 @@ | `maxFees` | `0xe83e34b1` | | `maxReAuctionCount` | `0xc367b376` | | `onCompleteData` | `0xb52fa926` | -| `onRequestComplete` | `0x5ed1f959` | +| `onDeployComplete` | `0xfa3dbd1e` | | `overrideParams` | `0xec5490fe` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | @@ -58,14 +58,16 @@ | `cancelOwnershipHandover` | `0x54d1f13d` | | `chainSlug` | `0xb349ba65` | | `completeOwnershipHandover` | `0xf04e283e` | -| `connect` | `0xb3bde1aa` | -| `disableSwitchboard` | `0xc4d9a820` | -| `enableSwitchboard` | `0xf97a498a` | -| `execute` | `0xafa8b480` | +| `connect` | `0xf3aebe4d` | +| `disableSwitchboard` | `0x25e94caf` | +| `disconnect` | `0xd9374bff` | +| `enableSwitchboard` | `0xea072f06` | +| `execute` | `0x2e4d89fb` | +| `gasLimitBuffer` | `0xe4d728f0` | | `getPlugConfig` | `0xf9778ee0` | | `grantRole` | `0x2f2ff15d` | | `hasRole` | `0x91d14854` | -| `isValidSwitchboard` | `0xb2d67675` | +| `isValidSwitchboard` | `0xb30fe8ff` | | `maxCopyBytes` | `0x212249d4` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | @@ -76,93 +78,97 @@ | `requestOwnershipHandover` | `0x25692962` | | `rescueFunds` | `0x6ccae054` | | `revokeRole` | `0xd547741f` | +| `setGasLimitBuffer` | `0x1f0cfa78` | | `setMaxCopyBytes` | `0x4fc7d6e9` | | `setSocketFeeManager` | `0x25bd97e5` | | `simulate` | `0x91bf8275` | | `socketFeeManager` | `0xde5b8838` | +| `switchboardAddresses` | `0x9cf0af93` | +| `switchboardIdCounter` | `0x5f850dfd` | +| `switchboardIds` | `0x91db23d3` | | `transferOwnership` | `0xf2fde38b` | +| `triggerAppGateway` | `0x29e654e1` | | `triggerCounter` | `0x8b0021de` | | `version` | `0x54fd4d50` | -## SocketBatcher +## SocketFeeManager | Function | Signature | | ---------------------------- | ------------ | -| `attestAndExecute` | `0x66c7748a` | | `cancelOwnershipHandover` | `0x54d1f13d` | | `completeOwnershipHandover` | `0xf04e283e` | +| `getMinSocketFees` | `0xd383b688` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `payAndCheckFees` | `0x0b2b48ed` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | | `rescueFunds` | `0x6ccae054` | -| `socket__` | `0xc6a261d2` | +| `revokeRole` | `0xd547741f` | +| `setSocketFees` | `0x47a406f6` | +| `socketFees` | `0xab1b33a8` | | `transferOwnership` | `0xf2fde38b` | -## SocketFeeManager +## FeesManager | Function | Signature | | ---------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `approve` | `0xa3b53d8b` | +| `approveWithSignature` | `0x94b649ec` | +| `approveAppGateways` | `0x86d23ab2` | +| `asyncDeployer__` | `0x2a39e801` | +| `auctionManager` | `0xb0192f9a` | +| `blockCredits` | `0x9e434307` | | `cancelOwnershipHandover` | `0x54d1f13d` | | `completeOwnershipHandover` | `0xf04e283e` | -| `getMinSocketFees` | `0xd383b688` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | +| `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` | -| `payAndCheckFees` | `0xd9d29ae3` | | `renounceOwnership` | `0x715018a6` | +| `requestBlockedCredits` | `0xb62d25ac` | | `requestOwnershipHandover` | `0x25692962` | | `rescueFunds` | `0x6ccae054` | -| `revokeRole` | `0xd547741f` | -| `setSocketFees` | `0x47a406f6` | -| `socketFees` | `0xab1b33a8` | +| `sbType` | `0x745de344` | +| `setAddress` | `0x85bf312c` | +| `setFeesPlug` | `0xd6a9a8b7` | +| `setFeesPool` | `0xd6684588` | +| `tokenOnChainBalances` | `0x3b27866d` | +| `transferFrom` | `0xf1686c89` | | `transferOwnership` | `0xf2fde38b` | - -## FeesManager - -| Function | Signature | -| -------------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `approveAppGateway` | `0xa3b53d8b` | -| `approveAppGatewayWithSignature` | `0x94b649ec` | -| `approveAppGateways` | `0x86d23ab2` | -| `asyncDeployer__` | `0x2a39e801` | -| `blockCredits` | `0x9e434307` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deployForwarder__` | `0xd4e3b034` | -| `deposit` | `0x5671d329` | -| `evmxSlug` | `0x8bae77c2` | -| `feesManager__` | `0x70568b58` | -| `feesPlugs` | `0x23f5ee8a` | -| `feesPool` | `0x6b259690` | -| `getAvailableCredits` | `0xb065a8e5` | -| `handleRevert` | `0x44792f25` | -| `initialize` | `0xbf2c8539` | -| `isApproved` | `0xa389783e` | -| `isCreditSpendable` | `0x4f8990fd` | -| `isNonceUsed` | `0xcab7e8eb` | -| `onRequestComplete` | `0x5ed1f959` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestBlockedCredits` | `0xb62d25ac` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `sbType` | `0x745de344` | -| `setFeesPlug` | `0xd6a9a8b7` | -| `setFeesPool` | `0xd6684588` | -| `tokenOnChainBalances` | `0x3b27866d` | -| `transferCredits` | `0xf1686c89` | -| `transferOwnership` | `0xf2fde38b` | -| `unblockAndAssignCredits` | `0x01958181` | -| `unblockCredits` | `0xa0b32314` | -| `unwrap` | `0x7647691d` | -| `userCredits` | `0x20babb92` | -| `watcher__` | `0x300bb063` | -| `withdrawCredits` | `0xcfc6dbd9` | -| `wrap` | `0x023276f0` | +| `unblockAndAssignCredits` | `0x01958181` | +| `unblockCredits` | `0xa0b32314` | +| `unwrap` | `0x7647691d` | +| `userCredits` | `0x20babb92` | +| `watcher__` | `0x300bb063` | +| `withdrawCredits` | `0xcfc6dbd9` | +| `wrap` | `0x023276f0` | ## FeesPool @@ -297,22 +303,6 @@ | `rescueFunds` | `0x6ccae054` | | `watcher__` | `0x300bb063` | -## ForwarderSolana - -| Function | Signature | -| -------- | --------- | -| `addressResolver__` | `0x6a750469` | -| `asyncDeployer__` | `0x2a39e801` | -| `callSolana` | `0x4ef7957b` | -| `chainSlug` | `0xb349ba65` | -| `deployForwarder__` | `0xd4e3b034` | -| `feesManager__` | `0x70568b58` | -| `getChainSlug` | `0x0b8c6568` | -| `getOnChainAddress` | `0x9da48789` | -| `initialize` | `0x148841cb` | -| `onChainAddress` | `0x8bd0b363` | -| `watcher__` | `0x300bb063` | - ## ProxyFactory | Function | Signature | @@ -354,12 +344,12 @@ | `appGatewayId` | `0x1c335f49` | | `cancelOwnershipHandover` | `0x54d1f13d` | | `completeOwnershipHandover` | `0xf04e283e` | -| `connectSocket` | `0x258d19c8` | -| `deployContract` | `0xa0695389` | +| `connectSocket` | `0x943103c3` | +| `deployContract` | `0xff8caf37` | | `getAddress` | `0x94ca2cb5` | | `grantRole` | `0x2f2ff15d` | | `hasRole` | `0x91d14854` | -| `initSocket` | `0xa07d8545` | +| `initSocket` | `0x18b7ff72` | | `isSocketInitialized` | `0x9a7d9a9b` | | `overrides` | `0x4a85f041` | | `owner` | `0x8da5cb5b` | @@ -385,10 +375,10 @@ | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | | `rescueFunds` | `0x6ccae054` | -| `setAppGatewayConfigs` | `0xebfb22cd` | +| `setAppGatewayConfigs` | `0x831c8195` | | `setIsValidPlug` | `0x4842c37a` | | `setSocket` | `0x38d4de67` | -| `setSwitchboard` | `0x491eac1f` | +| `setSwitchboard` | `0x4fc059a0` | | `sockets` | `0xb44a23ab` | | `switchboards` | `0xaa539546` | | `transferOwnership` | `0xf2fde38b` | @@ -488,6 +478,44 @@ | `watcherMultiCall` | `0x8021e82b` | | `watcher__` | `0x300bb063` | +## CCTPSwitchboard + +| Function | Signature | +| -------------------------------- | ------------ | +| `addRemoteEndpoint` | `0x7d396da5` | +| `allowPacket` | `0x21e9ec80` | +| `allowPayload` | `0x31c23f66` | +| `attest` | `0x63671b60` | +| `attestVerifyAndProveExecutions` | `0x6c913e2f` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `chainSlug` | `0xb349ba65` | +| `chainSlugToRemoteEndpoint` | `0xa4500424` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `domainToRemoteEndpoint` | `0xc24964fe` | +| `getTransmitter` | `0x73e7d880` | +| `grantRole` | `0x2f2ff15d` | +| `handleReceiveMessage` | `0x96abeb70` | +| `hasRole` | `0x91d14854` | +| `isAttested` | `0xc13c2396` | +| `isRemoteExecuted` | `0x0cd97747` | +| `isSyncedOut` | `0x5ae5dfd6` | +| `messageTransmitter` | `0x7b04c181` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `processTrigger` | `0x7f3352bc` | +| `proveRemoteExecutions` | `0x893289f8` | +| `registerSwitchboard` | `0x74f5b1fc` | +| `remoteExecutedDigests` | `0xecbf77d9` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `socket__` | `0xc6a261d2` | +| `switchboardId` | `0xd3be4120` | +| `syncOut` | `0x69a60ff0` | +| `transferOwnership` | `0xf2fde38b` | +| `verifyAttestations` | `0x6f30514c` | + ## FastSwitchboard | Function | Signature | @@ -497,17 +525,54 @@ | `cancelOwnershipHandover` | `0x54d1f13d` | | `chainSlug` | `0xb349ba65` | | `completeOwnershipHandover` | `0xf04e283e` | +| `getTransmitter` | `0x73e7d880` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `isAttested` | `0xc13c2396` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `processTrigger` | `0x7f3352bc` | +| `registerSwitchboard` | `0x74f5b1fc` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `socket__` | `0xc6a261d2` | +| `switchboardId` | `0xd3be4120` | +| `transferOwnership` | `0xf2fde38b` | + +## MessageSwitchboard + +| Function | Signature | +| ---------------------------- | ------------ | +| `allowPayload` | `0x31c23f66` | +| `attest` | `0x4cc621d2` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `chainSlug` | `0xb349ba65` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `getSwitchboardFees` | `0x99de43bf` | +| `getTransmitter` | `0x73e7d880` | | `grantRole` | `0x2f2ff15d` | | `hasRole` | `0x91d14854` | | `isAttested` | `0xc13c2396` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `payloadCounter` | `0x550ce1d5` | +| `processTrigger` | `0x7f3352bc` | +| `registerSibling` | `0x4f58b88c` | | `registerSwitchboard` | `0x74f5b1fc` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | | `rescueFunds` | `0x6ccae054` | | `revokeRole` | `0xd547741f` | +| `setSiblingConfig` | `0xacfbfc03` | +| `setSwitchboardFees` | `0x476bfc49` | +| `siblingPlugs` | `0x25fc3bcc` | +| `siblingSockets` | `0xce3483a5` | +| `siblingSwitchboards` | `0x51de49c9` | | `socket__` | `0xc6a261d2` | +| `switchboardFees` | `0xb2a71ee7` | +| `switchboardId` | `0xd3be4120` | | `transferOwnership` | `0xf2fde38b` | ## ReadPrecompile @@ -516,10 +581,10 @@ | ------------------------------ | ------------ | | `expiryTime` | `0x99bc0aea` | | `getPrecompileFees` | `0xb7a3d04c` | -| `handlePayload` | `0x1d5e1d98` | +| `handlePayload` | `0x62974d96` | | `readFees` | `0xe06357a2` | | `rescueFunds` | `0x6ccae054` | -| `resolvePayload` | `0xea92e825` | +| `resolvePayload` | `0x7f0b2207` | | `setExpiryTime` | `0x30fc4cff` | | `setFees` | `0x3d18678e` | | `validateAndGetPrecompileData` | `0x997f5bef` | @@ -531,10 +596,10 @@ | ------------------------------ | ------------ | | `expiryTime` | `0x99bc0aea` | | `getPrecompileFees` | `0xb7a3d04c` | -| `handlePayload` | `0x1d5e1d98` | +| `handlePayload` | `0x62974d96` | | `maxScheduleDelayInSeconds` | `0x3ef01cdb` | | `rescueFunds` | `0x6ccae054` | -| `resolvePayload` | `0xea92e825` | +| `resolvePayload` | `0x7f0b2207` | | `scheduleCallbackFees` | `0x4c5b6007` | | `scheduleFeesPerSecond` | `0x852a74c1` | | `setExpiryTime` | `0x30fc4cff` | @@ -554,17 +619,17 @@ | `contractFactoryPlugs` | `0x35426631` | | `digestHashes` | `0xd1a862bf` | | `expiryTime` | `0x99bc0aea` | -| `getDigest` | `0x91b6288b` | +| `getDigest` | `0x3554edc7` | | `getPrecompileFees` | `0xb7a3d04c` | | `getPrevBatchDigestHash` | `0x372863a1` | -| `handlePayload` | `0x1d5e1d98` | +| `handlePayload` | `0x62974d96` | | `initialize` | `0xeb990c59` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | | `rescueFunds` | `0x6ccae054` | -| `resolvePayload` | `0xea92e825` | +| `resolvePayload` | `0x7f0b2207` | | `setContractFactoryPlugs` | `0x8b198f5c` | | `setExpiryTime` | `0x30fc4cff` | | `setFees` | `0x3d18678e` | 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 542c9a41..0c8a1630 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -121,6 +121,12 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { IsPlug isPlug_, bytes memory initCallData_ ) internal { + onCompleteData = abi.encodeWithSelector( + this.onDeployComplete.selector, + watcher__().getCurrentRequestCount(), + abi.encode(chainSlug_) + ); + deployForwarder__().deploy( isPlug_, chainSlug_, @@ -129,7 +135,6 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { ); then(this.setAddress.selector, abi.encode(chainSlug_, contractId_)); - onCompleteData = abi.encode(chainSlug_, true); } /// @notice Sets the address for a deployed contract @@ -226,7 +231,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 @@ -240,7 +245,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_); } @@ -366,15 +371,10 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @param onCompleteData_ The on complete data /// @dev only payload delivery can call this /// @dev callback in pd promise to be called after all contracts are deployed - function onRequestComplete( - uint40, - bytes calldata onCompleteData_ - ) external override onlyWatcher { + function onDeployComplete(uint40, bytes calldata onCompleteData_) external virtual onlyWatcher { if (onCompleteData_.length == 0) return; - (uint32 chainSlug, bool isDeploy) = abi.decode(onCompleteData_, (uint32, bool)); - if (isDeploy) { - initializeOnChain(chainSlug); - } + uint32 chainSlug = abi.decode(onCompleteData_, (uint32)); + initializeOnChain(chainSlug); } /// @notice Initializes the contract after deployment @@ -385,5 +385,5 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @notice hook to handle the revert in callbacks or onchain executions /// @dev can be overridden by the app gateway to add custom logic /// @param payloadId_ The payload ID - function handleRevert(bytes32 payloadId_) external override onlyPromises {} + function handleRevert(bytes32 payloadId_) external virtual onlyPromises {} } diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index cb822c04..7fbfe747 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -5,17 +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; @@ -28,11 +35,13 @@ abstract contract FeesManagerStorage is IFeesManager { // slot 51 /// @notice switchboard type - bytes32 public sbType; + 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 + // TODO: this will have to be bytes32 (for solana addresses) + mapping(address => uint256) public userBlockedCredits; // slot 53 /// @notice Mapping to track request credits details for each request count @@ -40,19 +49,19 @@ 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 // chainSlug => token address => amount + // TODO: this will have to be bytes32 (for solana tokens) mapping(uint32 => mapping(address => uint256)) public tokenOnChainBalances; // slot 56 /// @notice Mapping to track nonce to whether it has been used /// @dev address => signatureNonce => isNonceUsed /// @dev used by watchers or other users in signatures + // TODO: how about this, do we need to change it to bytes32 ? - how nonces are used here ? mapping(address => mapping(uint256 => bool)) public isNonceUsed; // slot 57 @@ -60,15 +69,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, AddressResolverUtil { +/// @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 @@ -89,9 +113,6 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR /// @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); @@ -101,6 +122,12 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR /// @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_); @@ -111,44 +138,85 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR 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 depositTo_ The EVMx address to deposit the credits to (it serves as accounting contract that mirrors real on-chain balances) /// @param chainSlug_ The chain slug /// @param token_ The token address /// @param nativeAmount_ The native amount /// @param creditAmount_ The credit amount + // TODO:4: for Solana handling we will need to have separate function deposit_solana() so that we do not have to change - (?) + // existing function on EVM UserVault which will refer to this one + // - also different handling on transmitter and indexer function deposit( uint32 chainSlug_, + // TODO: token will have to be bytes32 (for solana tokens) - this is the address of token on native chain (could be Solana) 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 some evmx accounting contract + _mint(depositTo_, creditAmount_); if (nativeAmount_ > 0) { + // TODO: ask: what are native tokens in this context ? - native to real blockchains or to EVMx itself ? // 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); @@ -156,9 +224,10 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR } 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(); @@ -166,12 +235,36 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR 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 @@ -186,32 +279,52 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR ) 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 + ); } } @@ -221,7 +334,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR /// @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; @@ -235,7 +348,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR 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); } @@ -257,10 +370,11 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR 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 @@ -277,11 +391,9 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR address consumeFrom_, uint256 maxFees_, bytes memory payload_ - ) internal { - OverrideParams memory overrideParams; - overrideParams.callType = WRITE; - overrideParams.writeFinality = WriteFinality.LOW; - // todo: can add gas limit here + ) internal async { + _setMaxFees(getMaxFees(chainSlug_)); + _setOverrides(consumeFrom_); QueueParams memory queueParams; queueParams.overrideParams = overrideParams; @@ -291,9 +403,11 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR payload: payload_ }); queueParams.switchboardType = sbType; + watcher__().queue(queueParams, address(this)); + } - // queue and create request - watcher__().queueAndSubmit(queueParams, maxFees_, address(0), consumeFrom_, bytes("")); + function increaseFees(uint40 requestCount_, uint256 newMaxFees_) public { + _increaseFees(requestCount_, newMaxFees_); } function _getFeesPlugAddress(uint32 chainSlug_) internal view returns (bytes32) { @@ -314,13 +428,28 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR signer = ECDSA.recover(digest, signature_); } - /// @notice hook called by watcher precompile when request is finished - function onRequestComplete(uint40, bytes memory) external {} + // ERC20 metadata + function name() public pure override returns (string memory) { + return "Socket USDC"; + } - /// @notice hook to handle the revert while withdrawing credits - /// @param payloadId_ The payload ID - function handleRevert(bytes32 payloadId_) external { - if (watcher__().getPayloadParams(payloadId_).asyncPromise != msg.sender) return; - emit WithdrawFailed(payloadId_); + 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 306b27c2..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,13 +52,44 @@ contract FeesManager is Credit { address addressResolver_, address feesPool_, address owner_, + uint256 fees_, bytes32 sbType_ - ) public reinitializer(1) { + ) public reinitializer(2) { evmxSlug = evmxSlug_; sbType = sbType_; feesPool = IFeesPool(feesPool_); - _setAddressResolver(addressResolver_); + 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 /////////////////////// @@ -68,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_); } @@ -87,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_]; @@ -104,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/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index 17053f3b..da19b34d 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -10,6 +10,7 @@ import {Forwarder} from "./Forwarder.sol"; import {AsyncPromise} from "./AsyncPromise.sol"; import {AddressResolverUtil} from "./AddressResolverUtil.sol"; import "../../utils/RescueFundsLib.sol"; +import "solady/utils/LibCall.sol"; abstract contract AsyncDeployerStorage is IAsyncDeployer { // slots [0-49] reserved for gap @@ -39,6 +40,8 @@ abstract contract AsyncDeployerStorage is IAsyncDeployer { /// @title AsyncDeployer Contract /// @notice This contract is responsible for deploying Forwarder and AsyncPromise contracts. contract AsyncDeployer is AsyncDeployerStorage, Initializable, AddressResolverUtil, Ownable { + using LibCall for address; + constructor() { _disableInitializers(); // disable for implementation } @@ -157,7 +160,7 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, AddressResolverUt address proxy = LibClone.deployDeterministicERC1967BeaconProxy(beacon_, salt_); // Explicitly initialize after deployment - (bool success, ) = proxy.call(initData_); + (bool success, , ) = proxy.tryCall(0, gasleft(), 0, initData_); require(success, "Initialization failed"); return proxy; diff --git a/contracts/evmx/interfaces/IAppGateway.sol b/contracts/evmx/interfaces/IAppGateway.sol index 2321a8bc..ce6fa9e4 100644 --- a/contracts/evmx/interfaces/IAppGateway.sol +++ b/contracts/evmx/interfaces/IAppGateway.sol @@ -15,11 +15,6 @@ interface IAppGateway { /// @return sbType_ The switchboard type function getOverrideParams() external view returns (OverrideParams memory, bytes32); - /// @notice Handles the request complete event - /// @param requestCount_ The request count - /// @param onCompleteData_ The on complete data - function onRequestComplete(uint40 requestCount_, bytes calldata onCompleteData_) external; - /// @notice Handles the revert event /// @param payloadId_ The payload id function handleRevert(bytes32 payloadId_) external; @@ -45,4 +40,8 @@ interface IAppGateway { bytes32 contractId_, uint32 chainSlug_ ) external view returns (address forwarderAddress); + + /// @notice get the switchboard type + /// @return sbType The switchboard type + function sbType() external view returns (bytes32); } 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/IConfigurations.sol b/contracts/evmx/interfaces/IConfigurations.sol index 9d095679..49cc0bbf 100644 --- a/contracts/evmx/interfaces/IConfigurations.sol +++ b/contracts/evmx/interfaces/IConfigurations.sol @@ -26,20 +26,21 @@ interface IConfigurations { function getPlugConfigs( uint32 chainSlug_, bytes32 plug_ - ) external view returns (bytes32, bytes32); + ) external view returns (bytes32, uint64); /// @notice Maps chain slug to their associated socket /// @param chainSlug_ The chain slug /// @return The socket function sockets(uint32 chainSlug_) external view returns (bytes32); - /// @notice Returns the socket for a given chain slug + /// @notice Returns the switchboardId for a given chain slug and switchboard type (1:1 mapping) /// @param chainSlug_ The chain slug - /// @return The socket - function switchboards(uint32 chainSlug_, bytes32 sbType_) external view returns (bytes32); + /// @param sbType_ The type of switchboard + /// @return switchboardId + function switchboards(uint32 chainSlug_, bytes32 sbType_) external view returns (uint64); /// @notice Sets the switchboard for a network - function setSwitchboard(uint32 chainSlug_, bytes32 sbType_, bytes32 switchboard_) external; + function setSwitchboard(uint32 chainSlug_, bytes32 sbType_, uint64 switchboardId_) external; /// @notice Sets valid plugs for each chain slug /// @dev This function is used to verify if a plug deployed on a chain slug is valid connection to the app gateway diff --git a/contracts/evmx/interfaces/IContractFactoryPlug.sol b/contracts/evmx/interfaces/IContractFactoryPlug.sol index 4fa5f0fe..9688be0a 100644 --- a/contracts/evmx/interfaces/IContractFactoryPlug.sol +++ b/contracts/evmx/interfaces/IContractFactoryPlug.sol @@ -15,7 +15,7 @@ interface IContractFactoryPlug { IsPlug isPlug_, bytes32 salt_, bytes32 appGatewayId_, - address switchboard_, + uint64 switchboardId_, bytes memory creationCode_, bytes memory initCallData_ ) external returns (address); 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/ContractFactoryPlug.sol b/contracts/evmx/plugs/ContractFactoryPlug.sol index a83e098e..feb06938 100644 --- a/contracts/evmx/plugs/ContractFactoryPlug.sol +++ b/contracts/evmx/plugs/ContractFactoryPlug.sol @@ -35,7 +35,7 @@ contract ContractFactoryPlug is PlugBase, AccessControl, IContractFactoryPlug { /// @param isPlug_ Whether the contract to be deployed is a plug /// @param salt_ The salt used for create 2 /// @param appGatewayId_ The app gateway id - /// @param switchboard_ The switchboard address + /// @param switchboardId_ The switchboard id /// @param creationCode_ The creation code /// @param initCallData_ The init call data /// @return addr The address of the deployed contract @@ -43,7 +43,7 @@ contract ContractFactoryPlug is PlugBase, AccessControl, IContractFactoryPlug { IsPlug isPlug_, bytes32 salt_, bytes32 appGatewayId_, - address switchboard_, + uint64 switchboardId_, bytes memory creationCode_, bytes memory initCallData_ ) public override onlySocket returns (address addr) { @@ -55,7 +55,8 @@ contract ContractFactoryPlug is PlugBase, AccessControl, IContractFactoryPlug { } } - if (isPlug_ == IsPlug.YES) IPlug(addr).initSocket(appGatewayId_, msg.sender, switchboard_); + if (isPlug_ == IsPlug.YES) + IPlug(addr).initSocket(appGatewayId_, msg.sender, switchboardId_); bytes memory returnData; if (initCallData_.length > 0) { @@ -89,9 +90,9 @@ contract ContractFactoryPlug is PlugBase, AccessControl, IContractFactoryPlug { function connectSocket( bytes32 appGatewayId_, address socket_, - address switchboard_ + uint64 switchboardId_ ) external onlyOwner { - _connectSocket(appGatewayId_, socket_, switchboard_); + _connectSocket(appGatewayId_, socket_, switchboardId_); } /** diff --git a/contracts/evmx/plugs/FeesPlug.sol b/contracts/evmx/plugs/FeesPlug.sol index 3e035125..e0b2d654 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,42 +38,56 @@ 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 evmx_receiver_, + uint256 amount_, + bytes memory data_ + ) external override { + _deposit(token_, evmx_receiver_, amount_, 0, data_); } function depositCreditAndNative( address token_, - address receiver_, - uint256 amount_ + address evmx_receiver_, + uint256 amount_, + bytes memory data_ ) external override { uint256 nativeAmount_ = amount_ / 10; - _deposit(token_, receiver_, amount_ - nativeAmount_, nativeAmount_); + _deposit(token_, evmx_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 evmx_receiver_, + uint256 amount_, + bytes memory data_ + ) external override { + _deposit(token_, evmx_receiver_, 0, amount_, data_); } /// @notice Deposits funds /// @param token_ The token address /// @param creditAmount_ The amount of fees /// @param nativeAmount_ The amount of native tokens - /// @param receiver_ The receiver address + /// @param evmx_receiver_ The evmx receiver address. EVMx tokens will be minted to this address to mirror real on-chain balances. function _deposit( address token_, - address receiver_, + address evmx_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_, evmx_receiver_, creditAmount_, nativeAmount_, data_); } - /// @notice Withdraws fees + /// @notice Withdraws fees - amount in is represented as 18 decimals token. + /// Before transferring we need to convert to do decimals given token has on this chain. + /// final_amount = input_amount / 10^18 * 10^decimals => input_amount * 10^(-18 + decimals) => input_amount * 10^(decimals - 18) /// @param token_ The token address - /// @param amount_ The amount + /// @param amount_ The input amount (represented as 18 decimals token) /// @param receiver_ The receiver address function withdrawFees( address token_, @@ -119,9 +128,13 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { function connectSocket( bytes32 appGatewayId_, address socket_, - address switchboard_ + uint64 switchboardId_ ) external onlyOwner { - _connectSocket(appGatewayId_, socket_, switchboard_); + _connectSocket(appGatewayId_, socket_, switchboardId_); + } + + function disconnectSocket() external onlyOwner { + socket__.disconnect(); } /** 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 02726002..ddeee64c 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -21,8 +21,8 @@ abstract contract ConfigurationsStorage is IConfigurations { // slot 51 /// @notice Maps chain slug to their associated switchboard - /// @dev chainSlug => sb type => switchboard address - mapping(uint32 => mapping(bytes32 => bytes32)) public switchboards; + /// @dev chainSlug => sb type => switchboard id + mapping(uint32 => mapping(bytes32 => uint64)) public switchboards; // slot 52 /// @notice Maps chain slug to their associated socket @@ -56,8 +56,8 @@ contract Configurations is ConfigurationsStorage, Initializable, Ownable, Watche /// @notice Emitted when a switchboard is set for a network /// @param chainSlug The identifier of the network /// @param sbType The type of switchboard - /// @param switchboard The address of the switchboard - event SwitchboardSet(uint32 chainSlug, bytes32 sbType, bytes32 switchboard); + /// @param switchboardId The id of the switchboard + event SwitchboardSet(uint32 chainSlug, bytes32 sbType, uint64 switchboardId); /// @notice Emitted when socket is set for a network /// @param chainSlug The identifier of the network @@ -69,7 +69,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 @@ -108,14 +108,14 @@ contract Configurations is ConfigurationsStorage, Initializable, Ownable, Watche /// @notice Sets the switchboard for a network /// @param chainSlug_ The identifier of the network /// @param sbType_ The type of switchboard, hash of a string - /// @param switchboard_ The address of the switchboard + /// @param switchboardId_ The id of the switchboard function setSwitchboard( uint32 chainSlug_, bytes32 sbType_, - bytes32 switchboard_ + uint64 switchboardId_ ) external onlyOwner { - switchboards[chainSlug_][sbType_] = switchboard_; - emit SwitchboardSet(chainSlug_, sbType_, switchboard_); + switchboards[chainSlug_][sbType_] = switchboardId_; + emit SwitchboardSet(chainSlug_, sbType_, switchboardId_); } /// @notice Sets the valid plugs for an app gateway @@ -131,22 +131,22 @@ 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 /// @dev Returns zero addresses if configuration doesn't exist /// @param chainSlug_ The identifier of the network /// @param plug_ The address of the plug - /// @return The app gateway id and switchboard address for the plug + /// @return The app gateway id and switchboard id for the plug /// @dev Returns zero addresses if configuration doesn't exist function getPlugConfigs( uint32 chainSlug_, bytes32 plug_ - ) public view returns (bytes32, bytes32) { + ) public view returns (bytes32, uint64) { return ( _plugConfigs[chainSlug_][plug_].appGatewayId, - _plugConfigs[chainSlug_][plug_].switchboard + _plugConfigs[chainSlug_][plug_].switchboardId ); } @@ -162,9 +162,10 @@ contract Configurations is ConfigurationsStorage, Initializable, Ownable, Watche address appGateway_, bytes32 switchboardType_ ) external view { - (bytes32 appGatewayId, bytes32 switchboard) = getPlugConfigs(chainSlug_, target_); + (bytes32 appGatewayId, uint64 switchboardId) = getPlugConfigs(chainSlug_, target_); if (appGatewayId != toBytes32Format(appGateway_)) revert InvalidGateway(); - if (switchboard != switchboards[chainSlug_][switchboardType_]) revert InvalidSwitchboard(); + if (switchboardId != switchboards[chainSlug_][switchboardType_]) + revert InvalidSwitchboard(); } /** diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index d226492c..21172725 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -54,7 +54,7 @@ contract PromiseResolver is IPromiseResolver, WatcherBase { if (payloadParams.deadline < block.timestamp) revert DeadlinePassed(); address asyncPromise = payloadParams.asyncPromise; - requestCount = payloadParams.requestCount; + requestCount = uint40(payloadParams.payloadPointer >> 120); if (asyncPromise != address(0)) { success = IPromise(asyncPromise).markResolved(resolvedPromise_); @@ -82,10 +82,10 @@ 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(payloadParams.requestCount); + requestHandler__().cancelRequestForReverts(uint40(payloadParams.payloadPointer >> 120)); // marks the promise as onchain reverting if the request is reverting onchain if (isRevertingOnchain_ && payloadParams.asyncPromise != address(0)) diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index ad1a6b71..a5d793e0 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -11,6 +11,8 @@ import "../interfaces/IAppGateway.sol"; 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 @@ -60,6 +62,8 @@ abstract contract RequestHandlerStorage is IRequestHandler { /// @notice Contract that handles request processing and management, including request submission, batch processing, and request lifecycle management /// @dev Handles request submission, batch processing, transmitter assignment, request cancellation and settlement contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, AddressResolverUtil { + using LibCall for address; + error InsufficientMaxFees(); event RequestSubmitted( @@ -74,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) @@ -98,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( @@ -186,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)) { @@ -227,9 +238,7 @@ contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, Addres _requestBatchIds[requestCount_].push(nextBatchCount); } - // get the switchboard address from the configurations - // returns bytes32(0) for schedule precompile and reads if sb type not set - bytes32 switchboard = watcher__().configurations__().switchboards( + uint64 switchboardId = watcher__().configurations__().switchboards( queuePayloadParam.transaction.chainSlug, queuePayloadParam.switchboardType ); @@ -243,22 +252,20 @@ contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, Addres result.totalEstimatedWatcherFees += estimatedFees; // create payload id - uint40 payloadCount = payloadCounter++; + uint160 payloadPointer = (uint160(requestCount_) << 120) | + (uint160(nextBatchCount) << 80) | + uint160(payloadCounter++); + bytes32 payloadId = createPayloadId( - requestCount_, - nextBatchCount, - payloadCount, - switchboard, - // todo: add evmx chain slug if schedule or read? + payloadPointer, + switchboardId, queuePayloadParam.transaction.chainSlug ); _batchPayloadIds[nextBatchCount].push(payloadId); // create prev digest hash PayloadParams memory p; - p.requestCount = requestCount_; - p.batchCount = nextBatchCount; - p.payloadCount = payloadCount; + p.payloadPointer = payloadPointer; p.callType = callType; p.asyncPromise = queueParams_[i].asyncPromise; p.appGateway = appGateway_; @@ -317,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 @@ -419,13 +426,9 @@ contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, Addres ); if (r.onCompleteData.length > 0) { - try - IAppGateway(r.appGateway).onRequestComplete(requestCount_, r.onCompleteData) - {} catch { - emit RequestCompletedWithErrors(requestCount_); - } + (bool success, , ) = r.appGateway.tryCall(0, gasleft(), 0, r.onCompleteData); + if (!success) emit RequestCompletedWithErrors(requestCount_); } - emit RequestSettled(requestCount_, r.requestFeesDetails.winningBid.transmitter); } 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 b6714b92..0c714c3f 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -5,6 +5,10 @@ import "./Trigger.sol"; 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 } @@ -29,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) { @@ -184,7 +190,12 @@ contract Watcher is Trigger { ); // call the contract - (bool success, ) = params_[i].contractAddress.call(params_[i].data); + (bool success, , ) = params_[i].contractAddress.tryCall( + 0, + gasleft(), + 0, + params_[i].data + ); if (!success) revert CallFailed(); } } 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/borsh-serde/BorshEncoder.sol b/contracts/evmx/watcher/borsh-serde/BorshEncoder.sol index b498059e..e0b0f9cb 100644 --- a/contracts/evmx/watcher/borsh-serde/BorshEncoder.sol +++ b/contracts/evmx/watcher/borsh-serde/BorshEncoder.sol @@ -39,7 +39,7 @@ library BorshEncoder { uint128 arg = uint128(abiDecodedArg); bytes16 borshEncodedArg = encodeU128(arg); functionArgsPacked = abi.encodePacked(functionArgsPacked, borshEncodedArg); - } else if (keccak256(bytes(typeName)) == keccak256(bytes("string"))) { + } else if (keccak256(bytes(typeName)) == keccak256(bytes("String"))) { string memory abiDecodedArg = abi.decode(data, (string)); bytes memory borshEncodedArg = encodeString(abiDecodedArg); functionArgsPacked = abi.encodePacked(functionArgsPacked, borshEncodedArg); @@ -65,7 +65,7 @@ library BorshEncoder { uint128[] memory abiDecodedArg = abi.decode(data, (uint128[])); bytes memory borshEncodedArg = encodeUint128Vec(abiDecodedArg); functionArgsPacked = abi.encodePacked(functionArgsPacked, borshEncodedArg); - } else if (keccak256(bytes(typeName)) == keccak256(bytes("string[]"))) { + } else if (keccak256(bytes(typeName)) == keccak256(bytes("String[]"))) { string[] memory abiDecodedArg = abi.decode(data, (string[])); bytes memory borshEncodedArg = encodeStringArray(abiDecodedArg); functionArgsPacked = abi.encodePacked(functionArgsPacked, borshEncodedArg); @@ -154,6 +154,7 @@ library BorshEncoder { /// Encode bytes vector into borsh. Use this method to encode strings as well. function encodeBytes(bytes memory value) internal pure returns (bytes memory) { + require(value.length <= type(uint32).max, "vector length overflow (must fit in uint32)"); return abi.encodePacked(encodeU32(uint32(value.length)), bytes(value)); } @@ -165,31 +166,37 @@ library BorshEncoder { /** Encode Vector types with that can have variable length **/ function encodeUint8Vec(uint8[] memory arr) internal pure returns (bytes memory) { + require(arr.length <= type(uint32).max, "vector length overflow (must fit in uint32)"); bytes memory packed = packUint8Array(arr); return bytes.concat(encodeU32(uint32(arr.length)), packed); } function encodeUint16Vec(uint16[] memory arr) internal pure returns (bytes memory) { + require(arr.length <= type(uint32).max, "vector length overflow (must fit in uint32)"); bytes memory packed = packUint16Array(arr); return bytes.concat(encodeU32(uint32(arr.length)), packed); } function encodeUint32Vec(uint32[] memory arr) internal pure returns (bytes memory) { + require(arr.length <= type(uint32).max, "vector length overflow (must fit in uint32)"); bytes memory packed = packUint32Array(arr); return bytes.concat(encodeU32(uint32(arr.length)), packed); } function encodeUint64Vec(uint64[] memory arr) internal pure returns (bytes memory) { + require(arr.length <= type(uint32).max, "vector length overflow (must fit in uint32)"); bytes memory packed = packUint64Array(arr); return bytes.concat(encodeU32(uint32(arr.length)), packed); } function encodeUint128Vec(uint128[] memory arr) internal pure returns (bytes memory) { + require(arr.length <= type(uint32).max, "vector length overflow (must fit in uint32)"); bytes memory packed = packUint128Array(arr); return bytes.concat(encodeU32(uint32(arr.length)), packed); } function encodeStringVec(string[] memory arr) internal pure returns (bytes memory) { + require(arr.length <= type(uint32).max, "string length overflow (must fit in uint32)"); bytes memory packed = packStringArray(arr); return bytes.concat(encodeU32(uint32(arr.length)), packed); } 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 28b2c047..d51bceca 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -48,8 +48,6 @@ abstract contract WritePrecompileStorage is IPrecompile { /// @title WritePrecompile /// @notice Handles write precompile logic contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, WatcherBase { - // using BorshEncoder for borsh; - /// @notice Emitted when fees are set event FeesSet(uint256 writeFees); event ChainMaxMsgValueLimitsUpdated(uint32 chainSlug, uint256 maxMsgValueLimit); @@ -125,7 +123,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 @@ -135,7 +144,7 @@ contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, Watc queueParams_.overrideParams.writeFinality, queueParams_.overrideParams.gasLimit, queueParams_.overrideParams.value, - configurations__().switchboards( + configurations__().switchboards( // switchboardId queueParams_.transaction.chainSlug, queueParams_.switchboardType ) @@ -161,12 +170,11 @@ contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, Watc Transaction memory transaction, , uint256 gasLimit, - uint256 value, - - ) = - abi.decode( + uint256 value + ,// switchboardId + ) = abi.decode( payloadParams.precompileData, - (address, Transaction, WriteFinality, uint256, uint256, bytes32) + (address, Transaction, WriteFinality, uint256, uint256, uint64) ); precompileData = payloadParams.precompileData; @@ -174,8 +182,8 @@ contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, Watc fees = getPrecompileFees(payloadParams.precompileData); bytes32 prevBatchDigestHash = getPrevBatchDigestHash( - payloadParams.requestCount, - payloadParams.batchCount + uint40(payloadParams.payloadPointer >> 120), + uint40(payloadParams.payloadPointer >> 80) ); // Construct parameters for digest calculation @@ -185,7 +193,7 @@ contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, Watc payloadParams, transaction, appGateway, - transmitter_, + transmitter_, // TODO: we should use here Solana transmitter address prevBatchDigestHash, deadline, gasLimit, @@ -276,7 +284,7 @@ contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, Watc return DigestParams( configurations__().sockets(transaction_.chainSlug), - transmitter_, + toBytes32Format(transmitter_), payloadParams_.payloadId, deadline_, payloadParams_.callType, @@ -319,7 +327,7 @@ contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, Watc DigestParams( // watcherPrecompileConfig__.sockets(params_.payloadHeader.getChainSlug()), // TODO: this does not work, for some reason it returns 0x000.... address hardcodedSocket, - transmitter_, + toBytes32Format(transmitter_), payloadParams_.payloadId, deadline_, payloadParams_.callType, @@ -392,15 +400,4 @@ contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, Watc function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); } - - // // Borsh helper functions - // function encodeU64Borsh(uint64 v) public pure returns (bytes8) { - // return bytes8(swapBytes8(v)); - // } - - // function swapBytes8(uint64 v) internal pure returns (uint64) { - // v = ((v & 0x00ff00ff00ff00ff) << 8) | ((v & 0xff00ff00ff00ff00) >> 8); - // v = ((v & 0x0000ffff0000ffff) << 16) | ((v & 0xffff0000ffff0000) >> 16); - // return (v << 32) | (v >> 32); - // } } diff --git a/contracts/protocol/Socket.sol b/contracts/protocol/Socket.sol index b5e8bb17..4d4b2257 100644 --- a/contracts/protocol/Socket.sol +++ b/contracts/protocol/Socket.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.21; import "./SocketUtils.sol"; + import {WRITE} from "../utils/common/Constants.sol"; import {createPayloadId} from "../utils/common/IdUtils.sol"; @@ -13,33 +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; - // @notice buffer to account for gas used by current contract execution - uint256 private constant GAS_LIMIT_BUFFER = 105; - //////////////////////////////////////////////////////// ////////////////////// 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(); /** @@ -52,10 +42,16 @@ contract Socket is SocketUtils { uint32 chainSlug_, address owner_, string memory version_ - ) SocketUtils(chainSlug_, owner_, version_) {} + ) SocketUtils(chainSlug_, owner_, version_) { + gasLimitBuffer = 105; + } /** * @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,63 +63,76 @@ 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(); bytes32 payloadId = createPayloadId( - executeParams_.requestCount, - executeParams_.batchCount, - executeParams_.payloadCount, - toBytes32Format(plugConfig.switchboard), + executeParams_.payloadPointer, + plugConfig.switchboardId, chainSlug ); // validate the execution status _validateExecutionStatus(payloadId); - address transmitter = transmissionParams_.transmitterSignature.length > 0 - ? _recoverSigner( - keccak256(abi.encode(address(this), payloadId)), - transmissionParams_.transmitterSignature - ) - : address(0); - - // create the digest - // transmitter, payloadId, appGateway, executeParams_ and there contents are validated using digest verification from switchboard - bytes32 digest = _createDigest( - transmitter, - payloadId, - plugConfig.appGatewayId, - executeParams_ - ); - payloadIdToDigest[payloadId] = digest; - // verify the digest - _verify(digest, payloadId, plugConfig.switchboard); + _verify(payloadId, plugConfig, executeParams_, transmissionParams_.transmitterProof); + // execute the payload return _execute(payloadId, executeParams_, transmissionParams_); } //////////////////////////////////////////////////////// ////////////////// INTERNAL FUNCS ////////////////////// //////////////////////////////////////////////////////// - function _verify(bytes32 digest_, bytes32 payloadId_, address switchboard_) internal view { - if (isValidSwitchboard[switchboard_] != SwitchboardStatus.REGISTERED) + /** + * @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_, + ExecuteParams calldata executeParams_, + bytes calldata transmitterProof_ + ) internal { + if (isValidSwitchboard[plugConfig_.switchboardId] != SwitchboardStatus.REGISTERED) revert InvalidSwitchboard(); - // NOTE: is the the first un-trusted call in the system, another one is Plug.call - if (!ISwitchboard(switchboard_).allowPayload(digest_, payloadId_)) - revert VerificationFailed(); + // NOTE: the first un-trusted call in the system + address transmitter = ISwitchboard(switchboardAddresses[plugConfig_.switchboardId]) + .getTransmitter(msg.sender, payloadId_, transmitterProof_); + + // create the digest + // transmitter, payloadId, appGateway, executeParams_ and there contents are validated using digest verification from switchboard + bytes32 digest = _createDigest( + transmitter, + payloadId_, + plugConfig_.appGatewayId, + executeParams_ + ); + payloadIdToDigest[payloadId_] = digest; + + if ( + !ISwitchboard(switchboardAddresses[plugConfig_.switchboardId]).allowPayload( + digest, + payloadId_ + ) + ) revert VerificationFailed(); } /** - * 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_, @@ -132,7 +141,7 @@ contract Socket is SocketUtils { ) internal returns (bool success, bytes memory returnData) { // check if the gas limit is sufficient // bump by 5% to account for gas used by current contract execution - if (gasleft() < (executeParams_.gasLimit * GAS_LIMIT_BUFFER) / 100) revert LowGasLimit(); + if (gasleft() < (executeParams_.gasLimit * gasLimitBuffer) / 100) revert LowGasLimit(); // NOTE: external un-trusted call bool exceededMaxCopy; @@ -146,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_, @@ -155,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_]); @@ -176,34 +189,70 @@ contract Socket is SocketUtils { //////////////////////////////////////////////////////// ////////////////////// Trigger ////////////////////// //////////////////////////////////////////////////////// + + /** + * @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_) internal returns (bytes32 triggerId) { + function _triggerAppGateway( + address plug_, + uint256 value_, + bytes calldata data_ + ) internal returns (bytes32 triggerId) { PlugConfigEvm memory plugConfig = _plugConfigs[plug_]; // if no sibling plug is found for the given chain slug, revert - // sends the trigger to connected app gateway if (plugConfig.appGatewayId == bytes32(0)) revert PlugNotFound(); + if (isValidSwitchboard[plugConfig.switchboardId] != SwitchboardStatus.REGISTERED) + revert InvalidSwitchboard(); - // creates a unique ID for the message + bytes memory plugOverrides = IPlug(plug_).overrides(); triggerId = _encodeTriggerId(); + + // todo: need gas limit? + ISwitchboard(switchboardAddresses[plugConfig.switchboardId]).processTrigger{value: value_}( + plug_, + triggerId, + data_, + plugOverrides + ); + emit AppGatewayCallRequested( triggerId, plugConfig.appGatewayId, - toBytes32Format(plugConfig.switchboard), + plugConfig.switchboardId, toBytes32Format(plug_), - // gets the overrides from the plug - IPlug(plug_).overrides(), - msg.data + plugOverrides, + data_ ); } - /// @notice Fallback function that forwards all calls to Socket's callAppGateway - /// @dev The calldata is passed as-is to the gateways - /// @dev if ETH sent with the call, it will revert - fallback(bytes calldata) external returns (bytes memory) { + /** + * @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)); + return abi.encode(_triggerAppGateway(msg.sender, msg.value, msg.data)); + } + + /** + * @notice Sending ETH to the socket will revert + */ + receive() external payable { + revert("Socket does not accept ETH"); } } diff --git a/contracts/protocol/SocketBatcher.sol b/contracts/protocol/SocketBatcher.sol index 1013af2f..1ed5a359 100644 --- a/contracts/protocol/SocketBatcher.sol +++ b/contracts/protocol/SocketBatcher.sol @@ -5,12 +5,22 @@ import "solady/auth/Ownable.sol"; import "./interfaces/ISocket.sol"; import "./interfaces/ISocketBatcher.sol"; import "./interfaces/ISwitchboard.sol"; +import "./interfaces/ICCTPSwitchboard.sol"; import "../utils/RescueFundsLib.sol"; -import {ExecuteParams, TransmissionParams} from "../utils/common/Structs.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 @@ -31,23 +41,23 @@ contract SocketBatcher is ISocketBatcher, Ownable { * @param executeParams_ The execution parameters * @param digest_ The digest of the payload * @param proof_ The proof of the payload - * @param transmitterSignature_ The signature of the transmitter + * @param transmitterProof_ The signature of the transmitter * @return The return data after execution */ function attestAndExecute( ExecuteParams calldata executeParams_, - address switchboard_, + uint64 switchboardId_, bytes32 digest_, bytes calldata proof_, - bytes calldata transmitterSignature_, + bytes calldata transmitterProof_, address refundAddress_ ) external payable returns (bool, bytes memory) { - ISwitchboard(switchboard_).attest(digest_, proof_); + IFastSwitchboard(socket__.switchboardAddresses(switchboardId_)).attest(digest_, proof_); return socket__.execute{value: msg.value}( executeParams_, TransmissionParams({ - transmitterSignature: transmitterSignature_, + transmitterProof: transmitterProof_, socketFees: 0, extraData: executeParams_.extraData, refundAddress: refundAddress_ @@ -55,6 +65,44 @@ 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_, + uint64 switchboardId_ + ) external payable returns (bool, bytes memory) { + address switchboard = socket__.switchboardAddresses(switchboardId_); + bytes32 payloadId = createPayloadId( + execParams_.executeParams.payloadPointer, + switchboardId_, + socket__.chainSlug() + ); + ICCTPSwitchboard(switchboard).attestVerifyAndProveExecutions( + execParams_, + cctpParams_, + payloadId + ); + (bool success, bytes memory returnData) = socket__.execute{value: msg.value}( + execParams_.executeParams, + TransmissionParams({ + transmitterProof: execParams_.transmitterSignature, + socketFees: 0, + extraData: execParams_.executeParams.extraData, + refundAddress: execParams_.refundAddress + }) + ); + + ICCTPSwitchboard(switchboard).syncOut(payloadId, cctpParams_.nextBatchRemoteChainSlugs); + return (success, returnData); + } + /** * @notice Rescues funds from the contract * @param token_ The address of the token to rescue diff --git a/contracts/protocol/SocketConfig.sol b/contracts/protocol/SocketConfig.sol index 32bafb17..990003f4 100644 --- a/contracts/protocol/SocketConfig.sol +++ b/contracts/protocol/SocketConfig.sol @@ -22,7 +22,7 @@ abstract contract SocketConfig is ISocket, AccessControl { ISocketFeeManager public socketFeeManager; // @notice mapping of switchboard address to its status, helps socket to block invalid switchboards - mapping(address => SwitchboardStatus) public isValidSwitchboard; + mapping(uint64 => SwitchboardStatus) public isValidSwitchboard; // @notice mapping of plug address to its config mapping(address => PlugConfigEvm) internal _plugConfigs; @@ -30,80 +30,150 @@ abstract contract SocketConfig is ISocket, AccessControl { // @notice max copy bytes for socket uint16 public maxCopyBytes = 2048; // 2KB + // @notice counter for switchboard ids + uint64 public switchboardIdCounter = 1; + + // @notice mapping of switchboard id to its address + mapping(uint64 => address) public switchboardAddresses; + + // @notice mapping of switchboard address to its id + mapping(address => uint64) public switchboardIds; + + // @notice buffer to account for gas used by current contract execution + uint256 public gasLimitBuffer; + // @notice error triggered when a switchboard already exists error SwitchboardExists(); - // @notice error triggered when a switchboard already exists or is disabled - error SwitchboardExistsOrDisabled(); + // @notice error triggered when a plug is not connected + error PlugNotConnected(); // @notice event triggered when a new switchboard is added - event SwitchboardAdded(address switchboard); + event SwitchboardAdded(address switchboard, uint64 switchboardId); // @notice event triggered when a switchboard is disabled - event SwitchboardDisabled(address switchboard); + event SwitchboardDisabled(uint64 switchboardId); // @notice event triggered when a switchboard is enabled - event SwitchboardEnabled(address switchboard); + 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 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++; - // @notice function to register a switchboard - // @dev only callable by switchboards - function registerSwitchboard() external { - if (isValidSwitchboard[msg.sender] != SwitchboardStatus.NOT_REGISTERED) - revert SwitchboardExistsOrDisabled(); + // set the switchboard id and address + switchboardIds[msg.sender] = switchboardId; + switchboardAddresses[switchboardId] = msg.sender; - isValidSwitchboard[msg.sender] = SwitchboardStatus.REGISTERED; - emit SwitchboardAdded(msg.sender); + // 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 - function disableSwitchboard(address switchboard_) external onlyRole(SWITCHBOARD_DISABLER_ROLE) { - isValidSwitchboard[switchboard_] = SwitchboardStatus.DISABLED; - emit SwitchboardDisabled(switchboard_); + /** + * @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) { + isValidSwitchboard[switchboardId_] = SwitchboardStatus.DISABLED; + emit SwitchboardDisabled(switchboardId_); } - // @notice function to enable a switchboard - // @dev only callable by governance role - function enableSwitchboard() external onlyRole(GOVERNANCE_ROLE) { - isValidSwitchboard[msg.sender] = SwitchboardStatus.REGISTERED; - emit SwitchboardEnabled(msg.sender); + /** + * @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_, address switchboard_) external override { - if (isValidSwitchboard[switchboard_] != SwitchboardStatus.REGISTERED) + function connect(bytes32 appGatewayId_, uint64 switchboardId_) external override { + if (isValidSwitchboard[switchboardId_] != SwitchboardStatus.REGISTERED) revert InvalidSwitchboard(); PlugConfigEvm storage _plugConfig = _plugConfigs[msg.sender]; - _plugConfig.appGatewayId = appGatewayId_; - _plugConfig.switchboard = switchboard_; + _plugConfig.switchboardId = switchboardId_; + + emit PlugConnected(msg.sender, appGatewayId_, switchboardId_); + } + + /** + * @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]; + if (_plugConfig.appGatewayId == bytes32(0)) revert PlugNotConnected(); - emit PlugConnected(msg.sender, appGatewayId_, switchboard_); + _plugConfig.appGatewayId = bytes32(0); + _plugConfig.switchboardId = 0; + emit PlugDisconnected(msg.sender); } - // @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 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 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 switchboard The switchboard address + * @return switchboardId The switchboard id */ function getPlugConfig( address plugAddress_ - ) external view returns (bytes32 appGatewayId, address switchboard) { + ) external view returns (bytes32 appGatewayId, uint64 switchboardId) { PlugConfigEvm memory _plugConfig = _plugConfigs[plugAddress_]; - return (_plugConfig.appGatewayId, _plugConfig.switchboard); + return (_plugConfig.appGatewayId, _plugConfig.switchboardId); } } 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 46597144..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_, @@ -76,7 +82,7 @@ abstract contract SocketUtils is SocketConfig { keccak256( abi.encodePacked( toBytes32Format(address(this)), - transmitter_, + toBytes32Format(transmitter_), payloadId_, executeParams_.deadline, executeParams_.callType, @@ -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/MessagePlugBase.sol b/contracts/protocol/base/MessagePlugBase.sol new file mode 100644 index 00000000..768a374e --- /dev/null +++ b/contracts/protocol/base/MessagePlugBase.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {PlugBase} from "./PlugBase.sol"; +import {ISwitchboard} from "../interfaces/ISwitchboard.sol"; +import {APP_GATEWAY_ID} from "../../utils/common/Constants.sol"; +import {toBytes32Format} from "../../utils/common/Converters.sol"; + +interface IMessageSwitchboard is ISwitchboard { + function registerSibling(uint32 chainSlug_, bytes32 siblingPlug_) external; + + function getSwitchboardFees(uint32 chainSlug_) external view returns (uint256); +} + +/// @title MessagePlugBase +/// @notice Abstract contract for message plugs in the updated protocol +/// @dev This contract contains helpers for socket connection, disconnection, and overrides +/// Uses constant appGatewayId (0xaaaaa) for all chains +abstract contract MessagePlugBase is PlugBase { + address public switchboard; + uint64 public switchboardId; + uint256 public triggerPrefix; + error NotSupported(); + + constructor(address socket_, uint64 switchboardId_) { + _setSocket(socket_); + switchboardId = switchboardId_; + switchboard = socket__.switchboardAddresses(switchboardId_); + socket__.connect(APP_GATEWAY_ID, switchboardId_); + + triggerPrefix = (uint256(socket__.chainSlug()) << 224) | (uint256(uint160(socket_)) << 64); + } + + /// @notice Initializes the socket with the new protocol + function initSocket(bytes32, address, uint64) external override socketInitializer { + revert("Not Supported"); + } + + /// @notice Registers a sibling plug for a specific chain + /// @param chainSlug_ Chain slug of the sibling chain + /// @param siblingPlug_ Address of the sibling plug on the destination chain + function registerSibling(uint32 chainSlug_, address siblingPlug_) public { + // Call the switchboard to register the sibling + IMessageSwitchboard(switchboard).registerSibling(chainSlug_, toBytes32Format(siblingPlug_)); + } + + function getSocketFees(uint32 chainSlug_) public view returns (uint256) { + return IMessageSwitchboard(switchboard).getSwitchboardFees(chainSlug_); + } + + function getNextTriggerId(uint32 chainSlug_) public view returns (bytes32) { + return + bytes32( + (uint256(chainSlug_) << 224) | + (uint256(uint160(address(socket__))) << 64) | + (uint256(socket__.triggerCounter()) << 16) + ); + } +} diff --git a/contracts/protocol/base/PlugBase.sol b/contracts/protocol/base/PlugBase.sol index 3bd4c160..1190d065 100644 --- a/contracts/protocol/base/PlugBase.sol +++ b/contracts/protocol/base/PlugBase.sol @@ -9,11 +9,22 @@ 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; + // TODO: why it does not have a switchboardId field if it is used in the _connectSocket function? + // should it not be saved is same way as appGatewayId? + + // event emitted when plug is disconnected event ConnectorPlugDisconnected(); /// @notice Modifier to ensure only the socket can call the function @@ -33,18 +44,22 @@ abstract contract PlugBase is IPlug { /// @notice Connects the plug to the app gateway and switchboard /// @param appGatewayId_ The app gateway id /// @param socket_ The socket address - /// @param switchboard_ The switchboard address - function _connectSocket(bytes32 appGatewayId_, address socket_, address switchboard_) internal { + /// @param switchboardId_ The switchboard id + function _connectSocket( + bytes32 appGatewayId_, + address socket_, + uint64 switchboardId_ + ) internal { _setSocket(socket_); appGatewayId = appGatewayId_; - socket__.connect(appGatewayId_, switchboard_); + // connect to the app gateway and switchboard + socket__.connect(appGatewayId_, switchboardId_); } /// @notice Disconnects the plug from the socket function _disconnectSocket() internal { - (, address switchboard) = socket__.getPlugConfig(address(this)); - socket__.connect(bytes32(0), switchboard); + socket__.disconnect(); emit ConnectorPlugDisconnected(); } @@ -55,16 +70,23 @@ 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_, - address switchboard_ + uint64 switchboardId_ ) external virtual socketInitializer { - _connectSocket(appGatewayId_, socket_, switchboard_); + _connectSocket(appGatewayId_, socket_, switchboardId_); } } diff --git a/contracts/protocol/interfaces/ICCTPSwitchboard.sol b/contracts/protocol/interfaces/ICCTPSwitchboard.sol new file mode 100644 index 00000000..cbf8894d --- /dev/null +++ b/contracts/protocol/interfaces/ICCTPSwitchboard.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "./ISwitchboard.sol"; +import {ExecuteParams, CCTPExecutionParams, CCTPBatchParams} from "../../utils/common/Structs.sol"; + +/** + * @title ISwitchboard + * @dev The interface for a switchboard contract that is responsible for verification of payloads if the correct + * digest is executed. + */ +interface ICCTPSwitchboard is ISwitchboard { + /** + * @notice Syncs out a payload to the remote chains + * @param payloadId_ The unique identifier for the payload + * @param remoteChainSlugs_ The remote chain slugs + */ + function syncOut(bytes32 payloadId_, uint32[] calldata remoteChainSlugs_) external; + + /** + * @notice Handles the receive message + * @param sourceDomain The source domain + * @param sender The sender + * @param messageBody The message body + */ + function handleReceiveMessage( + uint32 sourceDomain, + bytes32 sender, + bytes calldata messageBody + ) external returns (bool); + + /** + * @notice Proves the remote executions + * @param previousPayloadIds_ The previous payload ids + * @param currentPayloadId_ The current payload id + * @param transmitterSignature_ The transmitter signature + * @param executeParams_ The execute parameters + */ + function proveRemoteExecutions( + bytes32[] calldata previousPayloadIds_, + bytes32 currentPayloadId_, + bytes calldata transmitterSignature_, + ExecuteParams calldata executeParams_ + ) external; + + /** + * @notice Verifies 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_, + bytes32 payloadId_ + ) external; +} diff --git a/contracts/protocol/interfaces/IMessageHandler.sol b/contracts/protocol/interfaces/IMessageHandler.sol new file mode 100644 index 00000000..cdc4764e --- /dev/null +++ b/contracts/protocol/interfaces/IMessageHandler.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +/** + * @title IMessageHandler + * @notice Handles messages on destination forwarded from IReceiver + */ +interface IMessageHandler { + /** + * @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 + */ + function handleReceiveMessage( + uint32 sourceDomain, + bytes32 sender, + bytes calldata messageBody + ) external returns (bool); +} diff --git a/contracts/protocol/interfaces/IMessageTransmitter.sol b/contracts/protocol/interfaces/IMessageTransmitter.sol new file mode 100644 index 00000000..a00626f0 --- /dev/null +++ b/contracts/protocol/interfaces/IMessageTransmitter.sol @@ -0,0 +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 be18836e..f67160a4 100644 --- a/contracts/protocol/interfaces/IPlug.sol +++ b/contracts/protocol/interfaces/IPlug.sol @@ -9,10 +9,11 @@ interface IPlug { /// @notice Initializes the socket /// @param appGatewayId_ The app gateway id /// @param socket_ The socket address - /// @param switchboard_ The switchboard address - function initSocket(bytes32 appGatewayId_, address socket_, address switchboard_) external; + /// @param switchboardId_ The switchboard id + 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 74dfe535..166c0f88 100644 --- a/contracts/protocol/interfaces/ISocket.sol +++ b/contracts/protocol/interfaces/ISocket.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {ExecuteParams, TransmissionParams} from "../../utils/common/Structs.sol"; +import {ExecuteParams, TransmissionParams, ExecutionStatus} from "../../utils/common/Structs.sol"; /** * @title ISocket @@ -26,16 +26,22 @@ 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 switchboard 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, address switchboard); + event PlugConnected(address plug, bytes32 appGatewayId, uint64 switchboardId); + + /** + * @notice emits the config set by a plug for a remoteChainSlug + * @param plug The address of plug on current chain + */ + event PlugDisconnected(address plug); /** * @notice emits the payload details when a new payload arrives at outbound * @param triggerId trigger id - * @param switchboard switchboard address + * @param switchboardId switchboard id * @param plug local plug address * @param overrides params, for specifying details like fee pool chain, fee pool token and max fees if required * @param payload the data which will be used by contracts on chain @@ -43,14 +49,18 @@ interface ISocket { event AppGatewayCallRequested( bytes32 triggerId, bytes32 appGatewayId, - bytes32 switchboard, + uint64 switchboardId, bytes32 plug, bytes overrides, bytes payload ); /** - * @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_, @@ -59,21 +69,62 @@ interface ISocket { /** * @notice sets the config specific to the plug - * @param appGatewayId_ address of plug present at sibling chain - * @param switchboard_ the address 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_, address switchboard_) external; + function connect(bytes32 appGatewayId_, uint64 switchboardId_) external; /** - * @notice registers a switchboard for the socket + * @notice Disconnects Plug from Socket */ - function registerSwitchboard() external; + function disconnect() external; /** - * @notice returns the config for given `plugAddress_` and `siblingChainSlug_` - * @param plugAddress_ address of plug present at current chain + * @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_ 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, address switchboard); + ) 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 dfd146ac..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,11 +15,12 @@ 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( ExecuteParams calldata executeParams_, - address switchboard_, + uint64 switchboardId_, bytes32 digest_, bytes calldata proof_, bytes calldata transmitterSignature_, 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 4f1095ea..f462cd18 100644 --- a/contracts/protocol/interfaces/ISwitchboard.sol +++ b/contracts/protocol/interfaces/ISwitchboard.sol @@ -16,9 +16,32 @@ interface ISwitchboard { function allowPayload(bytes32 digest_, bytes32 payloadId_) external view returns (bool); /** - * @notice Attests a payload - * @param digest_ The digest of the payload - * @param proof_ The proof of the payload + * @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 + * @param overrides_ Overrides for the trigger */ - function attest(bytes32 digest_, bytes calldata proof_) external; + function processTrigger( + address plug_, + bytes32 triggerId_, + bytes calldata payload_, + bytes calldata overrides_ + ) external payable; + + /** + * @notice Gets the transmitter for a given payload + * @notice Switchboard are required to implement this function to allow for the verification of the transmitters + * @param sender_ The sender of the payload + * @param payloadId_ The payload ID + * @param transmitterSignature_ The transmitter signature + * @return The transmitter address + */ + function getTransmitter( + address sender_, + bytes32 payloadId_, + bytes calldata transmitterSignature_ + ) external view returns (address); } diff --git a/contracts/protocol/switchboard/CCTPSwitchboard.sol b/contracts/protocol/switchboard/CCTPSwitchboard.sol new file mode 100644 index 00000000..63b39411 --- /dev/null +++ b/contracts/protocol/switchboard/CCTPSwitchboard.sol @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "./FastSwitchboard.sol"; +import {ISocket} from "../interfaces/ISocket.sol"; +import {ExecuteParams, ExecutionStatus, CCTPExecutionParams, CCTPBatchParams} from "../../utils/common/Structs.sol"; +import {IMessageTransmitter} from "../interfaces/IMessageTransmitter.sol"; +import {IMessageHandler} from "../interfaces/IMessageHandler.sol"; + +contract CCTPSwitchboard is FastSwitchboard, IMessageHandler { + struct RemoteEndpoint { + bytes32 remoteAddress; + uint32 remoteDomain; + } + IMessageTransmitter public immutable messageTransmitter; + + // remoteChainSlug => remoteEndpoint + mapping(uint32 => RemoteEndpoint) public chainSlugToRemoteEndpoint; + // remoteDomain => remoteEndpoint + mapping(uint32 => RemoteEndpoint) public domainToRemoteEndpoint; + + mapping(bytes32 => bool) public isSyncedOut; + mapping(bytes32 => bytes32) public remoteExecutedDigests; + mapping(bytes32 => bool) public isRemoteExecuted; + + error RemoteExecutionNotFound(); + error PrevBatchDigestHashMismatch(); + error NotAttested(); + error NotExecuted(); + error InvalidSender(); + error OnlyMessageTransmitter(); + + constructor( + uint32 chainSlug_, + ISocket socket_, + address owner_, + address messageTransmitter_ + ) FastSwitchboard(chainSlug_, socket_, owner_) { + messageTransmitter = IMessageTransmitter(messageTransmitter_); + } + + function allowPacket(bytes32 digest_, bytes32 payloadId_) external view returns (bool) { + // digest has enough attestations and is remote executed + return isAttested[digest_] && isRemoteExecuted[payloadId_]; + } + + function syncOut(bytes32 payloadId_, uint32[] calldata remoteChainSlugs_) external { + bytes32 digest = socket__.payloadIdToDigest(payloadId_); + // not attested + if (digest == bytes32(0) || !isAttested[digest]) revert NotAttested(); + + // already synced out + if (isSyncedOut[digest]) return; + isSyncedOut[digest] = true; + + // not executed + ExecutionStatus isExecuted = socket__.payloadExecuted(payloadId_); + if (isExecuted != ExecutionStatus.Executed) revert NotExecuted(); + + bytes memory message = abi.encode(payloadId_, digest); + for (uint256 i = 0; i < remoteChainSlugs_.length; i++) { + RemoteEndpoint memory endpoint = chainSlugToRemoteEndpoint[remoteChainSlugs_[i]]; + messageTransmitter.sendMessage(endpoint.remoteDomain, endpoint.remoteAddress, message); + } + } + + function handleReceiveMessage( + uint32 sourceDomain, + bytes32 sender, + bytes calldata messageBody + ) external returns (bool) { + if (msg.sender != address(messageTransmitter)) revert OnlyMessageTransmitter(); + if (domainToRemoteEndpoint[sourceDomain].remoteAddress != sender) revert InvalidSender(); + + (bytes32 payloadId, bytes32 digest) = abi.decode(messageBody, (bytes32, bytes32)); + remoteExecutedDigests[payloadId] = digest; + return true; + } + + function verifyAttestations(bytes[] calldata messages, bytes[] calldata attestations) public { + for (uint256 i = 0; i < messages.length; i++) { + messageTransmitter.receiveMessage(messages[i], attestations[i]); + } + } + + function proveRemoteExecutions( + bytes32[] calldata previousPayloadIds_, + bytes32 payloadId_, + bytes calldata transmitterSignature_, + ExecuteParams calldata executeParams_ + ) public { + // Calculate prevBatchDigestHash from stored remoteExecutedDigests + bytes32 prevBatchDigestHash = bytes32(0); + for (uint256 i = 0; i < previousPayloadIds_.length; i++) { + if (remoteExecutedDigests[previousPayloadIds_[i]] == bytes32(0)) + revert RemoteExecutionNotFound(); + prevBatchDigestHash = keccak256( + abi.encodePacked(prevBatchDigestHash, remoteExecutedDigests[previousPayloadIds_[i]]) + ); + } + // Check if the calculated prevBatchDigestHash matches the one in executeParams_ + if (prevBatchDigestHash != executeParams_.prevBatchDigestHash) + revert PrevBatchDigestHashMismatch(); + + address transmitter = _recoverSigner( + keccak256(abi.encode(address(socket__), payloadId_)), + transmitterSignature_ + ); + + // Construct current digest + (bytes32 appGatewayId, ) = socket__.getPlugConfig(executeParams_.target); + bytes32 constructedDigest = _createDigest( + transmitter, + payloadId_, + appGatewayId, + executeParams_ + ); + + // Verify the constructed digest matches the stored one + if (!isAttested[constructedDigest]) revert NotAttested(); + isRemoteExecuted[payloadId_] = true; + } + + /** + * @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 + */ + function _createDigest( + address transmitter_, + bytes32 payloadId_, + bytes32 appGatewayId_, + ExecuteParams calldata executeParams_ + ) internal view returns (bytes32) { + return + keccak256( + abi.encode( + address(socket__), + transmitter_, + payloadId_, + executeParams_.deadline, + executeParams_.callType, + executeParams_.gasLimit, + executeParams_.value, + executeParams_.payload, + executeParams_.target, + appGatewayId_, + executeParams_.prevBatchDigestHash, + executeParams_.extraData + ) + ); + } + + function addRemoteEndpoint( + uint32 remoteChainSlug_, + bytes32 remoteAddress_, + uint32 remoteDomain_ + ) external onlyOwner { + chainSlugToRemoteEndpoint[remoteChainSlug_] = RemoteEndpoint({ + remoteAddress: remoteAddress_, + remoteDomain: remoteDomain_ + }); + domainToRemoteEndpoint[remoteDomain_] = RemoteEndpoint({ + remoteAddress: remoteAddress_, + remoteDomain: remoteDomain_ + }); + } + + function attestVerifyAndProveExecutions( + CCTPExecutionParams calldata execParams_, + CCTPBatchParams calldata cctpParams_, + bytes32 payloadId_ + ) external { + attest(execParams_.digest, execParams_.proof); + verifyAttestations(cctpParams_.messages, cctpParams_.attestations); + proveRemoteExecutions( + cctpParams_.previousPayloadIds, + payloadId_, + execParams_.transmitterSignature, + execParams_.executeParams + ); + } +} diff --git a/contracts/protocol/switchboard/FastSwitchboard.sol b/contracts/protocol/switchboard/FastSwitchboard.sol index 27d915fe..3995a380 100644 --- a/contracts/protocol/switchboard/FastSwitchboard.sol +++ b/contracts/protocol/switchboard/FastSwitchboard.sol @@ -40,7 +40,7 @@ contract FastSwitchboard is SwitchboardBase { * @param proof_ proof from watcher * @notice we are attesting a payload uniquely identified with digest. */ - function attest(bytes32 digest_, bytes calldata proof_) external { + function attest(bytes32 digest_, bytes calldata proof_) public virtual { if (isAttested[digest_]) revert AlreadyAttested(); address watcher = _recoverSigner( @@ -61,7 +61,13 @@ contract FastSwitchboard is SwitchboardBase { return isAttested[digest_]; } - function registerSwitchboard() external onlyOwner { - socket__.registerSwitchboard(); - } + /** + * @inheritdoc ISwitchboard + */ + function processTrigger( + address plug_, + bytes32 triggerId_, + bytes calldata payload_, + bytes calldata overrides_ + ) external payable virtual {} } diff --git a/contracts/protocol/switchboard/MessageSwitchboard.sol b/contracts/protocol/switchboard/MessageSwitchboard.sol new file mode 100644 index 00000000..549634eb --- /dev/null +++ b/contracts/protocol/switchboard/MessageSwitchboard.sol @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "./SwitchboardBase.sol"; +import {WATCHER_ROLE} from "../../utils/common/AccessRoles.sol"; +import {toBytes32Format} from "../../utils/common/Converters.sol"; +import {createPayloadId} from "../../utils/common/IdUtils.sol"; +import {DigestParams} from "../../utils/common/Structs.sol"; +import {WRITE, APP_GATEWAY_ID} from "../../utils/common/Constants.sol"; + +/** + * @title MessageSwitchboard contract + * @dev This contract implements a message switchboard that enables payload attestations from watchers + */ +contract MessageSwitchboard is SwitchboardBase { + // used to track if watcher have attested a payload + // payloadId => isAttested + mapping(bytes32 => bool) public isAttested; + + // sibling mappings for outbound journey + // chainSlug => siblingSocket + mapping(uint32 => bytes32) public siblingSockets; + // chainSlug => siblingSwitchboard + mapping(uint32 => bytes32) public siblingSwitchboards; + // chainSlug => address => siblingPlug + mapping(uint32 => mapping(address => bytes32)) public siblingPlugs; + + // payload counter for generating unique payload IDs + uint40 public payloadCounter; + + // switchboard fees mapping: chainSlug => fee amount + mapping(uint32 => uint256) public switchboardFees; + + // Error emitted when a payload is already attested by watcher. + error AlreadyAttested(); + // Error emitted when watcher is not valid + error WatcherNotFound(); + // Error emitted when sibling not found + error SiblingNotFound(); + // Error emitted when invalid target verification + error InvalidTargetVerification(); + // Error emitted when msg.value is not equal to switchboard fees + value + error InvalidMsgValue(); + + // Event emitted when watcher attests a payload + event Attested(bytes32 payloadId, bytes32 digest, address watcher); + // Event emitted when trigger is processed + event TriggerProcessed( + uint32 dstChainSlug, + uint256 switchboardFees, + bytes32 digest, + DigestParams digestParams + ); + // Event emitted when sibling is registered + event SiblingRegistered(uint32 chainSlug, address plugAddress, bytes32 siblingPlug); + + // Event emitted when sibling config is set + event SiblingConfigSet(uint32 chainSlug, uint256 fee, bytes32 socket, bytes32 switchboard); + // Event emitted when switchboard fees are set + event SwitchboardFeesSet(uint32 chainSlug, uint256 feeAmount); + + /** + * @dev Constructor function for the MessageSwitchboard contract + * @param chainSlug_ Chain slug of the chain where the contract is deployed + * @param socket_ Socket contract address + * @param owner_ Owner of the contract + */ + constructor( + uint32 chainSlug_, + ISocket socket_, + address owner_ + ) SwitchboardBase(chainSlug_, socket_, owner_) {} + + /** + * @dev Function to register sibling addresses for a chain (admin only) + * @param chainSlug_ Chain slug of the sibling chain + * @param socket_ Sibling socket address + * @param switchboard_ Sibling switchboard address + */ + function setSiblingConfig( + uint32 chainSlug_, + uint256 fee_, + bytes32 socket_, + bytes32 switchboard_ + ) external onlyOwner { + siblingSockets[chainSlug_] = socket_; + siblingSwitchboards[chainSlug_] = switchboard_; + switchboardFees[chainSlug_] = fee_; + + emit SiblingConfigSet(chainSlug_, fee_, socket_, switchboard_); + } + + /** + * @dev Function for plugs to register their own siblings + * @param chainSlug_ Chain slug of the sibling chain + * @param siblingPlug_ Sibling plug address + */ + function registerSibling(uint32 chainSlug_, bytes32 siblingPlug_) external { + if ( + siblingSockets[chainSlug_] == bytes32(0) || + siblingSwitchboards[chainSlug_] == bytes32(0) + ) { + revert SiblingNotFound(); + } + + // Register the sibling for the calling plug + siblingPlugs[chainSlug_][msg.sender] = siblingPlug_; + emit SiblingRegistered(chainSlug_, msg.sender, siblingPlug_); + } + + /** + * @dev Function to process trigger and create payload + * @param plug_ Source plug address + * @param triggerId_ Trigger ID from socket + * @param payload_ Payload data + * @param overrides_ Override parameters including dstChainSlug and gasLimit + */ + function processTrigger( + address plug_, + bytes32 triggerId_, + bytes calldata payload_, + bytes calldata overrides_ + ) external payable override { + (uint32 dstChainSlug, uint256 gasLimit, uint256 value) = abi.decode( + overrides_, + (uint32, uint256, uint256) + ); + _validateSibling(dstChainSlug, plug_); + if (switchboardFees[dstChainSlug] + value < msg.value) revert InvalidMsgValue(); + + (DigestParams memory digestParams, bytes32 digest) = _createDigestAndPayloadId( + dstChainSlug, + plug_, + gasLimit, + value, + triggerId_, + payload_ + ); + + emit TriggerProcessed(dstChainSlug, switchboardFees[dstChainSlug], digest, digestParams); + } + + function _validateSibling(uint32 dstChainSlug_, address plug_) internal view { + bytes32 dstSocket = siblingSockets[dstChainSlug_]; + bytes32 dstSwitchboard = siblingSwitchboards[dstChainSlug_]; + bytes32 dstPlug = siblingPlugs[dstChainSlug_][plug_]; + + if (dstSocket == bytes32(0) || dstSwitchboard == bytes32(0) || dstPlug == bytes32(0)) { + revert SiblingNotFound(); + } + } + + function _createDigestAndPayloadId( + uint32 dstChainSlug_, + address plug_, + uint256 gasLimit_, + uint256 value_, + bytes32 triggerId_, + bytes calldata payload_ + ) internal returns (DigestParams memory digestParams, bytes32 digest) { + uint160 payloadPointer = (uint160(chainSlug) << 120) | + (uint160(uint64(uint256(triggerId_))) << 80) | + payloadCounter++; + + bytes32 payloadId = createPayloadId(payloadPointer, switchboardId, dstChainSlug_); + + digestParams = DigestParams({ + socket: siblingSockets[dstChainSlug_], + transmitter: bytes32(0), + payloadId: payloadId, + deadline: block.timestamp + 3600, + callType: WRITE, + gasLimit: gasLimit_, + value: value_, + payload: payload_, + target: siblingPlugs[dstChainSlug_][plug_], + appGatewayId: APP_GATEWAY_ID, + prevBatchDigestHash: triggerId_, + extraData: abi.encode(chainSlug, toBytes32Format(plug_)) + }); + digest = _createDigest(digestParams); + } + + /** + * @dev Function to attest a payload with enhanced verification + * @param digest_ Full un-hashed digest parameters + * @param proof_ proof from watcher + * @notice Enhanced attestation that verifies target with srcChainSlug and srcPlug + */ + function attest(DigestParams calldata digest_, bytes calldata proof_) public { + (uint32 srcChainSlug, bytes32 srcPlug) = abi.decode(digest_.extraData, (uint32, bytes32)); + if (siblingPlugs[srcChainSlug][address(uint160(uint256(digest_.target)))] != srcPlug) { + revert InvalidTargetVerification(); + } + bytes32 digest = _createDigest(digest_); + address watcher = _recoverSigner( + keccak256(abi.encodePacked(toBytes32Format(address(this)), chainSlug, digest)), + proof_ + ); + if (!_hasRole(WATCHER_ROLE, watcher)) revert WatcherNotFound(); + + if (isAttested[digest]) revert AlreadyAttested(); + isAttested[digest] = true; + + emit Attested(digest_.payloadId, digest, watcher); + } + + /** + * @inheritdoc ISwitchboard + */ + function allowPayload(bytes32 digest_, bytes32) external view override returns (bool) { + // digest has enough attestations + return isAttested[digest_]; + } + + /** + * @dev Function to set switchboard fees for a specific chain (admin only) + * @param chainSlug_ Chain slug for which to set the fee + * @param feeAmount_ Fee amount in wei + */ + function setSwitchboardFees(uint32 chainSlug_, uint256 feeAmount_) external onlyOwner { + switchboardFees[chainSlug_] = feeAmount_; + emit SwitchboardFeesSet(chainSlug_, feeAmount_); + } + + /** + * @dev Function to get switchboard fees for a specific chain + * @param chainSlug_ Chain slug for which to get the fee + * @return feeAmount Fee amount in wei + */ + function getSwitchboardFees(uint32 chainSlug_) external view returns (uint256 feeAmount) { + return switchboardFees[chainSlug_]; + } + + /** + * @dev Internal function to create digest from parameters + */ + function _createDigest(DigestParams memory digest_) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked( + digest_.socket, + digest_.transmitter, + digest_.payloadId, + digest_.deadline, + digest_.callType, + digest_.gasLimit, + digest_.value, + digest_.payload, + digest_.target, + digest_.appGatewayId, + digest_.prevBatchDigestHash, + digest_.extraData + ) + ); + } +} diff --git a/contracts/protocol/switchboard/SwitchboardBase.sol b/contracts/protocol/switchboard/SwitchboardBase.sol index 99e3a607..c8a3bc1d 100644 --- a/contracts/protocol/switchboard/SwitchboardBase.sol +++ b/contracts/protocol/switchboard/SwitchboardBase.sol @@ -11,11 +11,15 @@ 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; + /** * @dev Constructor of SwitchboardBase * @param chainSlug_ Chain slug of deployment chain @@ -27,6 +31,35 @@ 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, + bytes32 payloadId_, + bytes calldata transmitterSignature_ + ) external view returns (address transmitter) { + transmitter = transmitterSignature_.length > 0 + ? _recoverSigner( + // TODO: use api encode packed + keccak256(abi.encode(address(socket__), payloadId_)), + transmitterSignature_ + ) + : address(0); + } + /// @notice Recovers the signer from the signature /// @param digest_ The digest of the payload /// @param signature_ The signature of the watcher 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/Constants.sol b/contracts/utils/common/Constants.sol index 6634a270..b6fbf440 100644 --- a/contracts/utils/common/Constants.sol +++ b/contracts/utils/common/Constants.sol @@ -13,6 +13,7 @@ bytes4 constant SCHEDULE = bytes4(keccak256("SCHEDULE")); bytes32 constant CALLBACK = keccak256("CALLBACK"); bytes32 constant FAST = keccak256("FAST"); +bytes32 constant CCTP = keccak256("CCTP"); uint256 constant PAYLOAD_SIZE_LIMIT = 24_500; uint16 constant MAX_COPY_BYTES = 2048; // 2KB @@ -24,3 +25,6 @@ uint32 constant CHAIN_SLUG_SOLANA_DEVNET = 10000002; bytes32 constant TOKEN_ACCOUNT = keccak256("TokenAccount"); bytes32 constant MINT_ACCOUNT = keccak256("MintAccount"); + +// Constant appGatewayId used on all chains +bytes32 constant APP_GATEWAY_ID = 0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcdef; 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/contracts/utils/common/IdUtils.sol b/contracts/utils/common/IdUtils.sol index 6490ad04..8482df03 100644 --- a/contracts/utils/common/IdUtils.sol +++ b/contracts/utils/common/IdUtils.sol @@ -1,22 +1,20 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.22; +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; /// @notice Creates a payload ID from the given parameters -/// @param requestCount_ The request count -/// @param batchCount_ The batch count -/// @param payloadCount_ The payload count -/// @param switchboard_ The switchboard address +/// @param payloadPointer_ The payload pointer +/// @param switchboardId_ The switchboard id /// @param chainSlug_ The chain slug /// @return The created payload ID function createPayloadId( - uint40 requestCount_, - uint40 batchCount_, - uint40 payloadCount_, - bytes32 switchboard_, + uint160 payloadPointer_, + uint64 switchboardId_, uint32 chainSlug_ ) pure returns (bytes32) { return - keccak256( - abi.encodePacked(requestCount_, batchCount_, payloadCount_, chainSlug_, switchboard_) + bytes32( + (uint256(chainSlug_) << 224) | + (uint256(switchboardId_) << 160) | + uint256(payloadPointer_) ); } diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 8aa9796a..c10b953a 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -56,19 +56,15 @@ struct AppGatewayConfig { uint32 chainSlug; } // Plug config: -// struct PlugConfig { -// bytes32 appGatewayId; -// address switchboard; -// } struct PlugConfigGeneric { bytes32 appGatewayId; - bytes32 switchboard; + uint64 switchboardId; } // Plug config: struct PlugConfigEvm { bytes32 appGatewayId; - address switchboard; + uint64 switchboardId; } //trigger: @@ -89,9 +85,7 @@ struct PromiseReturnData { // AM struct ExecuteParams { bytes4 callType; - uint40 requestCount; - uint40 batchCount; - uint40 payloadCount; + uint160 payloadPointer; uint256 deadline; uint256 gasLimit; uint256 value; @@ -105,7 +99,7 @@ struct TransmissionParams { uint256 socketFees; address refundAddress; bytes extraData; - bytes transmitterSignature; + bytes transmitterProof; } struct WatcherMultiCallParams { @@ -136,7 +130,7 @@ struct UserCredits { // digest: struct DigestParams { bytes32 socket; - address transmitter; + bytes32 transmitter; bytes32 payloadId; uint256 deadline; bytes4 callType; @@ -174,10 +168,8 @@ struct QueueParams { } struct PayloadParams { - uint40 requestCount; - uint40 batchCount; - uint40 payloadCount; bytes4 callType; + uint160 payloadPointer; address asyncPromise; address appGateway; bytes32 payloadId; @@ -210,6 +202,21 @@ struct RequestParams { bytes onCompleteData; } +struct CCTPExecutionParams { + ExecuteParams executeParams; + bytes32 digest; + bytes proof; + bytes transmitterSignature; + address refundAddress; +} + +struct CCTPBatchParams { + bytes32[] previousPayloadIds; + uint32[] nextBatchRemoteChainSlugs; + bytes[] messages; + bytes[] attestations; +} + /********* Solana payloads *********/ /** Solana write payload - SolanaInstruction **/ diff --git a/deployments/dev_addresses.json b/deployments/dev_addresses.json index 6e0444a6..53fbdc36 100644 --- a/deployments/dev_addresses.json +++ b/deployments/dev_addresses.json @@ -1,44 +1,315 @@ { + "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": "0xcA99D298B5290558660b4D5C1019Be145FaB6020", + "AddressResolverImpl": "0x39b5D3FBBa1BC28438e25955aaB412C7576eCd61", + "AsyncDeployer": "0xd608e1345281dE0675e2Cc1E8D0B31aD167618Ad", + "AsyncDeployerImpl": "0x2F0E83Fcd03A191D280598c33d278AF8A7e9076a", + "AuctionManager": "0xED848E9e0CCA0868484353B529E04861Fd8F04Bd", + "AuctionManagerImpl": "0x2752caa4060bC744216515c247C54Ae5bB873DF2", + "Configurations": "0xf50A9785aef5ADeA0659609e9FF1de8578aF0b4f", + "ConfigurationsImpl": "0xa1780f9F81090737267ccd3A5663E058AfE73A49", + "DeployForwarder": "0xffF606007317cb7a1CC4C701d62C38c7734dfb15", + "DeployForwarderImpl": "0x69e3Dc5667f7413039fE3bFd335660A99DA869A9", + "ERC1967Factory": "0x4f1Cd0CdBc7EA445b8B34Af8844fA4D4B5f48b79", + "FeesManager": "0xbCFf8224d89f0b4e9B14c4356720439111BAC2bC", + "FeesManagerImpl": "0x62FB943442E577901Ad42Da5c64aaf850B43049c", + "FeesPool": "0x13A3018920c7b56B20dd34E29C298121025E6de4", + "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": { - "ContractFactoryPlug": "0x7b9928b01272b915050aDfcba7e0a11b22271BAd", - "FastSwitchboard": "0x2974E94c0d1323D3A24f7B4F924fbdB325Be1aa3", - "FeesPlug": "0xaFD76cADB518E7e5131991Fe4403e00297916957", - "Socket": "0xb7378ae43b135988C8a83dfD1AcD71Ff39381396", - "SocketBatcher": "0x60541d31Fda60163480CAb486be3762b5793B650", - "startBlock": 159641867 - }, - "7625382": { - "AddressResolver": "0x8161cDBa2d2fCE66307254AAC1d42966D4F5353E", - "AddressResolverImpl": "0x91e548d87768313C03da8405D01171b83912c430", - "AsyncDeployer": "0x025b308371dC1C5e337527f96BE46Ba6A12c774A", - "AsyncDeployerImpl": "0x80CFbD3B6134Fb2D2B7d21FC132a9F7c115e7B72", - "AuctionManager": "0xA40aFA1632328D84226084a4539B3869D2B68e28", - "AuctionManagerImpl": "0x42109F6212765ABeb589f9b2c14Bee4b8DB3e638", - "Configurations": "0x60185198097df249B504D5A164323eBF42B3764d", - "ConfigurationsImpl": "0x0d2646fC08af29A7799Af435c5ABBA1b020C4dC7", - "DeployForwarder": "0xdC51D652B8c3cCB3cAAB9C1E2704fD4D62E76433", - "DeployForwarderImpl": "0xCe95fca954a0BF43c299c79d5152f2c164C02b7A", - "ERC1967Factory": "0xb0364Fd8f158071831ac87E7EE2C792Ab509a524", - "FeesManager": "0x09F824Eae77f71279d73Ae24FEb2163FCe88B25D", - "FeesManagerImpl": "0x5b460B29750648f6D569Ed57139967BE589174F8", - "FeesPool": "0xc20Be67ef742202dc93A78aa741E7C3715eA1DFd", - "PromiseResolver": "0xcfFda1dF8668266E6A77809EcA9CCA8A632ecaF3", - "ReadPrecompile": "0x254Dc9e0623426A79F02D2001E367cd32B50aaaA", - "RequestHandler": "0x1FE7527a8620374B3Fdb101bA1D56eC46EC9a24A", - "RequestHandlerImpl": "0x3d9578B252ed1F5A66348Cc40E482dacc32Ae790", - "SchedulePrecompile": "0x7D6F2A4aDf7e5Cfcf9627CC7FCA1d39fD19C07fc", - "startBlock": 8355289, - "Watcher": "0xD5b30DC89D96ee7303Dc2726491996B46089F693", - "WatcherImpl": "0x872bb254118a2210e3C491918133F2ab4D7Bc362", - "WritePrecompile": "0x10eaDbd1a2787ebbF4Abe9b6D79e669C0c8E8B26", - "WritePrecompileImpl": "0xD3aEb53da0a72788C16eAf5a23a5aBae6708C073" + "CCTPSwitchboard": "0x0355064bBb553A3765af498004749fB2e19284c0", + "CCTPSwitchboardId": "2", + "ContractFactoryPlug": "0x106A3205827D94d804CF7823B82E6742ED38D863", + "FastSwitchboard": "0x36620137587b544A8235C080067B3c439ae1c7d7", + "FastSwitchboardId": "1", + "FeesPlug": "0x9Fd89116E514142C04aE72824E2A7dC26F311655", + "MessageSwitchboard": "0x060493ac77c630f4d307Df9bb9bF32cE7462eb70", + "MessageSwitchboardId": "3", + "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": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124" + } }, "11155420": { - "ContractFactoryPlug": "0x0279A18d5FC235A92fB4ABd5F7e9258e78E27948", - "FastSwitchboard": "0x6b4EF1452265193798bfa3ef6D29421da9e7E222", - "FeesPlug": "0x5E175fD699E066D6536054198d57AF0De88C7c4E", - "Socket": "0xB260A4DD0952e9A5b5F6652019469F05Fb137dC5", - "SocketBatcher": "0xc320FC7b06D4491A9E7e6fa55a3305b12548519e", - "startBlock": 28568337 + "CCTPSwitchboard": "0x56EaDAC97B54C0c7979Bd620cad389eC3476dB43", + "CCTPSwitchboardId": "2", + "ContractFactoryPlug": "0x253be2E93EadAD9D2802D83A26eE62E911F1E3fe", + "FastSwitchboard": "0x2cC155961F225AbFF5e64F4a8f9C4f59b2339172", + "FastSwitchboardId": "1", + "FeesPlug": "0x83Ad3d17493Bdc31C60344021CA93E8dD3666A2A", + "MessageSwitchboard": "0x9efC6D7050eF4F5b12205A32ceE49F456FFB6FA8", + "MessageSwitchboardId": "3", + "Socket": "0x631f1E974442d6d51B626cE27d0D7629F1C0aB38", + "SocketBatcher": "0x4b2942C43579C3a9405887CDFA2F2048a5bE91EE", + "startBlock": 32643803, + "SUSDC": "0x40F2CfE35134141F809582ad121BF23522b5Dd22", + "SwitchboardIdToAddressMap": { + "1": "0x2cC155961F225AbFF5e64F4a8f9C4f59b2339172" + } } } diff --git a/deployments/dev_verification.json b/deployments/dev_verification.json index d491459d..fcc8908c 100644 --- a/deployments/dev_verification.json +++ b/deployments/dev_verification.json @@ -1,223 +1,1210 @@ { - "421614": [], - "7625382": [ + "1": [ [ - "0x5b460B29750648f6D569Ed57139967BE589174F8", - "FeesManager", - "contracts/evmx/fees/FeesManager.sol", - [] + "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x872bb254118a2210e3C491918133F2ab4D7Bc362", - "Watcher", - "contracts/evmx/watcher/Watcher.sol", - [] + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SUSDC", + "SUSDC" + ] ], [ - "0x7D6F2A4aDf7e5Cfcf9627CC7FCA1d39fD19C07fc", - "SchedulePrecompile", - "contracts/evmx/watcher/precompiles/SchedulePrecompile.sol", + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", [ - "0xD5b30DC89D96ee7303Dc2726491996B46089F693", - 86400, - { - "type": "BigNumber", - "hex": "0xe8d4a51000" - }, - { - "type": "BigNumber", - "hex": "0xe8d4a51000" - }, - 300 + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0x254Dc9e0623426A79F02D2001E367cd32B50aaaA", - "ReadPrecompile", - "contracts/evmx/watcher/precompiles/ReadPrecompile.sol", + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", [ - "0xD5b30DC89D96ee7303Dc2726491996B46089F693", - { - "type": "BigNumber", - "hex": "0xe8d4a51000" - }, - 300 + 1, + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0xD3aEb53da0a72788C16eAf5a23a5aBae6708C073", - "WritePrecompile", - "contracts/evmx/watcher/precompiles/WritePrecompile.sol", - [] + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124" + ] ], [ - "0xcfFda1dF8668266E6A77809EcA9CCA8A632ecaF3", - "PromiseResolver", - "contracts/evmx/watcher/PromiseResolver.sol", - ["0xD5b30DC89D96ee7303Dc2726491996B46089F693"] + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "Socket", + "contracts/protocol/Socket.sol", + [ + 1, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ], + "56": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x3d9578B252ed1F5A66348Cc40E482dacc32Ae790", - "RequestHandler", - "contracts/evmx/watcher/RequestHandler.sol", - [] + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SUSDC", + "SUSDC" + ] ], [ - "0x0d2646fC08af29A7799Af435c5ABBA1b020C4dC7", - "Configurations", - "contracts/evmx/watcher/Configurations.sol", - [] + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0xCe95fca954a0BF43c299c79d5152f2c164C02b7A", - "DeployForwarder", - "contracts/evmx/helpers/DeployForwarder.sol", - [] + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 56, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x42109F6212765ABeb589f9b2c14Bee4b8DB3e638", - "AuctionManager", - "contracts/evmx/AuctionManager.sol", - [] + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" + ] ], [ - "0xFa9B9271A4153eEABa76ae10bfc4F128651c25D7", - "Watcher", - "contracts/evmx/watcher/Watcher.sol", - [] + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "Socket", + "contracts/protocol/Socket.sol", + [ + 56, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ], + "100": [ + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x80CFbD3B6134Fb2D2B7d21FC132a9F7c115e7B72", - "AsyncDeployer", - "contracts/evmx/helpers/AsyncDeployer.sol", - [] + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SUSDC", + "SUSDC" + ] ], [ - "0x6975302A1B7aF61d89F85a13855B66D15221Cf8D", - "FeesManager", - "contracts/evmx/fees/FeesManager.sol", - [] + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x91e548d87768313C03da8405D01171b83912c430", - "AddressResolver", - "contracts/evmx/helpers/AddressResolver.sol", - [] + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 100, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0xb0364Fd8f158071831ac87E7EE2C792Ab509a524", - "ERC1967Factory", - "lib/solady/src/utils/ERC1967Factory.sol", - [] + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" + ] ], [ - "0x09A1A0A7BB8266171855871c4c0Af200a30922BE", - "WritePrecompile", - "contracts/evmx/watcher/precompiles/WritePrecompile.sol", - [] + "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" + ] ], [ - "0xDa60303321dc6aA8AeF32557bDe914008a3196eC", - "SchedulePrecompile", - "contracts/evmx/watcher/precompiles/SchedulePrecompile.sol", + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", [ - "0x60005b459Dc46D9a63bcb61D01Ad002130644a4F", - 86400, - { - "type": "BigNumber", - "hex": "0xe8d4a51000" - }, - { - "type": "BigNumber", - "hex": "0xe8d4a51000" - }, - 300 + 130, + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0xddeEDDD5F156123fDbf77B86A66A043568AEfcda", - "ReadPrecompile", - "contracts/evmx/watcher/precompiles/ReadPrecompile.sol", + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", [ - "0x60005b459Dc46D9a63bcb61D01Ad002130644a4F", - { - "type": "BigNumber", - "hex": "0xe8d4a51000" - }, - 300 + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38" ] ], [ - "0xb64D07B0dDb23cc54eE5EDe294E0cD15f08CC971", + "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" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 5000, + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "Socket", + "contracts/protocol/Socket.sol", + [ + 5000, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ], + "8453": [], + "14323": [ + [ + "0x41882aff9F7575473e5B6E613B371d04bdCCC728", "WritePrecompile", "contracts/evmx/watcher/precompiles/WritePrecompile.sol", [] ], [ - "0xF24B41A8C9F814d70FAD9E617CE32C74EcCB1A25", - "PromiseResolver", - "contracts/evmx/watcher/PromiseResolver.sol", - ["0x60005b459Dc46D9a63bcb61D01Ad002130644a4F"] + "0xdBDA5D873b120f1C5E0966BFA3C588dDBECc9072", + + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + [] + ], + [ + + "0x2Bc1E6d31B1eabe4a11286c08aa67eCA29A55cc3", + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + [] ], [ - "0x1fa5D12C7dC1F3615c28B842A6053f5f151230F8", + "0x751085cA028D2BCfC58Cee2514DeF1ed72c843cd", "RequestHandler", "contracts/evmx/watcher/RequestHandler.sol", + "0x2996bD0DCB7C349340715472518E76342AC31b1a", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", [] ], [ - "0x8d41aBDbE6Bbd208D68Dd4E671c4B72474525C7B", - "Configurations", - "contracts/evmx/watcher/Configurations.sol", + "0xEd2a3cd034D873096E40C7E2EfB0e5BE99bBbF7a", + "PromiseResolver", + "contracts/evmx/watcher/PromiseResolver.sol", + [ + "0xCeEc354B7784C667Bd661483Ae30C8d4eBA96e1d" + ] + ], + [ + "0x2ECF118De0d747980c5d934E78a5746B6b6fD441", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", [] ], [ - "0xD9CF47342c8a256fcD8B51aaABA810cd5D05F726", - "DeployForwarder", - "contracts/evmx/helpers/DeployForwarder.sol", + "0x751085cA028D2BCfC58Cee2514DeF1ed72c843cd", + "RequestHandler", + "contracts/evmx/watcher/RequestHandler.sol", [] ], [ - "0x1C40B5d5f6E9be1Ca4557d92cb7dba35e721a322", - "AuctionManager", - "contracts/evmx/AuctionManager.sol", + "0x9b962E99fbc77aF1733CdE3bC65F1Cd621d4FDEF", + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", [] ], [ - "0x812EcdF5366036B045e41Fe2dD95B72ecc26d8f3", + "0x52fEa0aBEe0CC6CBf46099a9886Ed0C123241fDc", "Watcher", "contracts/evmx/watcher/Watcher.sol", [] ], [ - "0xF4f5606189Bc091528680b2ca1c82167641d3cAf", - "AsyncDeployer", - "contracts/evmx/helpers/AsyncDeployer.sol", + "0x0f832af23F7fc3332396f73caAB2Fa44A6d3aFFC", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", [] + ] + ], + "43114": [ + [ + "0x302E258fe375A1da4d6B3F4Dd5208638A29bc409", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x255fBaD02F8f2Aae0Faf7074249a8701371890D2", - "FeesManager", - "contracts/evmx/fees/FeesManager.sol", - [] + "0x313397aE9B6c22AC0e00d039543AE425b1F1c039", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "SUSDC", + "SUSDC" + ] ], [ - "0x865A24Cf706027639124489e0dA2A28766efB96A", - "AddressResolver", - "contracts/evmx/helpers/AddressResolver.sol", - [] + "0x3aac37DC85C522c09A3DDdA44D181E6aCCD2f9F0", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", + "MessageSwitchboard", + "contracts/protocol/switchboard/MessageSwitchboard.sol", + [ + 43114, + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0xc20Be67ef742202dc93A78aa741E7C3715eA1DFd", - "FeesPool", - "contracts/evmx/fees/FeesPool.sol", - ["0xb62505feacC486e809392c65614Ce4d7b051923b"] + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "CCTPSwitchboard", + "contracts/protocol/switchboard/CCTPSwitchboard.sol", + [ + 43114, + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x8186359aF5F57FbB40c6b14A588d2A59C0C29880" + ] ], [ - "0x1b0F1aA38F8BBbe779A6C1fCe7e3Ff00380fa9CE", - "ERC1967Factory", - "lib/solady/src/utils/ERC1967Factory.sol", - [] + "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..468e3a76 --- /dev/null +++ b/deployments/prod_addresses.json @@ -0,0 +1,288 @@ +{ + "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", + "AuctionManager": "0xcd5e9029a73890A5A3146bAddd272D65ac11521c", + "AuctionManagerImpl": "0xB604FBcA01897315D2d62A346DBf29796A4825D9", + "Configurations": "0x71B89bA78B9431d4E984893cD6885d39AD6c3c7A", + "ConfigurationsImpl": "0x117c63A8c9a980ddC60B2bF2b4701C9267f66394", + "DeployForwarder": "0xb6E6e6FCd2636B83C443628f3f5e42cB5Fcd44fD", + "DeployForwarderImpl": "0xf05f680E0611b81eD0255A1Cd829540504765711", + "ERC1967Factory": "0x4023941D9AB563b1c4d447B3f2A9dd2F1eF19fCA", + "FeesManager": "0xB63ab15c208A16a0480036C06e8828A4682E0B34", + "FeesManagerImpl": "0x9f3CDba2262DF94e415E092A4228ee7E6846ea1b", + "FeesPool": "0x3B1f4ABA1667EeB992B623E7c6d119728cEd3b15", + "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..f95b60e8 --- /dev/null +++ b/deployments/prod_verification.json @@ -0,0 +1,146 @@ +{ + "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": [], + "42161": [], + "43114": [], + "57073": [], + "59144": [], + "80094": [], + "747474": [] +} diff --git a/deployments/stage_addresses.json b/deployments/stage_addresses.json index 8ba36507..48240cc0 100644 --- a/deployments/stage_addresses.json +++ b/deployments/stage_addresses.json @@ -1,73 +1,106 @@ { "10": { - "ContractFactoryPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", - "FastSwitchboard": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", - "FeesPlug": "0x501bdF8C7163ddD32172575C2836c5A7F556cbE7", - "Socket": "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", - "SocketBatcher": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", - "startBlock": 136685079 - }, - "43": { - "AddressResolver": "0x935b06902cA5C8bb4C76e18738561c294D377A93", - "AddressResolverImpl": "0xD1586EaaA0d473E6655c11A927cE4FbED648F3BF", - "AsyncDeployer": "0xECa623A443F21B705714D4A0f810d0A5D135FF6F", - "AsyncDeployerImpl": "0x1B0ea1b79B526dD3d5889Bb33Dbd24f790C23102", - "AuctionManager": "0xD044f27A9c5EE4f92EF0e38685276adFDF13E90E", - "AuctionManagerImpl": "0xC72BE9e639DA23570fa1eF2fF2cb7901a081916F", - "Configurations": "0x72f4C225B4B4f0F9608a50aEe17dA9e11dcb94b2", - "ConfigurationsImpl": "0x351De7e4275dA7f49F75363e4E7ea86Dfe050501", - "DeployForwarder": "0x5E9d1072B60D6c752B1593F5937393413372E5eF", - "DeployForwarderImpl": "0x1b7752F0039E80Aa38f7CF8b5d18798dD2ac1597", - "ERC1967Factory": "0x526796AC60e45CBB9b17c654C9447Baf160C084d", - "FeesManager": "0xA07208F9e7aE243F922317ab6604DC9F86822406", - "FeesManagerImpl": "0xC7A525A5D78610A9B7154315F3eC39Aa62594d1f", - "FeesPool": "0xe2054B575664dfDBD7a7FbAf2B12420ae88DE0FF", - "PromiseResolver": "0x38e24A2F157817b830F36A35b862F24B1494d1aD", - "ReadPrecompile": "0x39b5D3FBBa1BC28438e25955aaB412C7576eCd61", - "RequestHandler": "0x2E928C000bdC1f90716B05cE2D7182C9FA081d31", - "RequestHandlerImpl": "0xD38ae1a6C410c7681ac464bd60009198406035Ed", - "SchedulePrecompile": "0xb14a7763f09eCbd47bC5230D6170547a22834a82", - "startBlock": 8240883, - "Watcher": "0x4C846eCa55ad8cF19B9D5d906225da7b565174C1", - "WatcherImpl": "0x2920F4FB50343EF2b33096650cE234E8aF9E8556", - "WritePrecompile": "0x393007B660a00970b25E34FEd6506CE96120f8e2", - "WritePrecompileImpl": "0x0026c4736E57fE2817b53f6df1E0808c3a61984d" + "ContractFactoryPlug": "0xC559BABEbcD92278E91a545308190E4761efc347", + "FastSwitchboard": "0xD78f99D62BeaF0918bB0601C68EB537b6703Ce63", + "FastSwitchboardId": "1", + "FeesPlug": "0xA557EBE094F939ae6eE8F18c8F88D06182168786", + "Socket": "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", + "SocketBatcher": "0x06234dB2D69Ac158793a3ce59c3764422028E964", + "startBlock": 141180188, + "SUSDC": "0x6D54668ba18B425a1DbFC0BD720145c0aeE97f65", + "SwitchboardIdToAddressMap": { + "1": "0xD78f99D62BeaF0918bB0601C68EB537b6703Ce63" + } }, "8453": { - "ContractFactoryPlug": "0x3aac37DC85C522c09A3DDdA44D181E6aCCD2f9F0", - "FastSwitchboard": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", - "FeesPlug": "0x79EB309890F4A797816478dB7D9d57A1e63CeeC2", - "Socket": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", - "SocketBatcher": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", - "startBlock": 31089766 + "ContractFactoryPlug": "0x2e531e37FdccA3CFd427a593f53f326bd24b8142", + "FastSwitchboard": "0xd3009795fFDc64Ee0d23198772a58ca9e53EEd25", + "FastSwitchboardId": "1", + "FeesPlug": "0xFAF76924169cf58f239d02EC40a2a1eA9eaeb62E", + "Socket": "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9", + "SocketBatcher": "0x356DBc19C69832010f92c963a8Ded6b5f9deeaCe", + "startBlock": 35584928, + "SUSDC": "0x900Cf1914Adcee43Cb1A69c042ded801Cd5051Ef", + "SwitchboardIdToAddressMap": { + "1": "0xd3009795fFDc64Ee0d23198772a58ca9e53EEd25" + } + }, + "14323": { + "AddressResolver": "0xE4C438c46b9dB51e298A1F65151eDe8418be009A", + "AddressResolverImpl": "0x241532190C8b549Ebb4CE7624454A47c1cC97171", + "AsyncDeployer": "0x08c2DFE559288e9fBfB440E68033BE9BB666142E", + "AsyncDeployerImpl": "0x148182E16aaf2Fd6137D0eb335c3f6c8266e0936", + "AuctionManager": "0xa6610D1bFb6F791eDaeBAdFc43e2415f16844929", + "AuctionManagerImpl": "0x4B8B34e439EBAB00116B1b4C642923b6A227AdCa", + "Configurations": "0x6c289e8b8A8Ac6965440Cd23f2Db8C810f2336F9", + "ConfigurationsImpl": "0x30240731147d217Bf228EC68104eb8664A377c33", + "DeployForwarder": "0x015BB35B075FACBED756C9403c4A6BAfF37328D7", + "DeployForwarderImpl": "0xD4DB3AB70EBA19586132686fBD4928809c3e42B4", + "ERC1967Factory": "0x945300e92aA450A9aEf1d9FBA7b7Aee45622a082", + "FeesManager": "0xB3a34AB69B538d48311656a4b5df56A1423C0075", + "FeesManagerImpl": "0xF31EF92126D4f20799dEb3b2F17Cc64B3272DEc8", + "FeesPool": "0xC8d803B7c1719cdF21392405879D1B56398045C4", + "PromiseResolver": "0xD5225A5BC7ef3eAc6eb5255776fF5F007C95D03E", + "ReadPrecompile": "0xD059D6D64B9dbAE2e56F70CBEc9Af03fd41DaE35", + "RequestHandler": "0xEd8f50ddf6ba832c699b019Ed62f86e511b72d53", + "RequestHandlerImpl": "0x4f4655Bf2aDf5Ce1b58205942c77C9549bafbEd7", + "SchedulePrecompile": "0x62Be6a0eabce7Efb1B9BB065e36b85C63B2101c6", + "startBlock": 50623, + "Watcher": "0xdd4B3431472573dB6dB988E8746a118005328589", + "WatcherImpl": "0x8BB97CaF2B6C94d4f3988cdBC2db6e9eeF12D857", + "WritePrecompile": "0xE786f01425718D52F7C0753FbDF743b56704D31f", + "WritePrecompileImpl": "0xD3E77f10D63031111599CB32C957CA703ec479b8" }, "42161": { - "ContractFactoryPlug": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", - "FastSwitchboard": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", - "FeesPlug": "0x501bdF8C7163ddD32172575C2836c5A7F556cbE7", - "Socket": "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", - "SocketBatcher": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", - "startBlock": 343531414 + "ContractFactoryPlug": "0xae59BA0Bd0D92232B3B6304185448C9Fe5445f4d", + "FastSwitchboard": "0x7E33B305e12aD0E73B3aedBE67A53B7818732d7d", + "FastSwitchboardId": "1", + "FeesPlug": "0xfaf8a3f8f4221398F3eC765836e8BF4A3d975962", + "Socket": "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", + "SocketBatcher": "0x0d7994B4aAc7cbdFAFEAED0B9B51E7de0586ec6f", + "startBlock": 379484006, + "SUSDC": "0x0c17822dcC44F8202F176a4960EAC8da8FDbfCA5", + "SwitchboardIdToAddressMap": { + "1": "0x7E33B305e12aD0E73B3aedBE67A53B7818732d7d" + } }, "84532": { - "ContractFactoryPlug": "0x87cC19AedD434ebD3B74FfdC073CAeC7dC1E92EA", - "FastSwitchboard": "0x5aA84ffE5eCCB5263d1AE6aEd5682EAb39Bc7036", - "Socket": "0xa09217Cfc47F399C382E982778f6128685e13aD4", - "SocketBatcher": "0x80568677f2B092bd974657FE47Fc8531bfE5DBDC", - "startBlock": 26600215 + "ContractFactoryPlug": "0x24A6Da9bAa5ba4AE8AF411546429b7eD2B29aA48", + "FastSwitchboard": "0x7442C13842dC293fce94Bf86116068F8FF62Ecf9", + "FastSwitchboardId": "1", + "FeesPlug": "0x5cdcD147A01Fc29C20c2061a89faF01F20363A20", + "Socket": "0x4861c9EB83d8ba745a184E5a11a50B6be25e4dDb", + "SocketBatcher": "0x5132751743cD59DB406A043d9983984E52Ca2cD5", + "startBlock": 31095773, + "SUSDC": "0x99D946bB805adba0233956E475bf70ED09d50d40", + "SwitchboardIdToAddressMap": { + "1": "0x7442C13842dC293fce94Bf86116068F8FF62Ecf9" + } }, "421614": { - "ContractFactoryPlug": "0xe2904171afCeC319236cc051c81202677F7Aac1B", - "FastSwitchboard": "0x82833e5ac997F8f9c426949595d49702E3b08414", - "Socket": "0x468cA4bB968FD86eD752A7bD453c6869E27204f0", - "SocketBatcher": "0x977B8aB88A7159130457adA4b7078208Ab4fB111", - "startBlock": 159757112 + "ContractFactoryPlug": "0x5B6ed8Aaa52643d1d2d3409398e30b4eAdC767f2", + "FastSwitchboard": "0xE6be06b48c66BEbBa2114948a94cbE7eC7220a7e", + "FastSwitchboardId": "1", + "FeesPlug": "0x946f1113f19CD1d20465e62D8F5480C49253EbA3", + "Socket": "0x7aA47Ed012c185127edA67f533D91f44391bfC7C", + "SocketBatcher": "0x163272Ec38a16193a22400799D242e381fecEB42", + "startBlock": 194622586, + "SUSDC": "0xb5DbadA4f0F84420F0803089cD52Ef39876A061d", + "SwitchboardIdToAddressMap": { + "1": "0xE6be06b48c66BEbBa2114948a94cbE7eC7220a7e" + } }, "11155420": { - "ContractFactoryPlug": "0x705A4DD80D7203BF78AcAf3BA1851D1A80fA3d89", - "FastSwitchboard": "0x74388051BcCfA2D28690a98242A259aD94f2B1f3", - "Socket": "0x790E894C59d6275503e2Ff4ba95A42E38c071195", - "SocketBatcher": "0xa13B9b5e797e13316B23EfC01E506c8c0c2BFeF2", - "startBlock": 28583052 + "ContractFactoryPlug": "0xfC6E8e1aC27b5d61A03a64f383F51d3669F82165", + "FastSwitchboard": "0xbE5CB1cf4e049F124B868DebF15d9B04ce0817b3", + "FastSwitchboardId": "1", + "FeesPlug": "0xf0A01453C34759588e2Ebd42183F4FF122cc73ee", + "Socket": "0x26292db660fbeB0271E11aa4f1d2a2d0c57dc378", + "SocketBatcher": "0xaA02a6FdA809cF11c4e26a82AcfE7666204736A0", + "startBlock": 33078325, + "SUSDC": "0x3039AC5cC80C531c682045278f92439D740fa62B", + "SwitchboardIdToAddressMap": { + "1": "0xbE5CB1cf4e049F124B868DebF15d9B04ce0817b3" + } } } diff --git a/deployments/stage_verification.json b/deployments/stage_verification.json index 28d06e20..757bd77d 100644 --- a/deployments/stage_verification.json +++ b/deployments/stage_verification.json @@ -1,90 +1,157 @@ { - "10": [], - "43": [ + "10": [ [ - "0xC7A525A5D78610A9B7154315F3eC39Aa62594d1f", - "FeesManager", - "contracts/evmx/fees/FeesManager.sol", - [] + "0xC559BABEbcD92278E91a545308190E4761efc347", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x0026c4736E57fE2817b53f6df1E0808c3a61984d", - "WritePrecompile", - "contracts/evmx/watcher/precompiles/WritePrecompile.sol", - [] + "0x6D54668ba18B425a1DbFC0BD720145c0aeE97f65", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", + "SUSDC", + "SUSDC" + ] ], [ - "0x38e24A2F157817b830F36A35b862F24B1494d1aD", - "PromiseResolver", - "contracts/evmx/watcher/PromiseResolver.sol", - ["0x4C846eCa55ad8cF19B9D5d906225da7b565174C1"] + "0xA557EBE094F939ae6eE8F18c8F88D06182168786", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0xD38ae1a6C410c7681ac464bd60009198406035Ed", - "RequestHandler", - "contracts/evmx/watcher/RequestHandler.sol", - [] + "0xD78f99D62BeaF0918bB0601C68EB537b6703Ce63", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 10, + "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x351De7e4275dA7f49F75363e4E7ea86Dfe050501", - "Configurations", - "contracts/evmx/watcher/Configurations.sol", - [] + "0x06234dB2D69Ac158793a3ce59c3764422028E964", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7" + ] ], [ - "0x1b7752F0039E80Aa38f7CF8b5d18798dD2ac1597", - "DeployForwarder", - "contracts/evmx/helpers/DeployForwarder.sol", - [] + "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", + "Socket", + "contracts/protocol/Socket.sol", + [ + 10, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ], + "8453": [ + [ + "0x2e531e37FdccA3CFd427a593f53f326bd24b8142", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0xC72BE9e639DA23570fa1eF2fF2cb7901a081916F", - "AuctionManager", - "contracts/evmx/AuctionManager.sol", - [] + "0x900Cf1914Adcee43Cb1A69c042ded801Cd5051Ef", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9", + "SUSDC", + "SUSDC" + ] ], [ - "0x2920F4FB50343EF2b33096650cE234E8aF9E8556", - "Watcher", - "contracts/evmx/watcher/Watcher.sol", - [] + "0xFAF76924169cf58f239d02EC40a2a1eA9eaeb62E", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x1B0ea1b79B526dD3d5889Bb33Dbd24f790C23102", - "AsyncDeployer", - "contracts/evmx/helpers/AsyncDeployer.sol", - [] + "0xd3009795fFDc64Ee0d23198772a58ca9e53EEd25", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 8453, + "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0xbD22EDD6559B28614f44D1c768EC26491CDE1cDD", - "FeesManager", - "contracts/evmx/fees/FeesManager.sol", + "0x356DBc19C69832010f92c963a8Ded6b5f9deeaCe", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9" + ] + ], + [ + "0x6EF9c18c1A69417625f4Cb3c634124a71025C3A9", + "Socket", + "contracts/protocol/Socket.sol", + [ + 8453, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ], + "14323": [ + [ + "0x8BB97CaF2B6C94d4f3988cdBC2db6e9eeF12D857", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", [] ], [ - "0xD1586EaaA0d473E6655c11A927cE4FbED648F3BF", - "AddressResolver", - "contracts/evmx/helpers/AddressResolver.sol", + "0xD3E77f10D63031111599CB32C957CA703ec479b8", + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", [] ], [ - "0xe2054B575664dfDBD7a7FbAf2B12420ae88DE0FF", - "FeesPool", - "contracts/evmx/fees/FeesPool.sol", - ["0xb62505feacC486e809392c65614Ce4d7b051923b"] + "0x4f4655Bf2aDf5Ce1b58205942c77C9549bafbEd7", + "RequestHandler", + "contracts/evmx/watcher/RequestHandler.sol", + [] ], [ - "0x526796AC60e45CBB9b17c654C9447Baf160C084d", - "ERC1967Factory", - "lib/solady/src/utils/ERC1967Factory.sol", + "0xF31EF92126D4f20799dEb3b2F17Cc64B3272DEc8", + "FeesManager", + "contracts/evmx/fees/FeesManager.sol", [] ], [ - "0xFaa00117ED72CAE3399669a1E3FEedaF93020853", + "0x62Be6a0eabce7Efb1B9BB065e36b85C63B2101c6", "SchedulePrecompile", "contracts/evmx/watcher/precompiles/SchedulePrecompile.sol", [ - "0x03Aa399188E2741f89cc4265493DC5b544C52134", + "0xdd4B3431472573dB6dB988E8746a118005328589", 86400, { "type": "BigNumber", @@ -94,122 +161,333 @@ "type": "BigNumber", "hex": "0xe8d4a51000" }, - 300 + 3600 ] ], [ - "0xD38d0Dfd8e7d61B45Cce6Ec58E1Ec4c514c00e7F", + "0xD059D6D64B9dbAE2e56F70CBEc9Af03fd41DaE35", "ReadPrecompile", "contracts/evmx/watcher/precompiles/ReadPrecompile.sol", [ - "0x03Aa399188E2741f89cc4265493DC5b544C52134", + "0xdd4B3431472573dB6dB988E8746a118005328589", { "type": "BigNumber", "hex": "0xe8d4a51000" }, - 300 + 3600 ] ], [ - "0x702EfE1DfABc3963114E2356aFaF36c8b67CA961", + "0x01aDAb65E88b931860E63928096B16dA717b0f99", "WritePrecompile", "contracts/evmx/watcher/precompiles/WritePrecompile.sol", [] ], [ - "0xd0bd7837E66eEd7Be04C88354e75F5bA3cd19959", + "0xD5225A5BC7ef3eAc6eb5255776fF5F007C95D03E", "PromiseResolver", "contracts/evmx/watcher/PromiseResolver.sol", - ["0x03Aa399188E2741f89cc4265493DC5b544C52134"] + [ + "0xdd4B3431472573dB6dB988E8746a118005328589" + ] ], [ - "0x446C6B4086d1888cB15cF62735Bf57A4647E31A4", + "0x994DA55f4295B073f1D60B5074cc7f6cD7b11753", "RequestHandler", "contracts/evmx/watcher/RequestHandler.sol", [] ], [ - "0x2dc671B87d1A9dc7C1cf06C74C2db06673b31FFf", + "0x30240731147d217Bf228EC68104eb8664A377c33", "Configurations", "contracts/evmx/watcher/Configurations.sol", [] ], [ - "0x4ab75b62c0E2A09E428Ce73043C36d54c78C8CFd", + "0xD4DB3AB70EBA19586132686fBD4928809c3e42B4", "DeployForwarder", "contracts/evmx/helpers/DeployForwarder.sol", [] ], [ - "0xed8255097DFB0BB2135870bb342335dCC0C30e21", + "0x4B8B34e439EBAB00116B1b4C642923b6A227AdCa", + "AuctionManager", + "contracts/evmx/AuctionManager.sol", + [] + ], + [ + "0x529d72181F1FFDA70aD62737f348d4913D5826F6", "Watcher", "contracts/evmx/watcher/Watcher.sol", [] ], [ - "0xF946503b3bF14b39468AEce46E7Ce1A08404D109", + "0x148182E16aaf2Fd6137D0eb335c3f6c8266e0936", "AsyncDeployer", "contracts/evmx/helpers/AsyncDeployer.sol", [] ], [ - "0x69DD00B8a250e0A1bFF1b59db2EA99792faAbC66", - "FeesPool", - "contracts/evmx/fees/FeesPool.sol", - ["0xb62505feacC486e809392c65614Ce4d7b051923b"] + "0xBe2153E78cc02F87a2652390Bd49481dBc1ccd2E", + "FeesManager", + "contracts/evmx/fees/FeesManager.sol", + [] ], [ - "0xfddb38811a0774E66ABD5F3Ae960bFB7E7415029", - "AuctionManager", - "contracts/protocol/payload-delivery/AuctionManager.sol", + "0x241532190C8b549Ebb4CE7624454A47c1cC97171", + "AddressResolver", + "contracts/evmx/helpers/AddressResolver.sol", [] ], [ - "0xa07e38cAB46eAA358C3653C63219f1009e8F7789", - "DeliveryHelper", - "contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol", + "0x945300e92aA450A9aEf1d9FBA7b7Aee45622a082", + "ERC1967Factory", + "lib/solady/src/utils/ERC1967Factory.sol", [] + ] + ], + "42161": [ + [ + "0xae59BA0Bd0D92232B3B6304185448C9Fe5445f4d", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x9F10A0c71178dbD4d049f2C04fD0e34966134b9e", - "FeesManager", - "contracts/protocol/payload-delivery/FeesManager.sol", - [] + "0x0c17822dcC44F8202F176a4960EAC8da8FDbfCA5", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", + "SUSDC", + "SUSDC" + ] ], [ - "0xB423eE3bffc3604F96B59cF419C48AE05b8E9d0b", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol", - [] + "0xfaf8a3f8f4221398F3eC765836e8BF4A3d975962", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0xd69E17Ce715f49Cd2B16C64cf75201A56Ce0E90d", - "WatcherPrecompileConfig", - "contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol", - [] + "0x7E33B305e12aD0E73B3aedBE67A53B7818732d7d", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 42161, + "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x0e26C8CFCABC04c642696A625664553e2C183bbe", - "WatcherPrecompileLimits", - "contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol", - [] + "0x0d7994B4aAc7cbdFAFEAED0B9B51E7de0586ec6f", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C" + ] ], [ - "0x794b92C2Ade7D33Fb34d138B13014C63aB27CBC0", - "AddressResolver", - "contracts/protocol/AddressResolver.sol", - [] + "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", + "Socket", + "contracts/protocol/Socket.sol", + [ + 42161, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ], + "84532": [ + [ + "0x99D946bB805adba0233956E475bf70ED09d50d40", + "SUSDC", + "contracts/evmx/plugs/SUSDC.sol", + [ + 18, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x4861c9EB83d8ba745a184E5a11a50B6be25e4dDb", + "SUSDC", + "SUSDC" + ] ], [ - "0x98ea7A5601f203DE56d86BDCA69fC3019377D6B1", - "ERC1967Factory", - "lib/solady/src/utils/ERC1967Factory.sol", - [] + "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" + ] + ] + ], + "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" + ] ] ], - "8453": [], - "42161": [], - "84532": [], - "421614": [], - "11155420": [] + "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 9b8a496e..9ac8bc70 100644 --- a/foundry.toml +++ b/foundry.toml @@ -10,29 +10,27 @@ evm_version = 'paris' via_ir = false [labels] -0xE486D1Da5E250a268b5DA7eBc6AF3503bf8288DC = "AddressResolver" -0xf0CaA8D7b0d7be914D1801Ab2d95B1A75fCd4c01 = "AddressResolverImpl" -0x66d59d0bA711241785F1110C163448071c4Dd4Cc = "AsyncDeployer" -0xFe468C6506c212734A998848Da419E8041f47A64 = "AsyncDeployerImpl" -0xD2E1bF41B54ada70590873BE2409d5AD20341E82 = "AuctionManager" -0xfDDC7488C060Bf56107ca3A47918aEf06B59071d = "AuctionManagerImpl" -0x63cbD05da9bE1e37D3fC3eeB27da601FBbA199d1 = "Configurations" -0x36d42DFE5b2aeF21F7750947cEDc8c950f89fC6A = "ConfigurationsImpl" -0x1746948725fc2E2003511c34BE3509FA112A392E = "DeployForwarder" -0x227d6082Ea2D7Ee52b33F0d83B9411297ABf8ecE = "DeployForwarderImpl" -0xc9B4874dDA3AbB27DF56466DD650dd9B30b48986 = "ERC1967Factory" -0x686Be563fa9797aa7F66dCF73321cbd2F7a98874 = "FeesManager" -0x17F2aC81c4f1bee70D4c8ee9a3cb28E4e096De4f = "FeesManagerImpl" -0x9De353dD1131aB4e502590D3a1832652FA316268 = "FeesPool" -0xC570206ACBa112fC8d438235BF8cE31b3548aa96 = "ForwarderSolana" -0x3Fe4DDEd31943B90cB2AdcA39cE1f33Fa4Ab45d8 = "ForwarderSolanaImpl" -0xa0EEEC3D28acF5cF00181130aACf8A63d5F53F94 = "PromiseResolver" -0x78dFD826E6Aef751144987E1E25326De48879869 = "ReadPrecompile" -0xd183b5bf6d77E2D253a1230C2eAE34C18810Fbc3 = "RequestHandler" -0xD05D508704a8984a471E4FCdD57865D36c4A88B7 = "RequestHandlerImpl" -0xD832BFfE0c5e43Ef36dE8a2c50367d3f12DE09B7 = "SchedulePrecompile" -0x2d0fAB18450A7A2885a0130090BfA0B184F0b801 = "Watcher" -0xEEe9A8308b5b2A5814b35D10aeBCDeA760B9117f = "WatcherImpl" -0x1D179869F6079818a1DC852fEbf0890cc6DC558c = "WritePrecompile" -0x9461e4b96d5ceAa749E6Ee535979D1f3A83d5968 = "WritePrecompileImpl" -0xD3A6671C53c57133095b800a10024060a5B6Bf02 = "APP_GATEWAY" +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/disable-sb.ts b/hardhat-scripts/admin/disable-sb.ts index d327cfa2..edd24d1c 100644 --- a/hardhat-scripts/admin/disable-sb.ts +++ b/hardhat-scripts/admin/disable-sb.ts @@ -1,4 +1,4 @@ -import { constants, Wallet } from "ethers"; +import { Wallet } from "ethers"; import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { chains, EVMX_CHAIN_ID, mode } from "../config"; import { DeploymentAddresses, FAST_SWITCHBOARD_TYPE } from "../constants"; @@ -68,9 +68,9 @@ export const disableSBOnEVMx = async (chain: number, watcherSigner: Wallet) => { Contracts.Configurations, "switchboards", [chain, FAST_SWITCHBOARD_TYPE], - constants.AddressZero, + "0", "setSwitchboard", - [chain, FAST_SWITCHBOARD_TYPE, constants.AddressZero], + [chain, FAST_SWITCHBOARD_TYPE, 0], watcherSigner ); } catch (error) { diff --git a/hardhat-scripts/admin/disconnect.ts b/hardhat-scripts/admin/disconnect.ts index e5931ca5..d7f195a9 100644 --- a/hardhat-scripts/admin/disconnect.ts +++ b/hardhat-scripts/admin/disconnect.ts @@ -4,7 +4,7 @@ import { chains, EVMX_CHAIN_ID, getFeesPlugChains, mode } from "../config"; import { AppGatewayConfig, DeploymentAddresses, - ZERO_APP_GATEWAY_ID, + BYTES32_ZERO, } from "../constants"; import { checkIfAddressExists, @@ -12,6 +12,7 @@ import { getInstance, getSocketSigner, overrides, + toBytes32FormatHexString, } from "../utils"; import { getWatcherSigner, sendWatcherMultiCallWithNonce } from "../utils/sign"; import { isConfigSetOnEVMx, isConfigSetOnSocket } from "../utils"; @@ -51,21 +52,18 @@ async function disconnectPlug( // Check if config is already set if ( - await isConfigSetOnSocket(plug, socket, ZERO_APP_GATEWAY_ID, switchboard) + await isConfigSetOnSocket(plug, socket, BYTES32_ZERO, switchboard, chain) ) { console.log(`${plugContract} Socket Config on ${chain} already set!`); return; } // Connect the plug - const tx = await plug.functions["connectSocket"]( - ZERO_APP_GATEWAY_ID, - socket.address, - switchboard, - { ...(await overrides(chain as ChainSlug)) } - ); + const tx = await plug.functions["disconnectSocket"]({ + ...(await overrides(chain as ChainSlug)), + }); console.log( - `Connecting ${plugContract} on ${chain} to ${ZERO_APP_GATEWAY_ID} tx hash: ${tx.hash}` + `Disconnecting ${plugContract} on ${chain} to ${BYTES32_ZERO} tx hash: ${tx.hash}` ); await tx.wait(); } @@ -119,8 +117,8 @@ export const updateConfigEVMx = async () => { if (feesPlugChains.includes(chain) || !addresses[chain]) return; const addr = addresses[chain]!; - const appGatewayId = ZERO_APP_GATEWAY_ID; - const switchboard = constants.AddressZero; + const appGatewayId = BYTES32_ZERO; + const switchboardId = "0"; const plugContract = Contracts.FeesPlug; if (!addr[plugContract]) return; @@ -131,7 +129,7 @@ export const updateConfigEVMx = async () => { chain, addr[plugContract], appGatewayId, - switchboard + switchboardId ) ) { console.log(`Config already set on ${chain} for ${plugContract}`); @@ -139,9 +137,9 @@ export const updateConfigEVMx = async () => { appConfigs.push({ plugConfig: { appGatewayId: appGatewayId, - switchboard: switchboard, + switchboardId: switchboardId, }, - plug: addr[plugContract], + plug: toBytes32FormatHexString(addr[plugContract]), chainSlug: chain, }); } @@ -149,15 +147,17 @@ export const updateConfigEVMx = async () => { // update fees manager const currentFeesPlug = await feesManagerContract.feesPlugs(chain); - if (currentFeesPlug === constants.AddressZero) { + if (currentFeesPlug.toString() === BYTES32_ZERO.toString()) { console.log(`Fees plug already set on ${chain}`); return; } const tx = await feesManagerContract.functions["setFeesPlug"]( Number(chain), - constants.AddressZero, - { ...(await overrides(EVMX_CHAIN_ID as ChainSlug)) } + BYTES32_ZERO, + { + ...(await overrides(EVMX_CHAIN_ID as ChainSlug)), + } ); console.log(`Updating Fees Manager tx hash: ${tx.hash}`); await tx.wait(); diff --git a/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index 7ba92e79..f6eb1e45 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -3,99 +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]; - case DeploymentMode.DEV: - return [ChainSlug.ARBITRUM_SEPOLIA, ChainSlug.OPTIMISM_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]: 7625382, - [DeploymentMode.STAGE]: 43, - [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 = 300; // 5 minutes +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 @@ -108,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 71aa09e1..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"; @@ -7,8 +7,9 @@ export const IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; export const FAST_SWITCHBOARD_TYPE = id("FAST"); +export const CCTP_SWITCHBOARD_TYPE = id("CCTP"); -export const ZERO_APP_GATEWAY_ID = 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 66ddb4dd..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]: "0xc20Be67ef742202dc93A78aa741E7C3715eA1DFd", - [DeploymentMode.STAGE]: "0xe2054B575664dfDBD7a7FbAf2B12420ae88DE0FF", + [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 3e41d235..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; @@ -16,7 +14,7 @@ export interface WatcherMultiCallParams { export type AppGatewayConfig = { plugConfig: { appGatewayId: string; - switchboard: string; + switchboardId: string; }; plug: string; chainSlug: number; diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index 61049f3b..db8fa465 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -2,13 +2,21 @@ import { config } from "dotenv"; import { Contract, utils, Wallet } from "ethers"; import { formatEther } from "ethers/lib/utils"; import { ethers } from "hardhat"; -import { ChainAddressesObj, ChainId, ChainSlug, Contracts } from "../../src"; +import { + ChainAddressesObj, + ChainSlug, + ChainId, + Contracts, + MESSAGE_TRANSMITTER, +} from "../../src"; import { AUCTION_END_DELAY_SECONDS, BID_TIMEOUT, chains, EVMX_CHAIN_ID, - EXPIRY_TIME, + WRITE_EXPIRY_TIME, + READ_EXPIRY_TIME, + SCHEDULE_EXPIRY_TIME, getFeesPlugChains, logConfig, MAX_RE_AUCTION_COUNT, @@ -17,6 +25,7 @@ import { READ_FEES, SCHEDULE_CALLBACK_FEES, SCHEDULE_FEES_PER_SECOND, + skipEVMXDeployment, TRIGGER_FEES, WRITE_FEES, } from "../config/config"; @@ -25,6 +34,7 @@ import { FAST_SWITCHBOARD_TYPE, getFeePool, IMPLEMENTATION_SLOT, + FEE_MANAGER_WRITE_MAX_FEES, } from "../constants"; import { DeployParams, @@ -75,6 +85,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, @@ -146,6 +160,7 @@ const deployEVMxContracts = async () => { addressResolver.address, deployUtils.addresses[Contracts.FeesPool], EVMxOwner, + FEE_MANAGER_WRITE_MAX_FEES, FAST_SWITCHBOARD_TYPE, ], proxyFactory, @@ -224,7 +239,7 @@ const deployEVMxContracts = async () => { EVMxOwner, deployUtils.addresses[Contracts.Watcher], WRITE_FEES, - EXPIRY_TIME, + WRITE_EXPIRY_TIME, ], proxyFactory, deployUtils @@ -234,7 +249,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; @@ -248,7 +263,7 @@ const deployEVMxContracts = async () => { MAX_SCHEDULE_DELAY_SECONDS, SCHEDULE_FEES_PER_SECOND, SCHEDULE_CALLBACK_FEES, - EXPIRY_TIME, + SCHEDULE_EXPIRY_TIME, ], deployUtils ); @@ -349,17 +364,50 @@ const deploySocketContracts = async () => { ); deployUtils.addresses[contractName] = sb.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; - } + // 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/evmx/plugs/${contractName}.sol`, + [socket.address, socketOwner], + deployUtils + ); + deployUtils.addresses[contractName] = feesPlug.address; + + contractName = Contracts.SUSDC; + const susdcPlug: Contract = await getOrDeploy( + contractName, + contractName, + `contracts/evmx/plugs/${contractName}.sol`, + [18, socketOwner, socket.address, "SUSDC", "SUSDC"], + deployUtils + ); + deployUtils.addresses[contractName] = susdcPlug.address; contractName = Contracts.ContractFactoryPlug; const contractFactoryPlug: Contract = await getOrDeploy( @@ -423,6 +471,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, @@ -431,11 +483,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); @@ -462,7 +509,13 @@ const deployContractWithProxy = async ( const proxyAddress = receipt.events?.find((e) => e.event === "Deployed")?.args ?.proxy; deployUtils.addresses[contractName] = proxyAddress; - + console.log( + "Deployed proxy contract", + contractName, + proxyAddress, + "implementation:", + implementation.address + ); return deployUtils; }; diff --git a/hardhat-scripts/deploy/2.roles.ts b/hardhat-scripts/deploy/2.roles.ts index 79723cec..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"; @@ -16,6 +30,8 @@ export const REQUIRED_ROLES = { }, Chain: { FastSwitchboard: [ROLES.WATCHER_ROLE, ROLES.RESCUE_ROLE], + CCTPSwitchboard: [ROLES.WATCHER_ROLE, ROLES.RESCUE_ROLE], + MessageSwitchboard: [ROLES.WATCHER_ROLE, ROLES.RESCUE_ROLE], Socket: [ ROLES.GOVERNANCE_ROLE, ROLES.RESCUE_ROLE, @@ -43,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(); } } @@ -80,14 +96,15 @@ async function setRolesOnChain(chain: number, addresses: DeploymentAddresses) { for (const roleName of roles) { const targetAddress = - contractName === Contracts.FastSwitchboard && - roleName === ROLES.WATCHER_ROLE + [Contracts.FastSwitchboard, Contracts.CCTPSwitchboard].includes( + contractName as Contracts + ) && roleName === ROLES.WATCHER_ROLE ? watcher : signer.address; await setRoleForContract( contractName as Contracts, - contractAddress, + contractAddress.toString(), targetAddress, roleName, signer, @@ -126,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 b99d158d..4cc22acd 100644 --- a/hardhat-scripts/deploy/3.configureChains.ts +++ b/hardhat-scripts/deploy/3.configureChains.ts @@ -1,21 +1,29 @@ import { config as dotenvConfig } from "dotenv"; dotenvConfig(); -import { Contract, Signer, Wallet } from "ethers"; +import { Contract, Signer, Wallet, constants, ethers } from "ethers"; import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; -import { chains, EVMX_CHAIN_ID, MAX_MSG_VALUE_LIMIT, mode } from "../config"; +import { + chains, + EVMX_CHAIN_ID, + getFeesPlugChains, + MAX_MSG_VALUE_LIMIT, + mode, +} from "../config"; import { DeploymentAddresses, FAST_SWITCHBOARD_TYPE, getFeeTokens, } from "../constants"; import { + DeployParams, getAddresses, getInstance, + getReadOverrides, getSocketSigner, getWatcherSigner, overrides, - toBytes32Format, + storeAddresses, toBytes32FormatHexString, updateContractSettings, } from "../utils"; @@ -33,22 +41,58 @@ 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); - const signer: Wallet = getSocketSigner(chain as ChainSlug); + let deployUtils: DeployParams = { + addresses: chainAddresses, + mode, + signer: signer, + currentChainSlug: chain as ChainSlug, + }; + deployUtils.addresses.SwitchboardIdToAddressMap = {}; const socketContract = ( await getInstance(Contracts.Socket, chainAddresses[Contracts.Socket]) ).connect(signer); - await registerSb( + const fastSwitchboardId = await registerSb( chain, chainAddresses[Contracts.FastSwitchboard], signer, socketContract ); + deployUtils.addresses[Contracts.FastSwitchboardId] = + fastSwitchboardId.toString(); + deployUtils.addresses.SwitchboardIdToAddressMap[ + 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]; if (chainAddresses[Contracts.FeesPlug]) { await whitelistToken(chain, chainAddresses[Contracts.FeesPlug], signer); @@ -56,7 +100,30 @@ export const configureChains = async (addresses: DeploymentAddresses) => { await setMaxMsgValueLimit(chain); - await setOnchainContracts(chain, addresses); + await setOnchainContracts( + chain, + addresses, + fastSwitchboardId + // cctpSwitchboardId + ); + + // 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 storeAddresses(deployUtils.addresses, chain, mode); } }; @@ -77,19 +144,15 @@ export const setMaxMsgValueLimit = async (chain: number) => { async function setOnchainContracts( chain: number, - addresses: DeploymentAddresses + addresses: DeploymentAddresses, + fastSwitchboardId: string, + cctpSwitchboardId?: string ) { - console.log("Setting onchain contracts"); + console.log("Setting onchain contracts", chain); const signer: Wallet = getWatcherSigner(); const chainAddresses = addresses[chain] as ChainAddressesObj; - const switchboard = toBytes32FormatHexString( - chainAddresses[Contracts.FastSwitchboard] - ); const socket = toBytes32FormatHexString(chainAddresses[Contracts.Socket]); - const feesPlug = toBytes32FormatHexString( - chainAddresses[Contracts.FeesPlug]! - ); const contractFactory = toBytes32FormatHexString( chainAddresses[Contracts.ContractFactoryPlug] ); @@ -99,9 +162,22 @@ async function setOnchainContracts( Contracts.Configurations, "switchboards", [chain, FAST_SWITCHBOARD_TYPE], - switchboard, + fastSwitchboardId, "setSwitchboard", - [chain, FAST_SWITCHBOARD_TYPE, toBytes32Format(switchboard)], + [chain, FAST_SWITCHBOARD_TYPE, fastSwitchboardId], + signer + ); + + + // TODO: this was commented out if fee-deposit-hook but it is in old solana deployment scheme + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.Configurations, + "switchboards", + [chain, CCTP_SWITCHBOARD_TYPE], + cctpSwitchboardId, + "setSwitchboard", + [chain, CCTP_SWITCHBOARD_TYPE, cctpSwitchboardId], signer ); console.log("XXX Setting solana switchboard"); @@ -132,42 +208,183 @@ async function setOnchainContracts( Contracts.Configurations, "sockets", [chain], - socket, + toBytes32FormatHexString(socket), "setSocket", - [chain, socket], + [chain, toBytes32FormatHexString(socket)], signer ); - if (chainAddresses[Contracts.FeesPlug]) + if (chainAddresses[Contracts.FeesPlug]) { + const feesPlug = toBytes32FormatHexString( + chainAddresses[Contracts.FeesPlug]! + ); + await updateContractSettings( EVMX_CHAIN_ID, Contracts.FeesManager, "feesPlugs", [chain], - feesPlug, + toBytes32FormatHexString(feesPlug).toString(), "setFeesPlug", - [chain, toBytes32Format(feesPlug)], + [chain, toBytes32FormatHexString(feesPlug)], signer ); + } await updateContractSettings( EVMX_CHAIN_ID, Contracts.WritePrecompile, "contractFactoryPlugs", [chain], - contractFactory, + toBytes32FormatHexString(contractFactory).toString(), "setContractFactoryPlugs", - [chain, toBytes32Format(contractFactory)], + [chain, toBytes32FormatHexString(contractFactory)], signer ); } +// 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, sbAddress: string, signer: Wallet, socket: Contract -) => { +): Promise => { + let switchboardId: string = "0"; try { console.log("Registering switchboard"); // used fast switchboard here as all have same function signature @@ -178,17 +395,25 @@ const registerSb = async ( // send overrides while reading capacitor to avoid errors on mantle chain // some chains give balance error if gas price is used with from address as zero // therefore override from address as well - let sb = await socket.isValidSwitchboard(sbAddress, { + switchboardId = await socket.switchboardIds(sbAddress, { from: signer.address, + ...(await overrides(chain)), }); - if (Number(sb) == 0) { + if (Number(switchboardId) == 0) { const registerTx = await switchboard.registerSwitchboard({ ...(await overrides(chain)), }); console.log(`Registering Switchboard ${sbAddress}: ${registerTx.hash}`); await registerTx.wait(); + + switchboardId = await switchboard.switchboardId({ + ...(await overrides(chain)), + }); + console.log(`Switchboard ID: ${switchboardId}`); } + + return switchboardId; } catch (error) { throw error; } @@ -200,24 +425,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); - - const tokens = getFeeTokens(mode, chain); + // 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 { @@ -226,6 +460,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 e8b56731..af8db267 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,14 +13,19 @@ import { } from "../utils"; import { getWatcherSigner, sendWatcherMultiCallWithNonce } from "../utils/sign"; import { isConfigSetOnEVMx, isConfigSetOnSocket } from "../utils"; +import pLimit from "p-limit"; import { mockForwarderSolanaOnChainAddress32Bytes } from "./1.deploy"; -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); @@ -46,22 +50,30 @@ async function connectPlug( await getInstance(Contracts.Socket, addr[Contracts.Socket]) ).connect(socketSigner); - // Get switchboard and app gateway addresses - const switchboard = addr[Contracts.FastSwitchboard]; - checkIfAddressExists(switchboard, "Switchboard"); + // Get switchboard id and app gateway addresses + const switchboardId = addr[Contracts.FastSwitchboardId]; const appGatewayId = getAppGatewayId(plugContract, addresses); checkIfAppGatewayIdExists(appGatewayId, "AppGatewayId"); // Check if config is already set - if (await isConfigSetOnSocket(plug, socket, appGatewayId, switchboard)) { + 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, - switchboard, + switchboardId, { ...(await overrides(chain)) } ); console.log( @@ -70,24 +82,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 @@ -114,26 +139,23 @@ export const updateConfigEVMx = async () => { const addr = addresses[chain]!; for (const plugContract of plugs) { - const appGatewayId = getAppGatewayId(plugContract, addresses); - const switchboardBytes32Hex = toBytes32FormatHexString( - addr[Contracts.FastSwitchboard] - ); - const plugBytes32Hex = toBytes32FormatHexString(addr[plugContract]); - // checkIfAddressExists(switchboard, "Switchboard"); - checkIfAppGatewayIdExists(appGatewayId, "AppGatewayId"); - if (!addr[plugContract]) { console.log(`${plugContract} not found on ${chain}`); continue; } + const appGatewayId = getAppGatewayId(plugContract, addresses); + const switchboardId = addr[Contracts.FastSwitchboardId]; + const plugBytes32Hex = toBytes32FormatHexString(addr[plugContract]); + checkIfAppGatewayIdExists(appGatewayId, "AppGatewayId"); + if ( await isConfigSetOnEVMx( configurationsContract, chain, plugBytes32Hex, appGatewayId, - switchboardBytes32Hex + switchboardId ) ) { console.log(`Config already set on ${chain} for ${plugContract}`); @@ -142,7 +164,7 @@ export const updateConfigEVMx = async () => { appConfigs.push({ plugConfig: { appGatewayId: appGatewayId, - switchboard: switchboardBytes32Hex, + switchboardId: switchboardId, }, plug: plugBytes32Hex, chainSlug: chain, 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 279be8b1..4bbe3431 100644 --- a/hardhat-scripts/deploy/9.setupTransmitter.ts +++ b/hardhat-scripts/deploy/9.setupTransmitter.ts @@ -20,8 +20,9 @@ let transmitterAddress: string; export const main = async () => { console.log("Setting up transmitter..."); await init(); + await checkAndDepositCredits(transmitterAddress); + await checkAndDepositNative(transmitterAddress); await approveAuctionManager(); - await checkAndDepositCredits(); console.log("Transmitter setup complete!"); }; @@ -38,7 +39,6 @@ export const init = async () => { }; export const approveAuctionManager = async () => { - console.log("Approving auction manager"); const auctionManagerAddress = evmxAddresses[Contracts.AuctionManager]; const isAlreadyApproved = await feesManagerContract .connect(transmitterSigner) @@ -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/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/misc-scripts/getAttestations.ts b/hardhat-scripts/misc-scripts/getAttestations.ts new file mode 100644 index 00000000..dcdcc7be --- /dev/null +++ b/hardhat-scripts/misc-scripts/getAttestations.ts @@ -0,0 +1,95 @@ +import { ethers } from "ethers"; +import axios from "axios"; + +async function getAttestation(messageHash: string): Promise { + try { + const response = await axios.get( + `https://iris-api-sandbox.circle.com/v1/attestations/${messageHash}` + ); + console.log("messageHash", messageHash, "response", response.data); + if (response.data.status === "complete") { + return response.data.attestation; + } + return null; + } catch (error) { + return null; + } +} + +async function main() { + const args = process.argv.slice(2); + if (args.length !== 2) { + console.log("Usage: ts-node getAttestations.ts "); + process.exit(1); + } + + const [txHash, providerUrl] = args; + const provider = new ethers.providers.JsonRpcProvider(providerUrl); + + // Get transaction receipt + const receipt = await provider.getTransactionReceipt(txHash); + + // ABI for MessageSent event + const messageTransmitterInterface = new ethers.utils.Interface([ + "event MessageSent(bytes message)", + ]); + + // Filter logs for MessageSent event + const messageSentLogs = receipt.logs.filter((log) => { + try { + const parsedLog = messageTransmitterInterface.parseLog(log); + return parsedLog.name === "MessageSent"; + } catch { + return false; + } + }); + + if (messageSentLogs.length === 0) { + console.log("No MessageSent events found in transaction"); + process.exit(1); + } + + const messages: string[] = []; + const messageHashes: string[] = []; + const attestations: string[] = []; + + // Get messages and calculate hashes + for (const log of messageSentLogs) { + const parsedLog = messageTransmitterInterface.parseLog(log); + const message = parsedLog.args.message; + const messageHash = ethers.utils.keccak256(message); + + messages.push(message); + messageHashes.push(messageHash); + } + + // Poll for attestations + let complete = false; + while (!complete) { + complete = true; + + for (let i = 0; i < messageHashes.length; i++) { + if (!attestations[i]) { + const attestation = await getAttestation(messageHashes[i]); + if (attestation) { + attestations[i] = attestation; + } else { + complete = false; + } + } + } + + if (!complete) { + console.log("Waiting for attestations..."); + await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait 5 seconds + } + } + + console.log("\nMessages:", messages); + console.log("\nAttestations:", attestations); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/hardhat-scripts/s3Config/buildConfig.ts b/hardhat-scripts/s3Config/buildConfig.ts index 73bac889..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,8 +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); @@ -43,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 0172655f..ddd74a28 100644 --- a/hardhat-scripts/utils/appConfig.ts +++ b/hardhat-scripts/utils/appConfig.ts @@ -1,17 +1,22 @@ 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, - switchboard: 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() && - plugConfigRegistered.switchboard.toLowerCase() === switchboard.toLowerCase() + plugConfigRegistered.switchboardId.toString() === switchboardId ); }; @@ -20,14 +25,17 @@ export const isConfigSetOnEVMx = async ( chain: number, plug: string, appGatewayId: string, - switchboard: 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() && - plugConfigRegistered[1].toLowerCase() === switchboard.toLowerCase() + plugConfigRegistered[1].toString() === switchboardId.toString() ); }; diff --git a/hardhat-scripts/utils/deployUtils.ts b/hardhat-scripts/utils/deployUtils.ts index dd71525e..f96cc872 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; @@ -111,12 +113,12 @@ export const verify = async ( await run("verify:verify", { address, contract: `${path}:${contractName}`, - constructorArguments: args, + constructorArguments: args }); 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 +132,27 @@ 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 5d49ab6e..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, @@ -30,13 +55,39 @@ export const chainOverrides: { [ChainSlug.BASE]: { 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, + // type: 0, + // // gasLimit: 1_000_000_000, + // 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/utils/sign.ts b/hardhat-scripts/utils/sign.ts index 00afdcb4..b296d565 100644 --- a/hardhat-scripts/utils/sign.ts +++ b/hardhat-scripts/utils/sign.ts @@ -1,5 +1,5 @@ import { ethers } from "ethers"; -import { ChainSlug, Contracts } from "../../src"; +import { ChainSlug, Contracts, EVMxAddressesObj } from "../../src"; import { EVMX_CHAIN_ID, mode } from "../config/config"; import { getProviderFromChainSlug } from "./networks"; import { signWatcherMultiCallMessage } from "../../src/signer"; @@ -30,9 +30,9 @@ export const signWatcherMessage = async ( targetContractAddress: string, calldata: string ) => { - const addresses = getAddresses(mode); + const evmxAddresses = getAddresses(mode)[EVMX_CHAIN_ID] as EVMxAddressesObj; return await signWatcherMultiCallMessage( - addresses[EVMX_CHAIN_ID][Contracts.Watcher], + evmxAddresses[Contracts.Watcher] as string, EVMX_CHAIN_ID, targetContractAddress, calldata, @@ -44,11 +44,11 @@ export const sendWatcherMultiCallWithNonce = async ( targetContractAddress: string, calldata: string ) => { - const addresses = getAddresses(mode); + const evmxAddresses = getAddresses(mode)[EVMX_CHAIN_ID] as EVMxAddressesObj; const watcherContract = ( await getInstance( Contracts.Watcher, - addresses[EVMX_CHAIN_ID][Contracts.Watcher] + evmxAddresses[Contracts.Watcher] as string ) ).connect(getWatcherSigner()); const { nonce, signature } = await signWatcherMessage( @@ -62,6 +62,7 @@ export const sendWatcherMultiCallWithNonce = async ( nonce, signature, }; + // Call watcherMultiCall function with single call data return await watcherContract.watcherMultiCall([params], { ...(await overrides(EVMX_CHAIN_ID as ChainSlug)), diff --git a/hardhat-scripts/verify/verify.ts b/hardhat-scripts/verify/verify.ts index eaec585c..211a69d8 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,95 @@ 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)); + + // 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; + } - const chainParams: VerifyArgs[] = verificationParams[chain]; - let retryCount = 0; + const chainParams: VerifyArgs[] = verificationParams as VerifyArgs[]; + let retryCount = 0; - 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]); - } + 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 20f97d25..516882f1 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,60 +107,157 @@ 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-sepolia-optimistic.etherscan.io/api", - browserURL: "https://sepolia-optimism.etherscan.io/", + apiURL: "https://api.etherscan.io/v2/api?chainid=56", + browserURL: "https://bscscan.com/", }, }, { - network: "arbitrumTestnet", - chainId: ChainId.ARBITRUM_SEPOLIA, + network:HardhatChainName.MANTLE, + chainId: ChainSlugToId[ChainSlug.MANTLE], urls: { - apiURL: "https://api-sepolia.arbiscan.io/api", - browserURL: "https://sepolia.arbiscan.io/", + apiURL: "https://api.etherscan.io/v2/api?chainid=5000", + browserURL: "https://explorer.mantle.xyz/", }, }, { - network: "baseTestnet", - chainId: ChainId.BASE_SEPOLIA, + network:HardhatChainName.UNICHAIN, + chainId: ChainSlugToId[ChainSlug.UNICHAIN], urls: { - apiURL: "https://api-sepolia.basescan.org/api", - browserURL: "https://sepolia.basescan.org/", + apiURL: "https://api.etherscan.io/v2/api?chainid=130", + browserURL: "https://uniscan.xyz/", }, }, { - network: "base", - chainId: ChainId.BASE, + network:HardhatChainName.SONIC, + chainId: ChainId.SONIC, urls: { - apiURL: "https://api.basescan.org/api", - browserURL: "https://basescan.org/", - }, + apiURL: "https://api.etherscan.io/v2/api?chainid=146", + browserURL: "https://sonicscan.org" + } + }, + { + network:HardhatChainName.BERA, + chainId: ChainId.BERA, + urls: { + apiURL: "https://api.etherscan.io/v2/api?chainid=80094", + browserURL: "https://berascan.com/" + } + }, + { + network:HardhatChainName.KATANA, + chainId: ChainId.KATANA, + urls: { + apiURL: "https://api.etherscan.io/v2/api?chainid=747474", + browserURL: "https://katanascan.com/" + } + }, + { + network:HardhatChainName.INK, + chainId: ChainId.INK, + urls: { + apiURL: "https://explorer.inkonchain.com/api", + browserURL: "https://explorer.inkonchain.com/" + } + }, + { + network: "hyperevm", + chainId: ChainId.HYPEREVM, + urls: { + 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://evmx.cloud.blockscout.com/api", - browserURL: "https://evmx.cloud.blockscout.com/", + 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/" + } + }, + + + ], }, // This fully resolves paths for imports in the ./lib directory for Hardhat diff --git a/package.json b/package.json index 0dfa34ef..6732c0a5 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "publishConfig": { "access": "public" }, - "version": "1.1.32", + "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": "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", @@ -44,6 +47,7 @@ "hardhat-preprocessor": "0.1.4", "http-server": "^14.1.1", "path": "^0.12.7", + "pg": "^8.16.3", "pre-commit": "^1.2.2", "prettier": "^2.3.1", "prettier-plugin-solidity": "^1.4.1", @@ -52,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 new file mode 100644 index 00000000..6ebec144 --- /dev/null +++ b/script/helpers/TransferRemainingCredits.s.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {FeesManager} from "../../contracts/evmx/fees/FeesManager.sol"; +import {IAppGateway} from "../../contracts/evmx/interfaces/IAppGateway.sol"; + +contract TransferRemainingCredits is Script { + function run() external { + string memory rpc = vm.envString("EVMX_RPC"); + vm.createSelectFork(rpc); + + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + vm.startBroadcast(deployerPrivateKey); + FeesManager feesManager = FeesManager(payable(vm.envAddress("FEES_MANAGER"))); + address appGateway = vm.envAddress("APP_GATEWAY"); + address newAppGateway = vm.envAddress("NEW_APP_GATEWAY"); + + 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.balanceOf(appGateway); + console.log("Available fees:", availableFees); + bytes memory data = abi.encodeWithSignature( + "transferFrom(address,address,uint256)", + appGateway, + newAppGateway, + availableFees + ); + (bool success, ) = appGateway.call(data); + require(success, "Transfer failed"); + vm.stopBroadcast(); + } +} diff --git a/script/helpers/WithdrawRemainingCredits.s.sol b/script/helpers/WithdrawRemainingCredits.s.sol new file mode 100644 index 00000000..c53cf1ee --- /dev/null +++ b/script/helpers/WithdrawRemainingCredits.s.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {FeesManager} from "../../contracts/evmx/fees/FeesManager.sol"; + +contract WithdrawRemainingCredits is Script { + function run() external { + string memory rpc = vm.envString("EVMX_RPC"); + vm.createSelectFork(rpc); + + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + vm.startBroadcast(deployerPrivateKey); + FeesManager feesManager = FeesManager(payable(vm.envAddress("FEES_MANAGER"))); + address appGateway = vm.envAddress("APP_GATEWAY"); + + 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.balanceOf(appGateway); + console.log("Available fees:", availableFees); + feesManager.transferFrom(appGateway, vm.addr(deployerPrivateKey), availableFees); + + vm.stopBroadcast(); + } +} diff --git a/script/super-token-solana/DeployEVMSolanaApps.s.sol b/script/super-token-solana/DeployEVMSolanaApps.s.sol index cb080b09..4bfef359 100644 --- a/script/super-token-solana/DeployEVMSolanaApps.s.sol +++ b/script/super-token-solana/DeployEVMSolanaApps.s.sol @@ -23,7 +23,7 @@ contract DeployEVMSolanaApps is Script { // fill with correct values after deployment bytes32 solanaProgramId = vm.envBytes32("SOLANA_TARGET_PROGRAM"); - address forwarderSolanaAddress = 0xC570206ACBa112fC8d438235BF8cE31b3548aa96; + address forwarderSolanaAddress = 0x9bBb97c66be06458A63D11ff6025Fdad104DA285; // Setting fee payment on Arbitrum Sepolia uint256 fees = 10 ether; diff --git a/script/super-token-solana/EvmSolanaOnchainCalls.s.sol b/script/super-token-solana/EvmSolanaOnchainCalls.s.sol index 4487f437..6bc06955 100644 --- a/script/super-token-solana/EvmSolanaOnchainCalls.s.sol +++ b/script/super-token-solana/EvmSolanaOnchainCalls.s.sol @@ -253,7 +253,7 @@ contract EvmSolanaOnchainCalls is Script { bytes32 solanaTargetProgramId = vm.envBytes32("SOLANA_TARGET_PROGRAM"); // May be subject to change - bytes32[] memory accounts = new bytes32[](5); + bytes32[] memory accounts = new bytes32[](4); // accounts 0 - plug signer pda : aprk6EUeRofYzyABHXLKG8hqJ3GHGV7Uhzbu612UMBD accounts[0] = 0x08aa478d7031ac31e2a406e25f1e4dbd00bce5cbd428b7bf5e5b01abfd4b7da8; // accounts 1 - trigger counter pda : 4EYucSHVdCt5BK9N95peyVCi7weQTBoW5Tf3a2nQbRbf @@ -334,7 +334,7 @@ contract EvmSolanaOnchainCalls is Script { // accounts 4 - token programId: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA accounts[4] = 0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9; - bytes[] memory functionArguments = new bytes[](1); + bytes[] memory functionArguments = new bytes[](3); functionArguments[0] = abi.encode(order.srcAmount); uint256[] memory array = new uint256[](100); functionArguments[1] = abi.encode(array); @@ -346,12 +346,11 @@ contract EvmSolanaOnchainCalls is Script { }); functionArguments[2] = abi.encode(complexTestStruct); - string[] memory functionArgumentTypeNames = new string[](1); + string[] memory functionArgumentTypeNames = new string[](3); functionArgumentTypeNames[0] = "u64"; functionArgumentTypeNames[1] = "[u64;100]"; - functionArgumentTypeNames[ - 2 - ] = '{"ComplexTestStruct": {"name": "string","addr": "[u8;32]","isActive": "boolean","value": "u64"}}'; + functionArgumentTypeNames[2] = + '{"ComplexTestStruct": {"name": "string","addr": "[u8;32]","isActive": "boolean","value": "u64"}}'; bytes1[] memory accountFlags = new bytes1[](5); // superTokenConfigPda is not writable diff --git a/script/supertoken/DeployEVMxSuperTokenApp.s.sol b/script/supertoken/DeployEVMxSuperTokenApp.s.sol new file mode 100644 index 00000000..c09efdcc --- /dev/null +++ b/script/supertoken/DeployEVMxSuperTokenApp.s.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import "../../test/apps/app-gateways/super-token/SuperTokenAppGateway.sol"; +import {CCTP} from "../../contracts/utils/common/Constants.sol"; +// source .env && forge script script/supertoken/deployEVMxSuperTokenApp.s.sol --broadcast --skip-simulation --legacy --gas-price 0 +contract SuperTokenDeploy is Script { + function run() external { + address addressResolver = vm.envAddress("ADDRESS_RESOLVER"); + string memory rpc = vm.envString("EVMX_RPC"); + vm.createSelectFork(rpc); + + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + vm.startBroadcast(deployerPrivateKey); + + // Setting fee payment on Arbitrum Sepolia + uint256 fees = 1 ether; + + SuperTokenAppGateway gateway = new SuperTokenAppGateway( + addressResolver, + vm.addr(deployerPrivateKey), + fees, + SuperTokenAppGateway.ConstructorParams({ + name_: "SuperToken", + symbol_: "SUPER", + decimals_: 18, + initialSupplyHolder_: vm.addr(deployerPrivateKey), + initialSupply_: 1000000000000000000000000000 + }) + ); + + console.log("Contracts deployed:"); + console.log("SuperTokenAppGateway:", address(gateway)); + gateway.setSbType(CCTP); + } +} diff --git a/script/supertoken/TransferSuperToken.s.sol b/script/supertoken/TransferSuperToken.s.sol new file mode 100644 index 00000000..c1d39d2a --- /dev/null +++ b/script/supertoken/TransferSuperToken.s.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {SuperTokenAppGateway} from "../../test/apps/app-gateways/super-token/SuperTokenAppGateway.sol"; + +// source .env && forge script script/supertoken/TransferSuperToken.s.sol --broadcast --skip-simulation --legacy --gas-price 0 +contract TransferSuperToken is Script { + function run() external { + string memory socketRPC = vm.envString("EVMX_RPC"); + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.createSelectFork(socketRPC); + + SuperTokenAppGateway gateway = SuperTokenAppGateway(vm.envAddress("APP_GATEWAY")); + address forwarderArb = gateway.forwarderAddresses(gateway.superToken(), 421614); + address forwarderOpt = gateway.forwarderAddresses(gateway.superToken(), 11155420); + + SuperTokenAppGateway.TransferOrder memory transferOrder = SuperTokenAppGateway + .TransferOrder({ + srcToken: forwarderArb, + dstToken: forwarderOpt, + user: vm.addr(deployerPrivateKey), + srcAmount: 100, + deadline: block.timestamp + 1000000 + }); + + bytes memory encodedOrder = abi.encode(transferOrder); + bytes memory encodedPayload = abi.encodeWithSelector( + bytes4(keccak256("transfer(bytes)")), + encodedOrder + ); + console.logBytes(encodedPayload); + } +} 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 7a813356..1cb5a746 100644 --- a/src/enums.ts +++ b/src/enums.ts @@ -53,9 +53,14 @@ export enum Events { export enum Contracts { Socket = "Socket", FeesPlug = "FeesPlug", + SUSDC = "SUSDC", ContractFactoryPlug = "ContractFactoryPlug", FastSwitchboard = "FastSwitchboard", + FastSwitchboardId = "FastSwitchboardId", CCTPSwitchboard = "CCTPSwitchboard", + CCTPSwitchboardId = "CCTPSwitchboardId", + MessageSwitchboard = "MessageSwitchboard", + MessageSwitchboardId = "MessageSwitchboardId", SocketBatcher = "SocketBatcher", SocketFeeManager = "SocketFeeManager", AddressResolver = "AddressResolver", @@ -71,6 +76,7 @@ export enum Contracts { FeesPool = "FeesPool", AsyncDeployer = "AsyncDeployer", DeployForwarder = "DeployForwarder", + Forwarder = "Forwarder", ForwarderSolana = "ForwarderSolana", } @@ -91,3 +97,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 9ec27359..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, @@ -7,7 +7,7 @@ export const signWatcherMultiCallMessage = async ( calldata: string, signer: ethers.Signer ) => { - const signatureNonce = Date.now(); + const signatureNonce = getNonce(); const digest = ethers.utils.keccak256( ethers.utils.defaultAbiCoder.encode( ["address", "uint32", "uint256", "address", "bytes"], @@ -23,3 +23,9 @@ export const signWatcherMultiCallMessage = async ( const signature = await signer.signMessage(ethers.utils.arrayify(digest)); return { nonce: signatureNonce, signature }; }; + +export const getNonce = () => { + const randomId = uuidv4(); + const nonceHex = randomId.replace(/-/g, ""); + return "0x" + nonceHex; +}; diff --git a/src/types.ts b/src/types.ts index ba32e046..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,11 +19,17 @@ export type ChainAddressesObj = { Socket: string; SocketBatcher: string; FastSwitchboard: string; - CCTPSwitchboard: string; + CCTPSwitchboard?: string; + MessageSwitchboard?: string; + FastSwitchboardId: string; + CCTPSwitchboardId?: string; + MessageSwitchboardId?: string; ContractFactoryPlug: string; SocketFeesManager?: string; FeesPlug?: string; + SUSDC?: string; startBlock: number; + SwitchboardIdToAddressMap: { [switchboardId: string]: string }; }; export type EVMxAddressesObj = { @@ -47,9 +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 = { @@ -61,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/DigestTest.t.sol b/test/DigestTest.t.sol index 02ed6120..34fe1e1b 100644 --- a/test/DigestTest.t.sol +++ b/test/DigestTest.t.sol @@ -5,6 +5,7 @@ import "forge-std/Test.sol"; import {DigestParams} from "../contracts/utils/common/Structs.sol"; import "../contracts/utils/common/Constants.sol"; import "forge-std/console.sol"; +import {toBytes32Format} from "../contracts/utils/common/Converters.sol"; contract DigestTest is Test { function testCallType() public pure { @@ -45,11 +46,11 @@ contract DigestTest is Test { } function testDigest() public pure { - bytes32 expectedDigest = 0xc26b01718c6f97b51ad73743bb5b1ac2abb53966d15a2948f65db43b30cce1a1; + bytes32 expectedDigest = 0xd72bce33c4eb6d4615f2878fd0d0711ff78e080f0ac4a2240d224e859f7f8dc1; DigestParams memory inputDigestParams = DigestParams({ socket: 0x84815e8ca2f6dad7e12902c39a51bc72e13c48139b4fb10025d94e7abea2969c, - transmitter: 0x138e9840861C983DC0BB9b3e941FB7C0e9Ade320, + transmitter: toBytes32Format(0x138e9840861C983DC0BB9b3e941FB7C0e9Ade320), payloadId: 0x965c0b8c6c5c8dc6f433b34b72ecddcec35b2f36f700f50aed20a40366efa88a, deadline: 1750681840, callType: WRITE, diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 4f761381..6852d132 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -12,8 +12,11 @@ import "../contracts/evmx/interfaces/IForwarder.sol"; import "../contracts/protocol/Socket.sol"; import "../contracts/protocol/switchboard/FastSwitchboard.sol"; +import "../contracts/protocol/switchboard/CCTPSwitchboard.sol"; +import "../contracts/protocol/switchboard/MessageSwitchboard.sol"; import "../contracts/protocol/SocketBatcher.sol"; import "../contracts/protocol/SocketFeeManager.sol"; +import "../contracts/protocol/base/MessagePlugBase.sol"; import "../contracts/evmx/watcher/Watcher.sol"; import "../contracts/evmx/watcher/Configurations.sol"; @@ -32,6 +35,9 @@ 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"; @@ -50,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; @@ -63,19 +69,27 @@ contract SetupStore is Test { uint256 scheduleFeesPerSecond = 10000; uint256 triggerFees = 10000; uint256 socketFees = 0; + uint256 msgSbFees = 1000000000000000; // 0.001 ETH uint256 public watcherNonce; uint256 public payloadIdCounter; uint256 public triggerCounter; uint256 public asyncPromiseCounter; + uint32 public optCCTPDomain = 2; + uint32 public arbCCTPDomain = 3; struct SocketContracts { uint32 chainSlug; + uint256 triggerPrefix; Socket socket; SocketFeeManager socketFeeManager; FastSwitchboard switchboard; + CCTPSwitchboard cctpSwitchboard; + MessageSwitchboard messageSwitchboard; + CCTPMessageTransmitter cctpMessageTransmitter; SocketBatcher socketBatcher; ContractFactoryPlug contractFactoryPlug; FeesPlug feesPlug; + SUSDC susdcPlug; TestUSDC testUSDC; } SocketContracts public arbConfig; @@ -121,9 +135,6 @@ contract DeploySetup is SetupStore { optConfig = _deploySocket(optChainSlug); _configureChain(optChainSlug); - // 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)); @@ -144,8 +155,40 @@ contract DeploySetup is SetupStore { 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, + addressToBytes32(address(optConfig.cctpSwitchboard)), + optCCTPDomain + ); + optConfig.cctpSwitchboard.addRemoteEndpoint( + arbChainSlug, + addressToBytes32(address(arbConfig.cctpSwitchboard)), + arbCCTPDomain + ); + + arbConfig.messageSwitchboard.setSiblingConfig( + optChainSlug, + msgSbFees, + toBytes32Format(address(optConfig.socket)), + toBytes32Format(address(optConfig.messageSwitchboard)) + ); + optConfig.messageSwitchboard.setSiblingConfig( + arbChainSlug, + msgSbFees, + toBytes32Format(address(arbConfig.socket)), + toBytes32Format(address(arbConfig.messageSwitchboard)) + ); vm.stopPrank(); + // transfer eth to fees pool for native fee payouts + vm.deal(address(feesPool), 100000 ether); + _connectCorePlugs(); _setupTransmitter(); } @@ -158,21 +201,22 @@ 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)), plugConfig: PlugConfigGeneric({ appGatewayId: toBytes32Format(address(feesManager)), - switchboard: toBytes32Format(address(arbConfig.switchboard)) + switchboardId: arbConfig.switchboard.switchboardId() }) }); configs[1] = AppGatewayConfig({ @@ -180,7 +224,7 @@ contract DeploySetup is SetupStore { plug: toBytes32Format(address(optConfig.feesPlug)), plugConfig: PlugConfigGeneric({ appGatewayId: toBytes32Format(address(feesManager)), - switchboard: toBytes32Format(address(optConfig.switchboard)) + switchboardId: optConfig.switchboard.switchboardId() }) }); configs[2] = AppGatewayConfig({ @@ -188,7 +232,7 @@ contract DeploySetup is SetupStore { plug: toBytes32Format(address(arbConfig.contractFactoryPlug)), plugConfig: PlugConfigGeneric({ appGatewayId: toBytes32Format(address(writePrecompile)), - switchboard: toBytes32Format(address(arbConfig.switchboard)) + switchboardId: arbConfig.switchboard.switchboardId() }) }); configs[3] = AppGatewayConfig({ @@ -196,7 +240,23 @@ contract DeploySetup is SetupStore { plug: toBytes32Format(address(optConfig.contractFactoryPlug)), plugConfig: PlugConfigGeneric({ appGatewayId: toBytes32Format(address(writePrecompile)), - switchboard: toBytes32Format(address(optConfig.switchboard)) + 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() }) }); @@ -209,16 +269,30 @@ contract DeploySetup is SetupStore { function _deploySocket(uint32 chainSlug_) internal returns (SocketContracts memory) { // socket Socket socket = new Socket(chainSlug_, socketOwner, "test"); - + CCTPMessageTransmitter cctpMessageTransmitter = new CCTPMessageTransmitter( + chainSlug_, + address(0) + ); return SocketContracts({ chainSlug: chainSlug_, + triggerPrefix: (uint256(chainSlug_) << 224) | + (uint256(uint160(address(socket))) << 64), socket: socket, socketFeeManager: new SocketFeeManager(socketOwner, socketFees), switchboard: new FastSwitchboard(chainSlug_, socket, socketOwner), + cctpSwitchboard: new CCTPSwitchboard( + chainSlug_, + socket, + socketOwner, + address(cctpMessageTransmitter) + ), + messageSwitchboard: new MessageSwitchboard(chainSlug_, socket, socketOwner), + cctpMessageTransmitter: cctpMessageTransmitter, 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) }); } @@ -227,6 +301,8 @@ contract DeploySetup is SetupStore { SocketContracts memory socketConfig = getSocketConfig(chainSlug_); Socket socket = socketConfig.socket; FastSwitchboard switchboard = socketConfig.switchboard; + CCTPSwitchboard cctpSwitchboard = socketConfig.cctpSwitchboard; + MessageSwitchboard messageSwitchboard = socketConfig.messageSwitchboard; FeesPlug feesPlug = socketConfig.feesPlug; ContractFactoryPlug contractFactoryPlug = socketConfig.contractFactoryPlug; @@ -241,26 +317,32 @@ contract DeploySetup is SetupStore { switchboard.grantRole(WATCHER_ROLE, watcherEOA); switchboard.grantRole(RESCUE_ROLE, address(socketOwner)); + cctpSwitchboard.registerSwitchboard(); + cctpSwitchboard.grantRole(WATCHER_ROLE, watcherEOA); + + messageSwitchboard.registerSwitchboard(); + messageSwitchboard.grantRole(WATCHER_ROLE, watcherEOA); + feesPlug.grantRole(RESCUE_ROLE, address(socketOwner)); feesPlug.whitelistToken(address(socketConfig.testUSDC)); feesPlug.connectSocket( toBytes32Format(address(feesManager)), address(socket), - address(switchboard) + switchboard.switchboardId() ); contractFactoryPlug.grantRole(RESCUE_ROLE, address(socketOwner)); contractFactoryPlug.connectSocket( toBytes32Format(address(writePrecompile)), address(socket), - address(switchboard) + switchboard.switchboardId() ); - vm.stopPrank(); vm.startPrank(watcherEOA); configurations.setSocket(chainSlug_, toBytes32Format(address(socket))); - configurations.setSwitchboard(chainSlug_, FAST, toBytes32Format(address(switchboard))); + configurations.setSwitchboard(chainSlug_, FAST, switchboard.switchboardId()); + configurations.setSwitchboard(chainSlug_, CCTP, cctpSwitchboard.switchboardId()); // plugs feesManager.setFeesPlug(chainSlug_, toBytes32Format(address(feesPlug))); @@ -271,8 +353,15 @@ contract DeploySetup is SetupStore { chainSlug_, 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 { @@ -307,6 +396,7 @@ contract DeploySetup is SetupStore { address(addressResolver), address(feesPool), watcherEOA, + writeFees, FAST ) ); @@ -435,17 +525,17 @@ contract DeploySetup is SetupStore { function _createWatcherSignature( address contractAddress_, bytes memory data_ - ) internal returns (bytes memory) { + ) internal view returns (bytes memory) { bytes32 digest = keccak256( abi.encode(address(watcher), evmxSlug, watcherNonce, contractAddress_, data_) ); - return _createSignature(digest, watcherPrivateKey); + return createSignature(digest, watcherPrivateKey); } - function _createSignature( + function createSignature( bytes32 digest_, uint256 privateKey_ - ) internal pure returns (bytes memory sig) { + ) 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); @@ -496,45 +586,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), @@ -542,29 +646,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_), @@ -573,7 +675,7 @@ contract FeesSetup is DeploySetup { ); } - function approveAppGatewayWithSignature( + function approveWithSignature( address appGateway_, address user_, uint256 userPrivateKey_ @@ -587,13 +689,13 @@ contract FeesSetup is DeploySetup { ); // Sign with consumeFrom's private key - bytes memory signature = _createSignature(digest, userPrivateKey_); + bytes memory signature = createSignature(digest, userPrivateKey_); // Encode approval data 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, @@ -614,7 +716,7 @@ contract AuctionSetup is FeesSetup { function placeBid(uint40 requestCount) internal { uint256 bidAmount = getBidAmount(requestCount); - bytes memory transmitterSignature = _createSignature( + bytes memory transmitterSignature = createSignature( keccak256(abi.encode(address(auctionManager), evmxSlug, requestCount, bidAmount, "")), transmitterPrivateKey ); @@ -644,7 +746,7 @@ contract AuctionSetup is FeesSetup { // todo: handle other cases uint256 bidAmount = getBidAmount(requestCount_); - // bytes memory watcherSignature = _createSignature( + // bytes memory watcherSignature = createSignature( // keccak256(abi.encode(address(watcher), evmxSlug, requestCount_, bidAmount, "")), // watcherPrivateKey // ); @@ -714,6 +816,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); @@ -789,7 +895,7 @@ contract WatcherSetup is AuctionSetup { ( uint32 chainSlug, - bytes32 switchboard, + uint64 switchboard, bytes32 digest, DigestParams memory digestParams ) = _validateAndGetDigest(payloadParams); @@ -810,12 +916,13 @@ contract WatcherSetup is AuctionSetup { function _uploadProof( bytes32 payloadId, bytes32 digest, - bytes32 switchboard, + uint64 switchboard, uint32 chainSlug ) internal returns (bytes memory proof) { - proof = _createSignature( + address sbAddress = getSocketConfig(chainSlug).socket.switchboardAddresses(switchboard); + proof = createSignature( // create sigDigest which get signed by watcher - keccak256(abi.encodePacked(switchboard, chainSlug, digest)), + keccak256(abi.encodePacked(toBytes32Format(sbAddress), chainSlug, digest)), watcherPrivateKey ); @@ -832,9 +939,10 @@ contract WatcherSetup is AuctionSetup { PayloadParams memory payloadParams ) internal + view returns ( uint32 chainSlug, - bytes32 switchboard, + uint64 switchboard, bytes32 digest, DigestParams memory digestParams ) @@ -845,22 +953,22 @@ contract WatcherSetup is AuctionSetup { , uint256 gasLimit, uint256 value, - bytes32 switchboard_ + uint64 switchboard_ ) = abi.decode( payloadParams.precompileData, - (address, Transaction, WriteFinality, uint256, uint256, bytes32) + (address, Transaction, WriteFinality, uint256, uint256, uint64) ); chainSlug = transaction.chainSlug; switchboard = switchboard_; bytes32 prevBatchDigestHash = writePrecompile.getPrevBatchDigestHash( - payloadParams.requestCount, - payloadParams.batchCount + uint40(payloadParams.payloadPointer >> 120), + uint40(payloadParams.payloadPointer >> 80) ); digestParams = DigestParams( toBytes32Format(address(getSocketConfig(transaction.chainSlug).socket)), - transmitterEOA, + toBytes32Format(transmitterEOA), payloadParams.payloadId, payloadParams.deadline, payloadParams.callType, @@ -879,41 +987,51 @@ contract WatcherSetup is AuctionSetup { function _executeWrite( uint32 chainSlug, - bytes32 switchboard, + uint64 switchboard, bytes32 digest, DigestParams memory digestParams, PayloadParams memory payloadParams, bytes memory watcherProof ) internal returns (bool success, PromiseReturnData memory promiseReturnData) { // this is a signature for the socket batcher (only used for EVM) - bytes memory transmitterSig = _createSignature( + bytes memory transmitterSig = createSignature( keccak256( abi.encode(address(getSocketConfig(chainSlug).socket), payloadParams.payloadId) ), transmitterPrivateKey ); bytes memory returnData; - (success, returnData) = getSocketConfig(chainSlug).socketBatcher.attestAndExecute( - ExecuteParams({ - callType: digestParams.callType, - deadline: digestParams.deadline, - gasLimit: digestParams.gasLimit, - value: digestParams.value, - payload: digestParams.payload, - target: fromBytes32Format(digestParams.target), - requestCount: payloadParams.requestCount, - batchCount: payloadParams.batchCount, - payloadCount: payloadParams.payloadCount, - prevBatchDigestHash: digestParams.prevBatchDigestHash, - extraData: digestParams.extraData - }), - fromBytes32Format(switchboard), - digest, - watcherProof, - transmitterSig, - transmitterEOA - ); + ExecuteParams memory executeParams = ExecuteParams({ + callType: digestParams.callType, + deadline: digestParams.deadline, + gasLimit: digestParams.gasLimit, + value: digestParams.value, + payload: digestParams.payload, + target: fromBytes32Format(digestParams.target), + payloadPointer: payloadParams.payloadPointer, + prevBatchDigestHash: digestParams.prevBatchDigestHash, + extraData: digestParams.extraData + }); + if (switchboard == getSocketConfig(chainSlug).switchboard.switchboardId()) { + (success, returnData) = getSocketConfig(chainSlug).socketBatcher.attestAndExecute( + executeParams, + getSocketConfig(chainSlug).switchboard.switchboardId(), + digest, + watcherProof, + transmitterSig, + transmitterEOA + ); + } else if (switchboard == getSocketConfig(chainSlug).cctpSwitchboard.switchboardId()) { + (success, returnData) = _executeWithCCTPBatcher( + chainSlug, + executeParams, + digest, + watcherProof, + transmitterSig, + payloadParams + ); + } promiseReturnData = PromiseReturnData({ exceededMaxCopy: false, payloadId: payloadParams.payloadId, @@ -921,6 +1039,118 @@ contract WatcherSetup is AuctionSetup { }); } + function _executeWithCCTPBatcher( + uint32 chainSlug, + ExecuteParams memory executeParams, + bytes32 digest, + bytes memory watcherProof, + bytes memory transmitterSig, + PayloadParams memory payloadParams + ) internal returns (bool success, bytes memory returnData) { + CCTPBatchParams memory cctpBatchParams = _prepareCCTPBatchData(chainSlug, payloadParams); + + return + getSocketConfig(chainSlug).socketBatcher.attestCCTPAndProveAndExecute( + CCTPExecutionParams({ + executeParams: executeParams, + digest: digest, + proof: watcherProof, + transmitterSignature: transmitterSig, + refundAddress: transmitterEOA + }), + cctpBatchParams, + getSocketConfig(chainSlug).cctpSwitchboard.switchboardId() + ); + } + + function _prepareCCTPBatchData( + uint32 chainSlug, + PayloadParams memory payloadParams + ) internal view returns (CCTPBatchParams memory cctpBatchParams) { + uint40[] memory requestBatchIds = requestHandler.getRequestBatchIds( + uint40(payloadParams.payloadPointer >> 120) + ); + uint40 currentBatchCount = uint40(payloadParams.payloadPointer >> 80); + + bytes32[] memory prevBatchPayloadIds = _getPrevBatchPayloadIds( + currentBatchCount, + requestBatchIds + ); + bytes32[] memory nextBatchPayloadIds = _getNextBatchPayloadIds( + currentBatchCount, + requestBatchIds + ); + + uint32[] memory prevBatchRemoteChainSlugs = _getRemoteChainSlugs(prevBatchPayloadIds); + uint32[] memory nextBatchRemoteChainSlugs = _getRemoteChainSlugs(nextBatchPayloadIds); + + bytes[] memory messages = _createCCTPMessages( + prevBatchPayloadIds, + prevBatchRemoteChainSlugs, + chainSlug + ); + + cctpBatchParams = CCTPBatchParams({ + previousPayloadIds: prevBatchPayloadIds, + nextBatchRemoteChainSlugs: nextBatchRemoteChainSlugs, + messages: messages, + attestations: new bytes[](prevBatchPayloadIds.length) // using mock attestations for now + }); + } + + function _getPrevBatchPayloadIds( + uint40 currentBatchCount, + uint40[] memory requestBatchIds + ) internal view returns (bytes32[] memory) { + if (currentBatchCount == requestBatchIds[0]) { + return new bytes32[](0); + } + return requestHandler.getBatchPayloadIds(currentBatchCount - 1); + } + + function _getNextBatchPayloadIds( + uint40 currentBatchCount, + uint40[] memory requestBatchIds + ) internal view returns (bytes32[] memory) { + if (currentBatchCount == requestBatchIds[requestBatchIds.length - 1]) { + return new bytes32[](0); + } + return requestHandler.getBatchPayloadIds(currentBatchCount + 1); + } + + function _getRemoteChainSlugs( + bytes32[] memory payloadIds + ) internal view returns (uint32[] memory) { + uint32[] memory chainSlugs = new uint32[](payloadIds.length); + for (uint i = 0; i < payloadIds.length; i++) { + PayloadParams memory params = requestHandler.getPayload(payloadIds[i]); + (, Transaction memory transaction, , , , ) = abi.decode( + params.precompileData, + (address, Transaction, WriteFinality, uint256, uint256, address) + ); + chainSlugs[i] = transaction.chainSlug; + } + return chainSlugs; + } + + function _createCCTPMessages( + bytes32[] memory payloadIds, + uint32[] memory remoteChainSlugs, + uint32 chainSlug + ) internal view returns (bytes[] memory) { + bytes[] memory messages = new bytes[](payloadIds.length); + for (uint i = 0; i < payloadIds.length; i++) { + messages[i] = abi.encode( + remoteChainSlugs[i], + addressToBytes32(address(getSocketConfig(remoteChainSlugs[i]).cctpSwitchboard)), + chainSlug, + addressToBytes32(address(getSocketConfig(chainSlug).cctpSwitchboard)), + abi.encode(payloadIds[i], writePrecompile.digestHashes(payloadIds[i])) + ); + } + return messages; + } + function _resolvePromise(PromiseReturnData[] memory promiseReturnData) internal { watcherMultiCall( address(promiseResolver), @@ -947,25 +1177,59 @@ contract WatcherSetup is AuctionSetup { IAppGateway appGateway_, bytes32[] memory contractIds_ ) internal { - AppGatewayConfig[] memory configs = new AppGatewayConfig[](contractIds_.length); + // 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 = _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) + ); + } + } - SocketContracts memory socketConfig = getSocketConfig(chainSlug_); + 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)) { + validCount++; + } + } + } - configs[i] = AppGatewayConfig({ - plug: plug, - chainSlug: chainSlug_, - plugConfig: PlugConfigGeneric({ - appGatewayId: toBytes32Format(address(appGateway_)), - switchboard: toBytes32Format(address(socketConfig.switchboard)) - }) - }); + 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_); + if (plug != bytes32(0)) { + configs[configIndex] = AppGatewayConfig({ + plug: plug, + chainSlug: chainSlug_, + plugConfig: PlugConfigGeneric({ + appGatewayId: toBytes32Format(address(appGateway_)), + switchboardId: switchboardId + }) + }); + configIndex++; + } } - watcherMultiCall( - address(configurations), - abi.encodeWithSelector(Configurations.setAppGatewayConfigs.selector, configs) - ); } } @@ -985,7 +1249,7 @@ contract AppGatewayBaseSetup is WatcherSetup { function checkRequestParams( uint40 requestCount, RequestParams memory expectedRequest - ) internal { + ) internal view { RequestParams memory actualRequest = watcher.getRequestParams(requestCount); // RequestParams checks assertEq( @@ -1062,7 +1326,7 @@ contract AppGatewayBaseSetup is WatcherSetup { ); } - function checkPayloadParams(PayloadParams[] memory expectedPayloads) internal { + function checkPayloadParams(PayloadParams[] memory expectedPayloads) internal view { for (uint i = 0; i < expectedPayloads.length; i++) { PayloadParams memory expectedPayload = expectedPayloads[i]; PayloadParams memory actualPayload = watcher.getPayloadParams( @@ -1070,19 +1334,9 @@ contract AppGatewayBaseSetup is WatcherSetup { ); // PayloadParams checks assertEq( - actualPayload.requestCount, - expectedPayload.requestCount, - "Payload: requestCount mismatch" - ); - assertEq( - actualPayload.batchCount, - expectedPayload.batchCount, - "Payload: batchCount mismatch" - ); - assertEq( - actualPayload.payloadCount, - expectedPayload.payloadCount, - "Payload: payloadCount mismatch" + actualPayload.payloadPointer, + expectedPayload.payloadPointer, + "Payload: payloadPointer mismatch" ); assertEq( actualPayload.callType, @@ -1129,3 +1383,147 @@ contract AppGatewayBaseSetup is WatcherSetup { ); } } + +contract MessageSwitchboardSetup is DeploySetup { + uint256 msgSbGasLimit = 100000; + + event TriggerProcessed( + uint32 optChainSlug, + uint256 switchboardFees, + bytes32 digest, + DigestParams digestParams + ); + + function _getTriggerData( + MessagePlugBase srcPlug_, + MessagePlugBase dstPlug_, + SocketContracts memory srcSocketConfig_, + SocketContracts memory dstSocketConfig_, + bytes memory payload_ + ) internal view returns (uint160 payloadPointer, DigestParams memory digestParams) { + bytes32 triggerId = srcPlug_.getNextTriggerId(srcSocketConfig_.chainSlug); + uint40 payloadCounter = srcSocketConfig_.messageSwitchboard.payloadCounter(); + + payloadPointer = + (uint160(srcSocketConfig_.chainSlug) << 120) | + (uint160(uint64(uint256(triggerId))) << 80) | + payloadCounter; + + bytes32 payloadId = createPayloadId( + payloadPointer, + dstSocketConfig_.messageSwitchboard.switchboardId(), + dstSocketConfig_.chainSlug + ); + + digestParams = _createDigestParams( + srcSocketConfig_.chainSlug, + address(srcPlug_), + address(dstPlug_), + address(dstSocketConfig_.socket), + payloadId, + triggerId, + payload_ + ); + } + + function _executeOnDestination( + DigestParams memory digestParams_, + uint160 payloadPointer_ + ) internal { + _attestPayload(digestParams_); + _execute(digestParams_, payloadPointer_); + } + + // Helper function to attest a payload + function _attestPayload(DigestParams memory digestParams_) internal { + bytes32 attestDigest = keccak256( + abi.encodePacked( + toBytes32Format(address(optConfig.messageSwitchboard)), + optConfig.chainSlug, + _createDigest(digestParams_) + ) + ); + + bytes memory signature = createSignature(attestDigest, watcherPrivateKey); + optConfig.messageSwitchboard.attest(digestParams_, signature); + } + + function _createDigestParams( + uint32 srcChainSlug_, + address srcPlug_, + address dstPlug_, + address dstSocket_, + bytes32 payloadId_, + bytes32 triggerId_, + bytes memory payload_ + ) internal view returns (DigestParams memory digestParams) { + bytes memory extraData = abi.encode(srcChainSlug_, toBytes32Format(srcPlug_)); + digestParams = DigestParams({ + socket: toBytes32Format(dstSocket_), + transmitter: bytes32(0), + payloadId: payloadId_, + deadline: block.timestamp + 3600, + callType: WRITE, + gasLimit: msgSbGasLimit, + value: uint256(0), + payload: payload_, + target: toBytes32Format(dstPlug_), + appGatewayId: APP_GATEWAY_ID, + prevBatchDigestHash: triggerId_, + extraData: extraData + }); + } + + function _createDigest(DigestParams memory digest_) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked( + digest_.socket, + digest_.transmitter, + digest_.payloadId, + digest_.deadline, + digest_.callType, + digest_.gasLimit, + digest_.value, + digest_.payload, + digest_.target, + digest_.appGatewayId, + digest_.prevBatchDigestHash, + digest_.extraData + ) + ); + } + + // Helper function to execute on destination chain + function _execute(DigestParams memory digestParams_, uint160 payloadPointer_) internal { + // this is a signature for the socket batcher (only used for EVM) + ExecuteParams memory executeParams = ExecuteParams({ + callType: digestParams_.callType, + deadline: digestParams_.deadline, + gasLimit: digestParams_.gasLimit, + value: digestParams_.value, + payload: digestParams_.payload, + target: fromBytes32Format(digestParams_.target), + payloadPointer: payloadPointer_, + prevBatchDigestHash: digestParams_.prevBatchDigestHash, + extraData: digestParams_.extraData + }); + + TransmissionParams memory transmissionParams = TransmissionParams({ + socketFees: 0, + refundAddress: socketOwner, + extraData: bytes(""), + transmitterProof: bytes("") + }); + + optConfig.socket.execute(executeParams, transmissionParams); + } +} + +function addressToBytes32(address addr_) pure returns (bytes32) { + return bytes32(uint256(uint160(addr_))); +} + +function bytes32ToAddress(bytes32 addrBytes32_) pure returns (address) { + return address(uint160(uint256(addrBytes32_))); +} 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 4a0b9395..00000000 --- a/test/Watcher.t.sol +++ /dev/null @@ -1,30 +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); - vm.expectRevert(abi.encodeWithSelector(SocketAlreadyInitialized.selector)); - arbConfig.feesPlug.initSocket( - bytes32(0), - address(hackerEOA), - address(arbConfig.switchboard) - ); - } -} diff --git a/test/apps/Counter.t.sol b/test/apps/Counter.t.sol index 3472fe0b..8e6783db 100644 --- a/test/apps/Counter.t.sol +++ b/test/apps/Counter.t.sol @@ -99,11 +99,13 @@ contract CounterTest is AppGatewayBaseSetup { instances[1] = optCounterForwarder; counterGateway.incrementCounters(instances); - uint32[] memory chains = new uint32[](2); - chains[0] = arbChainSlug; - chains[1] = optChainSlug; - + bool incremented = counterGateway.incremented(); + assertEq(incremented, false); executeRequest(); + + incremented = counterGateway.incremented(); + assertEq(incremented, true); + assertEq(Counter(arbCounter).counter(), arbCounterBefore + 1); assertEq(Counter(optCounter).counter(), optCounterBefore + 1); } 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 41666c9b..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"); @@ -13,6 +14,9 @@ contract CounterAppGateway is AppGatewayBase, Ownable { uint256 public arbCounter; uint256 public optCounter; + bool public incremented; + bool public feesManagerSwitch; + event CounterScheduleResolved(uint256 creationTimestamp, uint256 executionTimestamp); constructor(address addressResolver_, uint256 fees_) { @@ -53,10 +57,17 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } function incrementCounters(address[] memory instances_) public async { + incremented = false; // the increase function is called on given list of instances for (uint256 i = 0; i < instances_.length; i++) { ICounter(instances_[i]).increase(); } + + onCompleteData = abi.encodeWithSelector(this.onIncrementComplete.selector); + } + + function onIncrementComplete() public { + incremented = true; } // for testing purposes @@ -110,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 @@ -146,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/apps/app-gateways/counter/MessageCounter.sol b/test/apps/app-gateways/counter/MessageCounter.sol new file mode 100644 index 00000000..8f8194ca --- /dev/null +++ b/test/apps/app-gateways/counter/MessageCounter.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {MessagePlugBase} from "../../../../contracts/protocol/base/MessagePlugBase.sol"; + +interface ICounterPlug { + function increment() external payable; +} + +// Counter plug that extends MessagePlugBase and includes counter functionality +contract CounterPlug is MessagePlugBase { + uint256 public count; + + event CounterIncremented(uint256 newCount, address caller); + event IncrementRequested(bytes32 triggerId, uint32 dstChainSlug); + event IncrementExecuted(bytes32 triggerId, uint256 newCount); + + constructor(address socket_, uint64 switchboardId_) MessagePlugBase(socket_, switchboardId_) {} + + /// @notice Increment the counter (local function) + function increment() external { + count++; + emit CounterIncremented(count, msg.sender); + } + + /// @notice Request increment on remote chain + function requestIncrement(uint32 dstChainSlug) external payable { + _setOverrides(abi.encode(dstChainSlug, uint256(100000), uint256(0))); + ICounterPlug(address(socket__)).increment{value: msg.value}(); + } +} diff --git a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol index 0e835b7e..638b89f9 100644 --- a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol +++ b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol @@ -56,7 +56,7 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { } // no need to call this directly, will be called automatically after all contracts are deployed. - // check AppGatewayBase._deploy and AppGatewayBase.onRequestComplete + // check AppGatewayBase._deploy and AppGatewayBase.onDeployComplete function initializeOnChain(uint32) public pure override { return; } @@ -68,4 +68,8 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { emit Transferred(_getCurrentRequestCount()); } + + function setSbType(bytes32 sbType_) external onlyOwner { + _setSbType(sbType_); + } } diff --git a/test/AuctionManager.t.sol b/test/evmx/AuctionManager.t.sol similarity index 90% rename from test/AuctionManager.t.sol rename to test/evmx/AuctionManager.t.sol index ac087ccd..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,10 +32,9 @@ 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(); - console.log("requestCount", requestCount); hoax(user); feesManager.withdrawCredits( diff --git a/test/FeesTest.t.sol b/test/evmx/FeesTest.t.sol similarity index 54% rename from test/FeesTest.t.sol rename to test/evmx/FeesTest.t.sol index c94d0681..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); @@ -90,14 +198,9 @@ contract FeesTest is AppGatewayBaseSetup { } function testDisconnectFeesPlug() public { - hoax(socketOwner); - // disconnect old fees plug - arbConfig.feesPlug.connectSocket( - bytes32(0), - address(arbConfig.socket), - address(arbConfig.switchboard) - ); + hoax(socketOwner); + arbConfig.feesPlug.disconnectSocket(); hoax(watcherEOA); feesManager.setFeesPlug(arbChainSlug, bytes32(0)); @@ -106,21 +209,24 @@ contract FeesTest is AppGatewayBaseSetup { configs[0] = AppGatewayConfig({ chainSlug: arbChainSlug, plug: toBytes32Format(address(arbConfig.feesPlug)), - plugConfig: PlugConfigGeneric({appGatewayId: bytes32(0), switchboard: bytes32(0)}) + plugConfig: PlugConfigGeneric({ + appGatewayId: bytes32(0), + switchboardId: arbConfig.switchboard.switchboardId() + }) }); watcherMultiCall( address(configurations), 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) @@ -129,14 +235,9 @@ contract FeesTest is AppGatewayBaseSetup { function testMigrateFeesPlug() public { FeesPlug oldFeesPlug = arbConfig.feesPlug; - // disconnect old fees plug hoax(socketOwner); - oldFeesPlug.connectSocket( - bytes32(0), - address(arbConfig.socket), - address(arbConfig.switchboard) - ); + oldFeesPlug.disconnectSocket(); // deploy new fees plug arbConfig.feesPlug = new FeesPlug(address(arbConfig.socket), address(socketOwner)); @@ -148,7 +249,7 @@ contract FeesTest is AppGatewayBaseSetup { arbConfig.feesPlug.connectSocket( toBytes32Format(address(feesManager)), address(arbConfig.socket), - address(arbConfig.switchboard) + arbConfig.switchboard.switchboardId() ); vm.stopPrank(); @@ -161,7 +262,7 @@ contract FeesTest is AppGatewayBaseSetup { plug: toBytes32Format(address(arbConfig.feesPlug)), plugConfig: PlugConfigGeneric({ appGatewayId: toBytes32Format(address(feesManager)), - switchboard: toBytes32Format(address(arbConfig.switchboard)) + switchboardId: arbConfig.switchboard.switchboardId() }) }); watcherMultiCall( @@ -171,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 69720ca9..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; @@ -217,8 +217,6 @@ contract ProxyStorageAssertions is AppGatewayBaseSetup { evmxSlug ); - console.log("forwarder: ", forwarder); - // first bytes32 slotValue = vm.load(address(forwarder), bytes32(uint256(FIRST_SLOT))); assertEq(uint32(uint256(slotValue)), evmxSlug); 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/CCTPMessageTransmitter.sol b/test/mock/CCTPMessageTransmitter.sol new file mode 100644 index 00000000..57eee54a --- /dev/null +++ b/test/mock/CCTPMessageTransmitter.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +import "../../contracts/protocol/interfaces/IMessageTransmitter.sol"; +import "../../contracts/protocol/interfaces/IMessageHandler.sol"; + +contract CCTPMessageTransmitter is IMessageTransmitter { + uint32 public immutable override localDomain; + address public immutable override attestationManager; + + // Mapping to store sent messages for verification + mapping(uint64 => bytes) public sentMessages; + uint64 public nonce; + + event MessageSent( + uint32 destinationDomain, + bytes32 recipient, + bytes messageBody, + uint64 nonce, + bytes message + ); + + event MessageReceived(bytes message, bytes attestation, bool success); + + constructor(uint32 _localDomain, address _attestationManager) { + localDomain = _localDomain; + attestationManager = _attestationManager; + } + + function sendMessage( + uint32 destinationDomain, + bytes32 recipient, + bytes calldata messageBody + ) external override returns (uint64) { + uint64 currentNonce = nonce++; + sentMessages[currentNonce] = messageBody; + + bytes memory message = abi.encode( + localDomain, + msg.sender, + destinationDomain, + recipient, + messageBody + ); + emit MessageSent(destinationDomain, recipient, messageBody, currentNonce, message); + + return currentNonce; + } + + function receiveMessage( + bytes calldata message, + bytes calldata attestation + ) external override returns (bool) { + ( + uint32 sourceDomain, + bytes32 sender, // destinationDomain + , + bytes32 recipient, + bytes memory messageBody + ) = abi.decode(message, (uint32, bytes32, uint32, bytes32, bytes)); + IMessageHandler(bytes32ToAddress(recipient)).handleReceiveMessage( + sourceDomain, + sender, + messageBody + ); + // In mock implementation, we'll always return true + // In real implementation, this would verify the attestation + emit MessageReceived(message, attestation, true); + return true; + } + + function addressToBytes32(address addr_) public pure returns (bytes32) { + return bytes32(uint256(uint160(addr_))); + } + function bytes32ToAddress(bytes32 addrBytes32_) public pure returns (address) { + return address(uint160(uint256(addrBytes32_))); + } +} 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 284e88ca..6ed61324 100644 --- a/test/mock/MockFastSwitchboard.sol +++ b/test/mock/MockFastSwitchboard.sol @@ -10,6 +10,9 @@ 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 @@ -20,16 +23,43 @@ 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 setIsPayloadAllowed(bool isPayloadAllowed_) external { + isPayloadAllowed = isPayloadAllowed_; + } + + function registerSwitchboard() external returns (uint64) { + switchboardId = socket__.registerSwitchboard(); + return switchboardId; + } + + function processTrigger( + address plug_, + bytes32 triggerId_, + bytes calldata payload_, + bytes calldata overrides_ + ) external payable override { + // Simple implementation that just accepts the trigger + // In a real switchboard, this would process the trigger } - function registerSwitchboard() external { - socket__.registerSwitchboard(); + function getTransmitter( + address sender_, + 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/mock/MockSocket.sol b/test/mock/MockSocket.sol index adfcc841..a88f9b76 100644 --- a/test/mock/MockSocket.sol +++ b/test/mock/MockSocket.sol @@ -18,23 +18,27 @@ contract MockSocket is ISocket { struct PlugConfigEvm { // address of the sibling plug on the remote chain bytes32 appGatewayId; - // switchboard instance for the plug connection - ISwitchboard switchboard__; + // switchboard id for the plug connection + uint64 switchboardId; } - // plug => (appGateway, switchboard__) + // plug => (appGateway, switchboardId) mapping(address => PlugConfigEvm) internal _plugConfigs; + mapping(bytes32 => bytes32) public payloadIdToDigest; + function getPlugConfig( address plugAddress_ - ) external view returns (bytes32 appGatewayId, address switchboard__) { + ) external view returns (bytes32 appGatewayId, uint64 switchboardId) { PlugConfigEvm memory _plugConfig = _plugConfigs[plugAddress_]; - return (_plugConfig.appGatewayId, address(_plugConfig.switchboard__)); + return (_plugConfig.appGatewayId, _plugConfig.switchboardId); } - function connect(bytes32 appGatewayId_, address switchboard_) external override {} + function connect(bytes32 appGatewayId_, uint64 switchboardId_) external override {} + + function disconnect() external override {} - function registerSwitchboard() external override {} + function registerSwitchboard() external override returns (uint64 switchboardId) {} //////////////////////////////////////////////////////// ////////////////////// ERRORS ////////////////////////// @@ -65,13 +69,7 @@ contract MockSocket is ISocket { //////////////////////////////////////////////////////////// uint64 public triggerCounter; uint32 public chainSlug; - - enum ExecutionStatus { - NotExecuted, - Executed, - Reverted - } - + mapping(uint64 => address) public switchboardAddresses; /** * @dev keeps track of whether a payload has been executed or not using payload id */ @@ -98,7 +96,7 @@ contract MockSocket is ISocket { emit AppGatewayCallRequested( triggerId, plugConfig.appGatewayId, - toBytes32Format(address(plugConfig.switchboard__)), + plugConfig.switchboardId, toBytes32Format(msg.sender), overrides, payload 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 91% rename from test/SocketFeeManager.t.sol rename to test/protocol/SocketFeeManager.t.sol index 1fc6ce21..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; @@ -25,7 +25,11 @@ contract SocketFeeManagerTest is AppGatewayBaseSetup { counter = new Counter(); mockSwitchboard.registerSwitchboard(); - counter.initSocket(toBytes32Format(gateway), address(socket), address(mockSwitchboard)); + counter.initSocket( + toBytes32Format(gateway), + address(socket), + mockSwitchboard.switchboardId() + ); vm.prank(owner); socket.grantRole(GOVERNANCE_ROLE, address(owner)); @@ -134,15 +138,13 @@ contract SocketFeeManagerTest is AppGatewayBaseSetup { value: 0, payload: payload, target: address(counter), - requestCount: 0, - batchCount: 0, - payloadCount: 0, + payloadPointer: 0, prevBatchDigestHash: bytes32(0), extraData: bytes("") }); TransmissionParams memory transmissionParams = TransmissionParams({ - transmitterSignature: bytes(""), + transmitterProof: bytes(""), socketFees: socketFees, extraData: bytes(""), refundAddress: transmitterEOA diff --git a/test/TriggerTest.t.sol b/test/protocol/TriggerTest.t.sol similarity index 93% rename from test/TriggerTest.t.sol rename to test/protocol/TriggerTest.t.sol index 097c3ff0..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; @@ -13,7 +13,7 @@ contract TriggerTest is AppGatewayBaseSetup { event AppGatewayCallRequested( bytes32 triggerId, bytes32 appGatewayId, - bytes32 switchboard, + uint64 switchboard, bytes32 plug, bytes overrides, bytes payload @@ -61,7 +61,7 @@ contract TriggerTest is AppGatewayBaseSetup { emit AppGatewayCallRequested( triggerId, toBytes32Format(address(gateway)), - toBytes32Format(address(arbConfig.switchboard)), + arbConfig.switchboard.switchboardId(), toBytes32Format(address(counter)), bytes(""), payload 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/protocol/switchboards/MessageSwitchboardTest.t copy.sol b/test/protocol/switchboards/MessageSwitchboardTest.t copy.sol new file mode 100644 index 00000000..73398fcd --- /dev/null +++ b/test/protocol/switchboards/MessageSwitchboardTest.t copy.sol @@ -0,0 +1,88 @@ +// 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"; + +contract MessageSwitchboardTest is MessageSwitchboardSetup { + CounterPlug public arbPlug; + CounterPlug public optPlug; + + function setUp() public { + _deploy(); + arbPlug = new CounterPlug( + address(arbConfig.socket), + arbConfig.messageSwitchboard.switchboardId() + ); + optPlug = new CounterPlug( + address(optConfig.socket), + optConfig.messageSwitchboard.switchboardId() + ); + + arbPlug.registerSibling(optConfig.chainSlug, address(optPlug)); + optPlug.registerSibling(arbConfig.chainSlug, address(arbPlug)); + } + + function testIncrementWithMessageSwitchboard() public { + (uint160 payloadPointer, DigestParams memory digestParams) = _getTriggerData( + arbPlug, + optPlug, + arbConfig, + optConfig, + abi.encodeWithSignature("increment()") + ); + + vm.expectEmit(true, true, true, true); + emit TriggerProcessed( + optConfig.chainSlug, + msgSbFees, + _createDigest(digestParams), + digestParams + ); + arbPlug.requestIncrement{value: msgSbFees}(optConfig.chainSlug); + + _executeOnDestination(digestParams, payloadPointer); + assertEq(optPlug.count(), 1, "Counter should be incremented on destination"); + } + + function testSwitchboardFees() public { + uint256 feeAmount = 2000000000000000; // 0.002 ETH + + hoax(socketOwner); + arbConfig.messageSwitchboard.setSwitchboardFees(optConfig.chainSlug, feeAmount); + + assertEq( + arbConfig.messageSwitchboard.getSwitchboardFees(optConfig.chainSlug), + feeAmount, + "Fee should be set correctly" + ); + assertEq( + arbConfig.messageSwitchboard.switchboardFees(optConfig.chainSlug), + feeAmount, + "Fee should be accessible via mapping" + ); + } + + function testIncrementWithoutSiblingConfig() public { + vm.expectRevert(abi.encodeWithSelector(MessageSwitchboard.SiblingNotFound.selector)); + arbPlug.requestIncrement{value: msgSbFees}(uint32(999)); + } + + function testAttestWithoutWatcherRole() public { + (, DigestParams memory digestParams) = _getTriggerData( + arbPlug, + optPlug, + arbConfig, + optConfig, + abi.encodeWithSignature("increment()") + ); + + bytes memory signature = createSignature( + _createDigest(digestParams), + transmitterPrivateKey + ); + + vm.expectRevert(abi.encodeWithSelector(MessageSwitchboard.WatcherNotFound.selector)); + optConfig.messageSwitchboard.attest(digestParams, signature); + } +} diff --git a/trace.sh b/trace.sh index 3e185bc6..fc1cedf9 100644 --- a/trace.sh +++ b/trace.sh @@ -54,7 +54,7 @@ echo "txHash: $2" echo "rpcUrl: $RPC_URL" npx ts-node hardhat-scripts/misc-scripts/createLabels.ts $1 -cast run --la $2 --rpc-url $RPC_URL +cast run --la $2 --rpc-url $RPC_URL --quick # usage : # yarn trace 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 74278d03..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" @@ -4157,11 +4162,67 @@ pbkdf2@^3.0.17: safe-buffer "^5.0.1" sha.js "^2.4.8" +pg-cloudflare@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz#a1f3d226bab2c45ae75ea54d65ec05ac6cfafbef" + integrity sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg== + pg-connection-string@^2.6.1: version "2.7.0" resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.7.0.tgz#f1d3489e427c62ece022dba98d5262efcb168b37" integrity sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA== +pg-connection-string@^2.9.1: + version "2.9.1" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.9.1.tgz#bb1fd0011e2eb76ac17360dc8fa183b2d3465238" + integrity sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w== + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-pool@^3.10.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.10.1.tgz#481047c720be2d624792100cac1816f8850d31b2" + integrity sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg== + +pg-protocol@^1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.10.3.tgz#ac9e4778ad3f84d0c5670583bab976ea0a34f69f" + integrity sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ== + +pg-types@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg@^8.16.3: + version "8.16.3" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.16.3.tgz#160741d0b44fdf64680e45374b06d632e86c99fd" + integrity sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw== + dependencies: + pg-connection-string "^2.9.1" + pg-pool "^3.10.1" + pg-protocol "^1.10.3" + pg-types "2.2.0" + pgpass "1.0.5" + optionalDependencies: + pg-cloudflare "^1.2.7" + +pgpass@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" + integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== + dependencies: + split2 "^4.1.0" + picocolors@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" @@ -4210,6 +4271,28 @@ portfinder@^1.0.28: debug "^3.2.7" mkdirp "^0.5.6" +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + pre-commit@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/pre-commit/-/pre-commit-1.2.2.tgz#dbcee0ee9de7235e57f79c56d7ce94641a69eec6" @@ -4614,7 +4697,7 @@ spawn-sync@^1.0.15: concat-stream "^1.4.7" os-shim "^0.1.2" -split2@^4.0.0: +split2@^4.0.0, split2@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== @@ -5002,6 +5085,11 @@ ws@^7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"