diff --git a/.env.sample b/.env.sample index 7baff038..3d6427f5 100644 --- a/.env.sample +++ b/.env.sample @@ -1,15 +1,16 @@ # RPCs EVMX_RPC="https://rpc-evmx-devnet.socket.tech/" -SEPOLIA_RPC="https://rpc.ankr.com/eth_sepolia/" -ARBITRUM_SEPOLIA_RPC="https://rpc.ankr.com/arbitrum_sepolia" -OPTIMISM_SEPOLIA_RPC="https://rpc.ankr.com/optimism_sepolia" -BASE_SEPOLIA_RPC="https://rpc.ankr.com/base_sepolia" +SEPOLIA_RPC="https://ethereum-sepolia-rpc.publicnode.com" +ARBITRUM_SEPOLIA_RPC="https://sepolia-rollup.arbitrum.io/rpc" +OPTIMISM_SEPOLIA_RPC="https://sepolia.optimism.io" +BASE_SEPOLIA_RPC="https://sepolia.base.org" # EVMx key addresses -# Find the most up to date addresses in deployments/dev_addresses.json -ADDRESS_RESOLVER="0xf3046B22F98C25305E8040286fB1b33378BA10a1" -FEES_MANAGER="0x603723100172D30171B7Fd9870ba80F8baf6FaD4" -ARBITRUM_FEES_PLUG="0x89324F93d852cB4fcDC4Ee202456be466ce096bb" +# Find the most up to date addresses at: +# https://github.com/SocketDotTech/socket-protocol/blob/master/deployments/stage_addresses.json +ADDRESS_RESOLVER="0x4846430BB142385e581C894AE92a4CF0722aEC21" +FEES_MANAGER="0x9745623Aaa299500F93d2B1B4Efb7b3EC5e60FFc" +ARBITRUM_FEES_PLUG="0x9E263f6c7C199d9c147E30764A8cae1175184CB8" # Add your deployer private key here # or remove it from this file if it is already an env var diff --git a/.github/workflows/forge-test.yml b/.github/workflows/forge-test.yml index bd4002dc..251c7ec9 100644 --- a/.github/workflows/forge-test.yml +++ b/.github/workflows/forge-test.yml @@ -37,21 +37,11 @@ jobs: run: | forge --version - - name: Run Forge build - run: | - forge build --sizes - id: build - - name: Run Forge tests run: | - forge test -vvv + forge test id: test - - name: Run coverage - run: | - forge coverage - id: coverage - - name: Run snapshot run: | forge snapshot diff --git a/.gitignore b/.gitignore index d4d737a3..f72715cd 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,8 @@ broadcast/ .gas-snapshot .cursorrules + +deployments/local_addresses.json +deployments/local_verification.json + +testScript.sh \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index dbd0a97b..0f078158 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std -[submodule "lib/solmate"] - path = lib/solmate - url = https://github.com/transmissions11/solmate [submodule "lib/solady"] path = lib/solady url = https://github.com/vectorized/solady diff --git a/.prettierignore b/.prettierignore index 50581d4d..303d3069 100644 --- a/.prettierignore +++ b/.prettierignore @@ -17,6 +17,8 @@ scratchpad .gitmodules .prettierignore deploy.sh +publish.sh + foundry.toml LICENSE remappings.txt diff --git a/Errors.md b/Errors.md index fe4496c6..018c142e 100644 --- a/Errors.md +++ b/Errors.md @@ -1,40 +1,35 @@ # Custom Error Codes -## apps/super-token-lockable/LimitHook.sol - -| Error | Signature | -| --------------------- | ------------ | -| `BurnLimitExceeded()` | `0x85e72fd4` | -| `MintLimitExceeded()` | `0xb643bfa6` | - -## apps/super-token-lockable/SuperTokenLockable.sol - -| Error | Signature | -| ---------------------------- | ------------ | -| `InsufficientBalance()` | `0xf4d678b8` | -| `InsufficientLockedTokens()` | `0x4f6d2a3e` | - ## base/PlugBase.sol | Error | Signature | | ---------------------------- | ------------ | | `SocketAlreadyInitialized()` | `0xc9500b00` | -## mock/MockSocket.sol - -| Error | Signature | -| -------------------------- | ------------ | -| `PayloadAlreadyExecuted()` | `0xe17bd578` | -| `VerificationFailed()` | `0x439cc0cd` | -| `LowGasLimit()` | `0xd38edae0` | -| `InvalidSlug()` | `0x290a8315` | - -## mock/MockWatcherPrecompile.sol +## interfaces/IWatcherPrecompile.sol + +| Error | Signature | +| --------------------------- | ------------ | +| `InvalidChainSlug()` | `0xbff6b106` | +| `InvalidConnection()` | `0x63228f29` | +| `InvalidTransmitter()` | `0x58a70a0a` | +| `InvalidTimeoutRequest()` | `0x600ca372` | +| `InvalidPayloadId()` | `0xfa0b8c86` | +| `InvalidCaller()` | `0x48f5c3ed` | +| `InvalidGateway()` | `0xfc9dfe85` | +| `InvalidSwitchboard()` | `0xf63c9e4d` | +| `RequestAlreadyCancelled()` | `0xc70f47d8` | +| `RequestCancelled()` | `0xe3cf2258` | +| `AlreadyStarted()` | `0x1fbde445` | +| `InvalidLevelNumber()` | `0x5022f14b` | + +## interfaces/IWatcherPrecompileLimits.sol -| Error | Signature | -| ---------------------- | ------------ | -| `InvalidChainSlug()` | `0xbff6b106` | -| `InvalidTransmitter()` | `0x58a70a0a` | +| Error | Signature | +| ------------------------------------------------ | ------------ | +| `ActionNotSupported(address,bytes32)` | `0xa219158f` | +| `NotDeliveryHelper()` | `0x29029c67` | +| `LimitExceeded(address,bytes32,uint256,uint256)` | `0x80bb2621` | ## protocol/AddressResolver.sol @@ -51,6 +46,19 @@ | `PromiseAlreadySetUp()` | `0x927c53d5` | | `PromiseRevertFailed()` | `0x0175b9de` | +## protocol/Forwarder.sol + +| Error | Signature | +| ------------------------ | ------------ | +| `AsyncModifierNotUsed()` | `0xb9521e1a` | + +## protocol/payload-delivery/AuctionManager.sol + +| Error | Signature | +| ---------------------------- | ------------ | +| `InvalidBid()` | `0xc6388ef7` | +| `MaxReAuctionCountReached()` | `0xf2b4388c` | + ## protocol/payload-delivery/ContractFactoryPlug.sol | Error | Signature | @@ -59,6 +67,17 @@ | `ExecutionFailed()` | `0xacfdb444` | | `information(bool,bytes)` | `0x1a5c6d63` | +## protocol/payload-delivery/FeesManager.sol + +| Error | Signature | +| ----------------------------- | ------------ | +| `InsufficientFeesAvailable()` | `0x51488f54` | +| `NoFeesForTransmitter()` | `0x248bac55` | +| `NoFeesBlocked()` | `0x116d68f9` | +| `InvalidWatcherSignature()` | `0x5029f14f` | +| `NonceUsed()` | `0x1f6d5aef` | +| `InvalidCaller()` | `0x48f5c3ed` | + ## protocol/payload-delivery/FeesPlug.sol | Error | Signature | @@ -68,17 +87,7 @@ | `InvalidDepositAmount()` | `0xfe9ba5cd` | | `TokenNotWhitelisted(address)` | `0xea3bff2e` | -## protocol/payload-delivery/app-gateway/AuctionManager.sol - -| Error | Signature | -| ------------------------- | ------------ | -| `AuctionClosed()` | `0x36b6b46d` | -| `AuctionAlreadyStarted()` | `0x628e3883` | -| `BidExceedsMaxFees()` | `0x4c923f3c` | -| `InvalidTransmitter()` | `0x58a70a0a` | -| `LowerBidAlreadyExists()` | `0xaaa1f709` | - -## protocol/payload-delivery/app-gateway/BatchAsync.sol +## protocol/payload-delivery/app-gateway/DeliveryUtils.sol | Error | Signature | | ----------------------- | ------------ | @@ -89,16 +98,7 @@ | `OnlyAppGateway()` | `0xfec944ea` | | `WinningBidExists()` | `0xe8733654` | | `InsufficientFees()` | `0x8d53e553` | - -## protocol/payload-delivery/app-gateway/FeesManager.sol - -| Error | Signature | -| ----------------------------- | ------------ | -| `InsufficientFeesAvailable()` | `0x51488f54` | -| `NoFeesForTransmitter()` | `0x248bac55` | -| `NoFeesBlocked()` | `0x116d68f9` | -| `InvalidWatcherSignature()` | `0x5029f14f` | -| `NonceUsed()` | `0x1f6d5aef` | +| `ReadOnlyRequests()` | `0x5f16b0e6` | ## protocol/socket/Socket.sol @@ -114,9 +114,9 @@ | Error | Signature | | ------------------------------- | ------------ | -| `SwitchboardExists()` | `0x2dff8555` | | `InvalidConnection()` | `0x63228f29` | | `InvalidSwitchboard()` | `0xf63c9e4d` | +| `SwitchboardExists()` | `0x2dff8555` | | `SwitchboardExistsOrDisabled()` | `0x1c7d2487` | ## protocol/socket/SocketUtils.sol @@ -146,10 +146,11 @@ ## protocol/utils/AddressResolverUtil.sol -| Error | Signature | -| ------------------------- | ------------ | -| `OnlyPayloadDelivery()` | `0x7ccc3a43` | -| `OnlyWatcherPrecompile()` | `0x663a892a` | +| Error | Signature | +| ----------------------------------------- | ------------ | +| `OnlyPayloadDelivery()` | `0x7ccc3a43` | +| `OnlyWatcherPrecompile()` | `0x663a892a` | +| `OnlyWatcherPrecompileOrDeliveryHelper()` | `0xe93a2814` | ## protocol/utils/common/Errors.sol @@ -185,22 +186,17 @@ | `InvalidTokenAddress()` | `0x1eb00b06` | | `InvalidWatcherSignature()` | `0x5029f14f` | | `NonceUsed()` | `0x1f6d5aef` | - -## protocol/watcherPrecompile/WatcherPrecompile.sol - -| Error | Signature | -| ------------------------- | ------------ | -| `InvalidChainSlug()` | `0xbff6b106` | -| `InvalidConnection()` | `0x63228f29` | -| `InvalidTransmitter()` | `0x58a70a0a` | -| `InvalidTimeoutRequest()` | `0x600ca372` | -| `InvalidPayloadId()` | `0xfa0b8c86` | -| `InvalidCaller()` | `0x48f5c3ed` | - -## protocol/watcherPrecompile/WatcherPrecompileLimits.sol - -| Error | Signature | -| ------------------------------------------------ | ------------ | -| `ActionNotSupported(address,bytes32)` | `0xa219158f` | -| `NotDeliveryHelper()` | `0x29029c67` | -| `LimitExceeded(address,bytes32,uint256,uint256)` | `0x80bb2621` | +| `AuctionClosed()` | `0x36b6b46d` | +| `AuctionAlreadyStarted()` | `0x628e3883` | +| `BidExceedsMaxFees()` | `0x4c923f3c` | +| `LowerBidAlreadyExists()` | `0xaaa1f709` | +| `AsyncModifierNotUsed()` | `0xb9521e1a` | + +## protocol/watcherPrecompile/WatcherPrecompileConfig.sol + +| Error | Signature | +| --------------------------- | ------------ | +| `InvalidGateway()` | `0xfc9dfe85` | +| `InvalidSwitchboard()` | `0xf63c9e4d` | +| `NonceUsed()` | `0x1f6d5aef` | +| `InvalidWatcherSignature()` | `0x5029f14f` | diff --git a/EventTopics.md b/EventTopics.md index fd91d9d2..28b83f5a 100644 --- a/EventTopics.md +++ b/EventTopics.md @@ -1,185 +1,189 @@ # Event Topics -## AddressResolver.sol - -| Event | Topic | -| ----------------------- | -------------------------------------------------------------------- | -| `PlugAdded` | `0x2cb8d865028f9abf3dc064724043264907615fadc8615a3699a85edb66472273` | -| `ForwarderDeployed` | `0x4dbbecb9cf9c8b93da9743a2b48ea52efe68d69230ab1c1b711891d9d223b29f` | -| `AsyncPromiseDeployed` | `0xb6c5491cf83e09749b1a4dd6a9f07b0e925fcb0a915ac8c2b40e8ab28191c270` | -| `ImplementationUpdated` | `0xa1e41aa2c2f3f20d9b63ac06b634d2788768d6034f3d9192cdf7d07374bb16f4` | - -## apps/cron/CronAppGateway.sol - -| Event | Topic | -| ----------------- | -------------------------------------------------------------------- | -| `TimeoutResolved` | `0x21f74fe97870cde3cfbde7addf2b9343c27ca433b826801e63b3d6153699ec3f` | - -## apps/payload-delivery/ContractFactoryPlug.sol - -| Event | Topic | -| ---------- | -------------------------------------------------------------------- | -| `Deployed` | `0x94bfd9af14ef450884c8a7ddb5734e2e1e14e70a1c84f0801cc5a29e34d26428` | - -## apps/payload-delivery/FeesPlug.sol - -| Event | Topic | -| --------------- | -------------------------------------------------------------------- | -| `FeesDeposited` | `0x0fd38537e815732117cfdab41ba9b6d3eb2c5799d44039c100c05fc9c112f235` | -| `FeesWithdrawn` | `0x87044da2612407bc001bb0985725dcc651a0dc71eaabfd1d7e8617ca85a8c19c` | - -## apps/payload-delivery/app-gateway/AuctionManager.sol - -| Event | Topic | -| ---------------- | -------------------------------------------------------------------- | -| `AuctionStarted` | `0x884055d82c091219e252c5c2acca6051c823fcba97cecb3ba07d5f06c1628e6c` | -| `AuctionEnded` | `0xefa02d67c6f01c72b191e6c5076e63d9a4941f9037bf1c4aa4ccc613340e1571` | -| `BidPlaced` | `0xaf5c23b337289338f72cec2fdec2c736d419c7607e4c840ee4d28176477d4e08` | - -## apps/payload-delivery/app-gateway/BatchAsync.sol - -| Event | Topic | -| ----------------------- | -------------------------------------------------------------------- | -| `PayloadSubmitted` | `0xaab415570fdc7fb2a70601b49667178ab5f887c7901dc5e84b853c5bad514106` | -| `FeesIncreased` | `0xf1a5d6adcecf6c2be482b515e9564a9898cd629b54c57ede69295dffbf16bb1d` | -| `PayloadAsyncRequested` | `0x71c5226e31c1ad0fb69f89c62225760ba7c06c4ebdd284dfc71fd61603120d95` | -| `BatchCancelled` | `0xac01c50ce693d1fe783ba60ec0f82ab99f65e62446fffb028e3bd639cd5684d4` | - -## apps/payload-delivery/app-gateway/DeliveryHelper.sol - -| Event | Topic | -| ------------------ | -------------------------------------------------------------------- | -| `CallBackReverted` | `0xb793657774d4efcce6746ecc3d896279387c392fe6f6f2932daf35d5a1d65be6` | - -## apps/payload-delivery/app-gateway/FeesManager.sol - -| Event | Topic | -| -------------------------- | -------------------------------------------------------------------- | -| `FeesBlocked` | `0xc1639cc709c1b397fa20d3a1ece33aee2eb5c29573fe9e1e06d2364d40cdf2f7` | -| `TransmitterFeesUpdated` | `0x409067fdd2f9c474161a5b1f96399f2d24c45cfc4a93f4b1c27c9bf351f1e2bb` | -| `FeesDepositedUpdated` | `0xe82dece33ef85114446a366b7d94538d641968e3ec87bf9f2f5a957ace1086e7` | -| `FeesUnblockedAndAssigned` | `0x09a0f93a20f672833eeac3a1c9d63495cfcbee2e32f968e947a6124054b44a79` | -| `FeesUnblocked` | `0x5290de2b93b8542dc233ee9f02c346e94a47254ed50e00738e6d7ec4a54bcb3a` | - -## apps/payload-delivery/app-gateway/QueueAsync.sol - -| Event | Topic | -| ----------------------- | -------------------------------------------------------------------- | -| `PayloadBatchCancelled` | `0xae2e532ea00438ec2fc3e806f19c85f21334853d16c32107c75ff8d176af7633` | - -## apps/super-token/SuperTokenAppGateway.sol - -| Event | Topic | -| ------------- | -------------------------------------------------------------------- | -| `Transferred` | `0xd729be146db2a3467d5eaf1eed3f1afcdd5cc05d1b3b14d27675e36844fb3aba` | - -## apps/super-token-lockable/SuperTokenLockableAppGateway.sol - -| Event | Topic | -| --------- | -------------------------------------------------------------------- | -| `Bridged` | `0x19138f4129b378a375fc2f5ca3b1be3fea2f048ef2b1884a1d0fff5dca83e0ac` | - -## base/PlugBase.sol - -| Event | Topic | -| --------------------------- | -------------------------------------------------------------------- | -| `ConnectorPlugDisconnected` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | - -## interfaces/IAddressResolver.sol - -| Event | Topic | -| ------------ | -------------------------------------------------------------------- | -| `AddressSet` | `0x9ef0e8c8e52743bb38b83b17d9429141d494b8041ca6d616a6c77cebae9cd8b7` | - -## interfaces/IDeliveryHelper.sol - -| Event | Topic | -| -------------- | -------------------------------------------------------------------- | -| `BidPlaced` | `0xaf5c23b337289338f72cec2fdec2c736d419c7607e4c840ee4d28176477d4e08` | -| `AuctionEnded` | `0xefa02d67c6f01c72b191e6c5076e63d9a4941f9037bf1c4aa4ccc613340e1571` | - -## interfaces/IERC20.sol - -| Event | Topic | -| ---------- | -------------------------------------------------------------------- | -| `Transfer` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | -| `Approval` | `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925` | - -## interfaces/ISocket.sol - -| Event | Topic | -| ------------------------- | -------------------------------------------------------------------- | -| `ExecutionSuccess` | `0xc54787fbe087097b182e713f16d3443ad2e67cbe6732628451dd3695a11814c2` | -| `PlugConnected` | `0x99c37c6da3bd69c6d59967915f8339f11a0a17fed28c615efb19457fdec0d7db` | -| `AppGatewayCallRequested` | `0x392cb36fae7bd0470268c65b15c32a745b37168c4ccd13348c59bd9170f3b3e8` | - -## mock/MockWatcherPrecompile.sol - -| Event | Topic | -| ------------------- | -------------------------------------------------------------------- | -| `CalledAppGateway` | `0x255bcf22d238fe60f6611670cd7919d2bc890283be2fdaf6d2ad3411e777e33c` | -| `QueryRequested` | `0x19a4898a6390d795c9d86362d12853f4f6515b41b95a57f9b28774b4b36fc916` | -| `FinalizeRequested` | `0x17e763b469fcd8535794b9c8c1452d90597be1eeb0eb0367662e18c067fe9656` | -| `Finalized` | `0x8ee21307ed5b839a691d488e11de81bee61525893865b7ae106cc712ef42376e` | -| `PromiseResolved` | `0x2e6de63938bd94bb20d9aa80f8bc4b07be2d8fbd4525664156351836588ed365` | -| `TimeoutRequested` | `0xdf94fed77e41734b8a17815476bbbf88e2db15d762f42a30ddb9d7870f2fb858` | -| `TimeoutResolved` | `0x221462ec065e22637f794ec3a7edb17b2f04bec88f0546dda308bc37a83801b8` | - -## socket/SocketBase.sol - -| Event | Topic | -| ---------------------- | -------------------------------------------------------------------- | -| `HasherSet` | `0xc7238b23787eb9f8aa74c79b27083bb4b8f0db527df90366b487c40fa0ba2d3a` | -| `SignatureVerifierSet` | `0xcb341def955dbf73920141be056568edde30b1dbc56a29396945e5596a03c68c` | - -## socket/SocketConfig.sol - -| Event | Topic | -| ------------------ | -------------------------------------------------------------------- | -| `SwitchboardAdded` | `0x1595852923edfbbf906f09fc8523e4cfb022a194773c4d1509446b614146ee88` | - -## socket/switchboard/FastSwitchboard.sol - -| Event | Topic | -| ---------- | -------------------------------------------------------------------- | -| `Attested` | `0x2f8e66b1207a4b70274a2a3da88ffb5737c8214576490da1b35acc38b2d62db6` | - -## socket/utils/AccessControl.sol - -| Event | Topic | -| ------------- | -------------------------------------------------------------------- | -| `RoleGranted` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | - -## utils/OwnableTwoStep.sol - -| Event | Topic | -| ---------------- | -------------------------------------------------------------------- | -| `OwnerNominated` | `0x906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22` | -| `OwnerClaimed` | `0xfbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f87` | - -## watcherPrecompile/WatcherPrecompile.sol - -| Event | Topic | -| ------------------- | -------------------------------------------------------------------- | -| `CalledAppGateway` | `0x255bcf22d238fe60f6611670cd7919d2bc890283be2fdaf6d2ad3411e777e33c` | -| `QueryRequested` | `0x19a4898a6390d795c9d86362d12853f4f6515b41b95a57f9b28774b4b36fc916` | -| `FinalizeRequested` | `0x17e763b469fcd8535794b9c8c1452d90597be1eeb0eb0367662e18c067fe9656` | -| `Finalized` | `0x8ee21307ed5b839a691d488e11de81bee61525893865b7ae106cc712ef42376e` | -| `PromiseResolved` | `0x3f1120f34271f52a541dfc8a71efbe6123ab80730562e8948fa7275514c41bda` | -| `TimeoutRequested` | `0xdf94fed77e41734b8a17815476bbbf88e2db15d762f42a30ddb9d7870f2fb858` | -| `TimeoutResolved` | `0x221462ec065e22637f794ec3a7edb17b2f04bec88f0546dda308bc37a83801b8` | - -## watcherPrecompile/WatcherPrecompileConfig.sol - -| Event | Topic | -| ---------------- | -------------------------------------------------------------------- | -| `PlugAdded` | `0x2cb8d865028f9abf3dc064724043264907615fadc8615a3699a85edb66472273` | -| `SwitchboardSet` | `0x6273f161f4a795e66ef3585d9b4442ef3796b32337157fdfb420b5281e4cf2e3` | - -## watcherPrecompile/WatcherPrecompileLimits.sol - -| Event | Topic | -| --------------------- | -------------------------------------------------------------------- | -| `LimitParamsUpdated` | `0x76b76501b1f65d80b7de6c1a42b2245466c1c80504052e7ad48e86b6038d39a1` | -| `AppGatewayActivated` | `0x44628d7d5628b9fbc2c84ea9bf3bd3987fa9cde8d2b28e2d5ceb451f916cb8b9` | +## ProxyFactory + +| Event | Arguments | Topic | +| -------------- | ----------------------------------------------------------- | -------------------------------------------------------------------- | +| `AdminChanged` | `(proxy: address, admin: address)` | `0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f` | +| `Deployed` | `(proxy: address, implementation: address, admin: address)` | `0xc95935a66d15e0da5e412aca0ad27ae891d20b2fb91cf3994b6a3bf2b8178082` | +| `Upgraded` | `(proxy: address, implementation: address)` | `0x5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c7` | + +## AddressResolver + +| Event | Arguments | Topic | +| ---------------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------- | +| `AddressSet` | `(name: bytes32, oldAddress: address, newAddress: address)` | `0x9ef0e8c8e52743bb38b83b17d9429141d494b8041ca6d616a6c77cebae9cd8b7` | +| `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` | +| `PlugAdded` | `(appGateway: address, chainSlug: uint32, plug: address)` | `0x2cb8d865028f9abf3dc064724043264907615fadc8615a3699a85edb66472273` | + +## AsyncPromise + +| Event | Arguments | Topic | +| ------------- | ------------------- | -------------------------------------------------------------------- | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | + +## Forwarder + +| Event | Arguments | Topic | +| ------------- | ------------------- | -------------------------------------------------------------------- | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | + +## AuctionManager + +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------- | -------------------------------------------------------------------- | +| `AuctionEnded` | `(requestCount: uint40, winningBid: tuple)` | `0x9cc96c8b9e588c26f8beae57fe7fbb59113b82865578b54ff3f025317dcd6895` | +| `AuctionRestarted` | `(requestCount: uint40)` | `0x071867b21946ec4655665f0d4515d3757a5a52f144c762ecfdfb11e1da542b82` | +| `AuctionStarted` | `(requestCount: uint40)` | `0xcd040613cf8ef0cfcaa3af0d711783e827a275fc647c116b74595bf17cb9364f` | +| `BidPlaced` | `(requestCount: uint40, bid: tuple)` | `0xd3dc2f289bc8a88faaaf6a3f4f800dd0eac760a653b067ef749771252a1343b3` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `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` | + +## 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` | + +## FeesManager + +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `FeesBlocked` | `(requestCount: uint40, chainSlug: uint32, token: address, amount: uint256)` | `0xbb23ad39130b455188189b8de52b55fa41a7ea8ee8413dc28ced31e543d0df0c` | +| `FeesDepositedUpdated` | `(chainSlug: uint32, appGateway: address, token: address, amount: uint256)` | `0xe82dece33ef85114446a366b7d94538d641968e3ec87bf9f2f5a957ace1086e7` | +| `FeesUnblocked` | `(requestCount: uint40, appGateway: address)` | `0xc8b27128d97a92b6664c696ac891afaa87c9fc7d7c7cda17d892237589ebd4fc` | +| `FeesUnblockedAndAssigned` | `(requestCount: uint40, transmitter: address, amount: uint256)` | `0x04d2986fb321499f6bc8263ff6e65d823570e186dcdc16c04c6b388ccd0f29a8` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `TransmitterFeesUpdated` | `(requestCount: uint40, transmitter: address, amount: uint256)` | `0x9839a0f8408a769f0f3bb89025b64a6cff279673c77d2de3ab8d59b1841fcd5f` | + +## FeesPlug + +| Event | Arguments | Topic | +| ---------------------------- | -------------------------------------------------------- | -------------------------------------------------------------------- | +| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | +| `FeesDeposited` | `(appGateway: address, token: address, amount: uint256)` | `0x0fd38537e815732117cfdab41ba9b6d3eb2c5799d44039c100c05fc9c112f235` | +| `FeesWithdrawn` | `(token: address, amount: uint256, receiver: address)` | `0x87044da2612407bc001bb0985725dcc651a0dc71eaabfd1d7e8617ca85a8c19c` | +| `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` | + +## Socket + +| Event | Arguments | Topic | +| ---------------------------- | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `AppGatewayCallRequested` | `(callId: bytes32, chainSlug: uint32, plug: address, appGateway: address, params: bytes32, payload: bytes)` | `0x392cb36fae7bd0470268c65b15c32a745b37168c4ccd13348c59bd9170f3b3e8` | +| `ExecutionFailed` | `(payloadId: bytes32, returnData: bytes)` | `0xd255d8a333980d77af4f9179384057def133983cb02db3e1fdb70c4dc14102e8` | +| `ExecutionSuccess` | `(payloadId: bytes32, returnData: bytes)` | `0xc54787fbe087097b182e713f16d3443ad2e67cbe6732628451dd3695a11814c2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PlugConnected` | `(plug: address, appGateway: address, switchboard: address)` | `0x99c37c6da3bd69c6d59967915f8339f11a0a17fed28c615efb19457fdec0d7db` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `SwitchboardAdded` | `(switchboard: address)` | `0x1595852923edfbbf906f09fc8523e4cfb022a194773c4d1509446b614146ee88` | +| `SwitchboardDisabled` | `(switchboard: address)` | `0x1b4ee41596b4e754e5665f01ed6122b356f7b36ea0a02030804fac7fa0fdddfc` | + +## SocketBatcher + +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | + +## WatcherPrecompile + +| Event | Arguments | Topic | +| ---------------------------- | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `CalledAppGateway` | `(callId: bytes32, chainSlug: uint32, plug: address, appGateway: address, params: bytes32, payload: bytes)` | `0x255bcf22d238fe60f6611670cd7919d2bc890283be2fdaf6d2ad3411e777e33c` | +| `FinalizeRequested` | `(digest: bytes32, params: tuple)` | `0x5bc623895e2e50e307b4c3ba21df61ddfe68de0e084bb85eb1d42d4596532589` | +| `Finalized` | `(payloadId: bytes32, proof: bytes)` | `0x7e6e3e411317567fb9eabe3eb86768c3e33c46e38a50790726e916939b4918d6` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `MarkedRevert` | `(payloadId: bytes32, isRevertingOnchain: bool)` | `0xcf1fd844cb4d32cbebb5ca6ce4ac834fe98da3ddac44deb77fffd22ad933824c` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PromiseNotResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0xbcf0d0c678940566e9e64f0c871439395bd5fb5c39bca3547b126fe6ee467937` | +| `PromiseResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0x1b1b5810494fb3e17f7c46547e6e67cd6ad3e6001ea6fb7d12ea0241ba13c4ba` | +| `QueryRequested` | `(params: tuple)` | `0xca81bf0029a549d7e6e3a9c668a717472f4330a6a5ec4350304a9e79bf437345` | +| `RequestSubmitted` | `(middleware: address, requestCount: uint40, payloadParamsArray: tuple[])` | `0xb856562fcff2119ba754f0486f47c06087ebc1842bff464faf1b2a1f8d273b1d` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `TimeoutRequested` | `(timeoutId: bytes32, target: address, payload: bytes, executeAt: uint256)` | `0xdf94fed77e41734b8a17815476bbbf88e2db15d762f42a30ddb9d7870f2fb858` | +| `TimeoutResolved` | `(timeoutId: bytes32, target: address, payload: bytes, executedAt: uint256)` | `0x221462ec065e22637f794ec3a7edb17b2f04bec88f0546dda308bc37a83801b8` | + +## WatcherPrecompileConfig + +| Event | Arguments | Topic | +| ---------------------------- | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OnChainContractSet` | `(chainSlug: uint32, socket: address, contractFactoryPlug: address, feesPlug: address)` | `0xd24cf816377e3c571e7bc798dd43d3d5fc78c32f7fc94b42898b0d37c5301a4e` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PlugAdded` | `(appGateway: address, chainSlug: uint32, plug: address)` | `0x2cb8d865028f9abf3dc064724043264907615fadc8615a3699a85edb66472273` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `SwitchboardSet` | `(chainSlug: uint32, sbType: bytes32, switchboard: address)` | `0x6273f161f4a795e66ef3585d9b4442ef3796b32337157fdfb420b5281e4cf2e3` | + +## WatcherPrecompileLimits + +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------- | +| `AppGatewayActivated` | `(appGateway: address, maxLimit: uint256, ratePerSecond: uint256)` | `0x44628d7d5628b9fbc2c84ea9bf3bd3987fa9cde8d2b28e2d5ceb451f916cb8b9` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `LimitParamsUpdated` | `(updates: tuple[])` | `0x81576b12f4d507fd0543afd25a86785573a595334c2c7eb8ca8ec1b0a56a55b3` | +| `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` | + +## DeliveryHelper + +| Event | Arguments | Topic | +| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `AuctionEnded` | `(requestCount: uint40, winningBid: tuple)` | `0x9cc96c8b9e588c26f8beae57fe7fbb59113b82865578b54ff3f025317dcd6895` | +| `BidTimeoutUpdated` | `(newBidTimeout: uint256)` | `0xd4552e666d0e4e343fb2b13682972a8f0c7f1a86e252d6433b356f0c0e817c3d` | +| `CallBackReverted` | `(requestCount_: uint40, payloadId_: bytes32)` | `0xcecb2641ea89470f68bf9f852d731e123505424e4dcfd770c7ea9e2e25326b1b` | +| `FeesIncreased` | `(appGateway: address, requestCount: uint40, newMaxFees: uint256)` | `0x63ee9e9e84d216b804cb18f51b7f7511254b0c1f11304b7a3aa34d57511aa6dc` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PayloadSubmitted` | `(requestCount: uint40, appGateway: address, payloadSubmitParams: tuple[], fees: tuple, auctionManager: address, onlyReadRequests: bool)` | `0x204c4de167e7a12fc9ad8231fa3d877639ed95a66bd19e1a55d1f68088d4c784` | +| `RequestCancelled` | `(requestCount: uint40)` | `0xff191657769be72fc08def44c645014c60d18cb24b9ca05c9a33406a28253245` | + +## FastSwitchboard + +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `Attested` | `(digest_: 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` | diff --git a/FunctionSignatures.md b/FunctionSignatures.md new file mode 100644 index 00000000..6f9cdf76 --- /dev/null +++ b/FunctionSignatures.md @@ -0,0 +1,433 @@ +# Function Signatures + +## ProxyFactory + +| Function | Signature | +| ----------------------------- | ------------ | +| `adminOf` | `0x2abbef15` | +| `changeAdmin` | `0x1acfd02a` | +| `deploy` | `0x545e7c61` | +| `deployAndCall` | `0x4314f120` | +| `deployDeterministic` | `0x3729f922` | +| `deployDeterministicAndCall` | `0xa97b90d5` | +| `initCodeHash` | `0xdb4c545e` | +| `predictDeterministicAddress` | `0x5414dff0` | +| `upgrade` | `0x99a88ec4` | +| `upgradeAndCall` | `0x9623609d` | + +## AddressResolver + +| Function | Signature | +| ------------------------------- | ------------ | +| `asyncPromiseBeacon` | `0xc0fbc0ef` | +| `asyncPromiseCounter` | `0x97cdbf4c` | +| `asyncPromiseImplementation` | `0x59531b8d` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `clearPromises` | `0x96e03234` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `contractsToGateways` | `0x5bc03a67` | +| `defaultAuctionManager` | `0x8f27cdc6` | +| `deliveryHelper` | `0x71eaa36f` | +| `deployAsyncPromiseContract` | `0x00afbf9d` | +| `feesManager` | `0x05a9e073` | +| `forwarderBeacon` | `0x945709ae` | +| `forwarderImplementation` | `0xe38d60a1` | +| `getAsyncPromiseAddress` | `0xb6400df5` | +| `getForwarderAddress` | `0x48c0b3e0` | +| `getOrDeployForwarderContract` | `0xe8d616a8` | +| `getPromises` | `0xa01afb0d` | +| `initialize` | `0xc4d66de8` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `setAsyncPromiseImplementation` | `0xeb506eab` | +| `setContractsToGateways` | `0xb08dd08b` | +| `setDefaultAuctionManager` | `0xede8b4b5` | +| `setDeliveryHelper` | `0x75523822` | +| `setFeesManager` | `0x1c89382a` | +| `setForwarderImplementation` | `0x83b1e974` | +| `setWatcherPrecompile` | `0x5ca44c9b` | +| `transferOwnership` | `0xf2fde38b` | +| `version` | `0x54fd4d50` | +| `watcherPrecompile__` | `0x1de360c3` | + +## AsyncPromise + +| Function | Signature | +| ------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `callbackData` | `0xef44c272` | +| `callbackSelector` | `0x2764f92f` | +| `deliveryHelper__` | `0xc031dfb4` | +| `forwarder` | `0xf645d4f9` | +| `initialize` | `0xc0c53b8b` | +| `localInvoker` | `0x45eb87f4` | +| `markOnchainRevert` | `0x7734a84e` | +| `markResolved` | `0xdd94d9b2` | +| `resolved` | `0x3f6fa655` | +| `state` | `0xc19d93fb` | +| `then` | `0x0bf2ba15` | +| `watcherPrecompileConfig` | `0x8618a912` | +| `watcherPrecompileLimits` | `0xa71cd97d` | +| `watcherPrecompile__` | `0x1de360c3` | + +## Forwarder + +| Function | Signature | +| ------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `chainSlug` | `0xb349ba65` | +| `deliveryHelper__` | `0xc031dfb4` | +| `getChainSlug` | `0x0b8c6568` | +| `getOnChainAddress` | `0x9da48789` | +| `initialize` | `0x647c576c` | +| `latestAsyncPromise` | `0xb8a8ba52` | +| `onChainAddress` | `0x8bd0b363` | +| `then` | `0x0bf2ba15` | +| `watcherPrecompileConfig` | `0x8618a912` | +| `watcherPrecompileLimits` | `0xa71cd97d` | +| `watcherPrecompile__` | `0x1de360c3` | + +## AuctionManager + +| Function | Signature | +| ---------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `auctionClosed` | `0x6862ebb0` | +| `auctionEndDelaySeconds` | `0x9087dfdb` | +| `auctionStarted` | `0x7c9c5bb8` | +| `bid` | `0xfcdf49c2` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deliveryHelper__` | `0xc031dfb4` | +| `endAuction` | `0x1212e653` | +| `evmxSlug` | `0x8bae77c2` | +| `expireBid` | `0x1dd5022c` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `initialize` | `0x5f24043b` | +| `maxReAuctionCount` | `0xc367b376` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `reAuctionCount` | `0x9b4b22d3` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `revokeRole` | `0xd547741f` | +| `setAuctionEndDelaySeconds` | `0x88606b1a` | +| `transferOwnership` | `0xf2fde38b` | +| `watcherPrecompileConfig` | `0x8618a912` | +| `watcherPrecompileLimits` | `0xa71cd97d` | +| `watcherPrecompile__` | `0x1de360c3` | +| `whitelistedTransmitters` | `0xc2f1bf5d` | +| `winningBids` | `0x9133f232` | + +## ContractFactoryPlug + +| Function | Signature | +| ---------------------------- | ------------ | +| `appGateway` | `0xb82bb881` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `connectSocket` | `0x052615a6` | +| `deployContract` | `0x35041492` | +| `getAddress` | `0x94ca2cb5` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `initSocket` | `0x59c92b64` | +| `isSocketInitialized` | `0x9a7d9a9b` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `socket__` | `0xc6a261d2` | +| `transferOwnership` | `0xf2fde38b` | + +## FeesManager + +| Function | Signature | +| ---------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `appGatewayFeeBalances` | `0x46a312be` | +| `blockFees` | `0x1c0ac675` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deliveryHelper__` | `0xc031dfb4` | +| `evmxSlug` | `0x8bae77c2` | +| `feesCounter` | `0xb94f4778` | +| `getAvailableFees` | `0xe3d07506` | +| `incrementFeesDeposited` | `0x4f88fe32` | +| `initialize` | `0x6f6186bd` | +| `isFeesEnough` | `0x7d274c6a` | +| `isNonceUsed` | `0x5d00bb12` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestCountBlockedFees` | `0xd09604ed` | +| `requestOwnershipHandover` | `0x25692962` | +| `sbType` | `0x745de344` | +| `transferOwnership` | `0xf2fde38b` | +| `transmitterFees` | `0xefb4cdea` | +| `unblockAndAssignFees` | `0x3c5366a2` | +| `unblockFees` | `0xc1867a4b` | +| `watcherPrecompileConfig` | `0x8618a912` | +| `watcherPrecompileLimits` | `0xa71cd97d` | +| `watcherPrecompile__` | `0x1de360c3` | +| `withdrawFees` | `0xe1a69364` | +| `withdrawTransmitterFees` | `0x8c047bbd` | + +## FeesPlug + +| Function | Signature | +| ---------------------------- | ------------ | +| `appGateway` | `0xb82bb881` | +| `balanceOf` | `0x70a08231` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `connectSocket` | `0x052615a6` | +| `deposit` | `0x8340f549` | +| `distributeFee` | `0x7aeee972` | +| `feesRedeemed` | `0x58f8782b` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `initSocket` | `0x59c92b64` | +| `isSocketInitialized` | `0x9a7d9a9b` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `removeTokenFromWhitelist` | `0x306275be` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `socket__` | `0xc6a261d2` | +| `transferOwnership` | `0xf2fde38b` | +| `whitelistToken` | `0x6247f6f2` | +| `whitelistedTokens` | `0xdaf9c210` | +| `withdrawFees` | `0x9ba372c2` | + +## Socket + +| Function | Signature | +| ---------------------------- | ------------ | +| `callAppGateway` | `0x31ed7099` | +| `callCounter` | `0xc0f9882e` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `chainSlug` | `0xb349ba65` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `connect` | `0x295058ef` | +| `disableSwitchboard` | `0xe545b261` | +| `execute` | `0x2c6571a9` | +| `getPlugConfig` | `0xf9778ee0` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `isValidSwitchboard` | `0xb2d67675` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `payloadExecuted` | `0x3eaeac3d` | +| `registerSwitchboard` | `0x74f5b1fc` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `transferOwnership` | `0xf2fde38b` | +| `version` | `0x54fd4d50` | + +## SocketBatcher + +| Function | Signature | +| ---------------------------- | ------------ | +| `attestAndExecute` | `0x841f0228` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `socket__` | `0xc6a261d2` | +| `transferOwnership` | `0xf2fde38b` | + +## WatcherPrecompile + +| Function | Signature | +| ----------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `appGatewayCalled` | `0xc6767cf1` | +| `batchPayloadIds` | `0x02b74f98` | +| `callAppGateways` | `0xdede3465` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `cancelRequest` | `0x50ad0779` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deliveryHelper__` | `0xc031dfb4` | +| `evmxSlug` | `0x8bae77c2` | +| `expiryTime` | `0x99bc0aea` | +| `finalize` | `0x7ffecf2e` | +| `finalized` | `0x81c051de` | +| `getBatchPayloadIds` | `0xfd83cd1f` | +| `getBatches` | `0xcb95b7b3` | +| `getCurrentRequestCount` | `0x5715abbb` | +| `getDigest` | `0xeba9500e` | +| `getPayloadParams` | `0xae5eeb77` | +| `getRequestParams` | `0x71263d0d` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `initialize` | `0xb7dc6b77` | +| `isNonceUsed` | `0x5d00bb12` | +| `isPromiseExecuted` | `0x17a2cdf0` | +| `markRevert` | `0x1c75dad5` | +| `maxTimeoutDelayInSeconds` | `0x46fbc9d7` | +| `nextBatchCount` | `0x333a3963` | +| `nextRequestCount` | `0xfef72893` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `payloadCounter` | `0x550ce1d5` | +| `payloads` | `0x58722672` | +| `query` | `0x16ad71bc` | +| `renounceOwnership` | `0x715018a6` | +| `requestBatchIds` | `0xf865c4a7` | +| `requestOwnershipHandover` | `0x25692962` | +| `requestParams` | `0x5ce2d853` | +| `resolvePromises` | `0xccb1caff` | +| `resolveTimeout` | `0xa67c0781` | +| `revokeRole` | `0xd547741f` | +| `setExpiryTime` | `0x30fc4cff` | +| `setMaxTimeoutDelayInSeconds` | `0x65d480fc` | +| `setTimeout` | `0x9c29ec74` | +| `startProcessingRequest` | `0x77290f24` | +| `submitRequest` | `0x16b47482` | +| `timeoutCounter` | `0x94f6522e` | +| `timeoutRequests` | `0xcdf85751` | +| `transferOwnership` | `0xf2fde38b` | +| `updateTransmitter` | `0xb228a22c` | +| `watcherPrecompileConfig` | `0x8618a912` | +| `watcherPrecompileConfig__` | `0xa816cbd9` | +| `watcherPrecompileLimits` | `0xa71cd97d` | +| `watcherPrecompileLimits__` | `0xb2ad6c48` | +| `watcherPrecompile__` | `0x1de360c3` | +| `watcherProofs` | `0x3fa3166b` | + +## WatcherPrecompileConfig + +| Function | Signature | +| ---------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `contractFactoryPlug` | `0xd8427483` | +| `deliveryHelper__` | `0xc031dfb4` | +| `evmxSlug` | `0x8bae77c2` | +| `feesPlug` | `0xd1ba159d` | +| `getPlugConfigs` | `0x8a028c38` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `initialize` | `0x6ecf2b22` | +| `isNonceUsed` | `0x5d00bb12` | +| `isValidPlug` | `0xec8aef74` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `revokeRole` | `0xd547741f` | +| `setAppGateways` | `0xbdf0b455` | +| `setIsValidPlug` | `0xb3a6bbcf` | +| `setOnChainContracts` | `0x33fa78c2` | +| `setSwitchboard` | `0x61706f1e` | +| `sockets` | `0xb44a23ab` | +| `switchboards` | `0xaa539546` | +| `transferOwnership` | `0xf2fde38b` | +| `verifyConnections` | `0xe283ce7b` | +| `watcherPrecompileConfig` | `0x8618a912` | +| `watcherPrecompileLimits` | `0xa71cd97d` | +| `watcherPrecompile__` | `0x1de360c3` | + +## WatcherPrecompileLimits + +| Function | Signature | +| ---------------------------- | ------------ | +| `LIMIT_DECIMALS` | `0x1e65497d` | +| `addressResolver__` | `0x6a750469` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `consumeLimit` | `0xc22f5a13` | +| `defaultLimit` | `0xe26b013b` | +| `defaultRatePerSecond` | `0x16d7acdf` | +| `deliveryHelper__` | `0xc031dfb4` | +| `getCurrentLimit` | `0x1a065507` | +| `getLimitParams` | `0x2ff81ee0` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `initialize` | `0x1794bb3c` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `revokeRole` | `0xd547741f` | +| `setDefaultLimit` | `0x995284b1` | +| `setDefaultRatePerSecond` | `0xa44df657` | +| `transferOwnership` | `0xf2fde38b` | +| `updateLimitParams` | `0x01b2a5a0` | +| `watcherPrecompileConfig` | `0x8618a912` | +| `watcherPrecompileLimits` | `0xa71cd97d` | +| `watcherPrecompile__` | `0x1de360c3` | + +## DeliveryHelper + +| Function | Signature | +| ------------------------------ | ------------ | +| `addressResolver__` | `0x6a750469` | +| `batch` | `0x039cc50a` | +| `bidTimeout` | `0x94090d0b` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `cancelRequest` | `0x50ad0779` | +| `clearQueue` | `0xf22cb874` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deliveryHelper__` | `0xc031dfb4` | +| `endTimeout` | `0x9c3bb867` | +| `finishRequest` | `0xeab148c0` | +| `getDeliveryHelperPlugAddress` | `0xb709bd9f` | +| `getFees` | `0xfbf4ec4b` | +| `getRequestMetadata` | `0x5f1dde51` | +| `handleRequestReverts` | `0x8fe9734f` | +| `increaseFees` | `0xe9b304da` | +| `initialize` | `0x7265580f` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `queue` | `0x1b9396f5` | +| `queuePayloadParams` | `0x3c362159` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `requests` | `0xb71a5e58` | +| `saltCounter` | `0xa04c6809` | +| `startRequestProcessing` | `0xf61474a9` | +| `transferOwnership` | `0xf2fde38b` | +| `updateBidTimeout` | `0xa29f83d1` | +| `watcherPrecompileConfig` | `0x8618a912` | +| `watcherPrecompileLimits` | `0xa71cd97d` | +| `watcherPrecompile__` | `0x1de360c3` | +| `withdrawTo` | `0x74c33667` | + +## FastSwitchboard + +| Function | Signature | +| ---------------------------- | ------------ | +| `allowPacket` | `0x21e9ec80` | +| `attest` | `0x63671b60` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `chainSlug` | `0xb349ba65` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `initialPacketCount` | `0x7c138814` | +| `isAttested` | `0xc13c2396` | +| `nextNonce` | `0x0cd55abf` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `registerSwitchboard` | `0x74f5b1fc` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `socket__` | `0xc6a261d2` | +| `transferOwnership` | `0xf2fde38b` | diff --git a/contracts/base/AppGatewayBase.sol b/contracts/base/AppGatewayBase.sol index 156f98bd..2b509aab 100644 --- a/contracts/base/AppGatewayBase.sol +++ b/contracts/base/AppGatewayBase.sol @@ -4,24 +4,20 @@ pragma solidity ^0.8.3; import "../protocol/utils/AddressResolverUtil.sol"; import "../interfaces/IAppGateway.sol"; import "../interfaces/IForwarder.sol"; -import "../interfaces/IDeliveryHelper.sol"; +import "../interfaces/IMiddleware.sol"; import "../interfaces/IPromise.sol"; import {FeesPlugin} from "../protocol/utils/FeesPlugin.sol"; -import {InvalidPromise, FeesNotSet} from "../protocol/utils/common/Errors.sol"; +import {InvalidPromise, FeesNotSet, AsyncModifierNotUsed} from "../protocol/utils/common/Errors.sol"; import {FAST} from "../protocol/utils/common/Constants.sol"; /// @title AppGatewayBase /// @notice Abstract contract for the app gateway abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin { - Read public override isReadCall; - Parallel public override isParallelCall; - uint256 public override gasLimit; - + OverrideParams public overrideParams; address public auctionManager; bytes public onCompleteData; bytes32 public sbType; - bool public isAsyncModifierSet; mapping(address => bool) public isValidPromise; @@ -32,11 +28,12 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin modifier async() { if (fees.feePoolChain == 0) revert FeesNotSet(); isAsyncModifierSet = true; - deliveryHelper().clearQueue(); + deliveryHelper__().clearQueue(); addressResolver__.clearPromises(); + _clearOverrides(); _; isAsyncModifierSet = false; - deliveryHelper().batch(fees, auctionManager, onCompleteData, sbType); + deliveryHelper__().batch(fees, auctionManager, onCompleteData); _markValidPromises(); onCompleteData = bytes(""); } @@ -56,11 +53,13 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin _setAddressResolver(addressResolver_); sbType = FAST; } + /// @notice Sets the switchboard type /// @param sbType_ The switchboard type function _setSbType(bytes32 sbType_) internal { sbType = sbType_; } + /// @notice Creates a contract ID /// @param contractName_ The contract name /// @return bytes32 The contract ID @@ -69,9 +68,9 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin } /// @notice Gets the current async ID - /// @return bytes32 The current async ID - function _getCurrentAsyncId() internal view returns (bytes32) { - return deliveryHelper().getCurrentAsyncId(); + /// @return uint40 The current async ID + function _getCurrentAsyncId() internal view returns (uint40) { + return watcherPrecompile__().getCurrentRequestCount(); } /// @notice Sets the auction manager @@ -92,7 +91,17 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin /// @param chainSlug_ The chain slug /// @return socketAddress_ The socket address function getSocketAddress(uint32 chainSlug_) public view returns (address) { - return watcherPrecompile__().sockets(chainSlug_); + return watcherPrecompileConfig().sockets(chainSlug_); + } + + /// @notice Sets the validity of an onchain contract (plug) to authorize it to send information to a specific AppGateway + /// @param chainSlug_ The unique identifier of the chain where the contract resides + /// @param contractId The bytes32 identifier of the contract to be validated + /// @param isValid Boolean flag indicating whether the contract is authorized (true) or not (false) + /// @dev This function retrieves the onchain address using the contractId and chainSlug, then calls the watcher precompile to update the plug's validity status + function _setValidPlug(uint32 chainSlug_, bytes32 contractId, bool isValid) internal { + address onchainAddress = getOnChainAddress(contractId, chainSlug_); + watcherPrecompileConfig().setIsValidPlug(chainSlug_, onchainAddress, isValid); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -115,22 +124,31 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin IsPlug isPlug_, bytes memory initCallData_ ) internal { + if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); + address asyncPromise = addressResolver__.deployAsyncPromiseContract(address(this)); isValidPromise[asyncPromise] = true; IPromise(asyncPromise).then(this.setAddress.selector, abi.encode(chainSlug_, contractId_)); onCompleteData = abi.encode(chainSlug_, true); - IDeliveryHelper(deliveryHelper()).queue( - isPlug_, - isParallelCall, - chainSlug_, - address(0), - asyncPromise, - 0, - CallType.DEPLOY, - creationCodeWithArgs[contractId_], - initCallData_ - ); + + QueuePayloadParams memory queuePayloadParams = QueuePayloadParams({ + chainSlug: chainSlug_, + callType: CallType.DEPLOY, + isParallel: overrideParams.isParallelCall, + isPlug: isPlug_, + writeFinality: overrideParams.writeFinality, + asyncPromise: asyncPromise, + switchboard: watcherPrecompileConfig().switchboards(chainSlug_, sbType), + target: address(0), + appGateway: address(this), + gasLimit: overrideParams.gasLimit, + value: 0, + readAt: overrideParams.readAt, + payload: creationCodeWithArgs[contractId_], + initCallData: initCallData_ + }); + IMiddleware(deliveryHelper__()).queue(queuePayloadParams); } /// @notice Sets the address for a deployed contract @@ -179,46 +197,76 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin uint256 gasLimit_, Fees memory fees_ ) internal { - isReadCall = isReadCall_; - isParallelCall = isParallelCall_; - gasLimit = gasLimit_; + overrideParams.isReadCall = isReadCall_; + overrideParams.isParallelCall = isParallelCall_; + overrideParams.gasLimit = gasLimit_; fees = fees_; } + function _clearOverrides() internal { + overrideParams.isReadCall = Read.OFF; + overrideParams.isParallelCall = Parallel.OFF; + overrideParams.gasLimit = 0; + overrideParams.readAt = 0; + overrideParams.writeFinality = WriteFinality.LOW; + } + /// @notice Sets isReadCall, fees and gasLimit overrides /// @param isReadCall_ The read call flag /// @param isParallelCall_ The sequential call flag /// @param gasLimit_ The gas limit function _setOverrides(Read isReadCall_, Parallel isParallelCall_, uint256 gasLimit_) internal { - isReadCall = isReadCall_; - isParallelCall = isParallelCall_; - gasLimit = gasLimit_; + overrideParams.isReadCall = isReadCall_; + overrideParams.isParallelCall = isParallelCall_; + overrideParams.gasLimit = gasLimit_; } /// @notice Sets isReadCall and isParallelCall overrides /// @param isReadCall_ The read call flag /// @param isParallelCall_ The sequential call flag function _setOverrides(Read isReadCall_, Parallel isParallelCall_) internal { - isReadCall = isReadCall_; - isParallelCall = isParallelCall_; + overrideParams.isReadCall = isReadCall_; + overrideParams.isParallelCall = isParallelCall_; + } + + /// @notice Sets isParallelCall overrides + /// @param writeFinality_ The write finality + function _setOverrides(WriteFinality writeFinality_) internal { + overrideParams.writeFinality = writeFinality_; } /// @notice Sets isParallelCall overrides /// @param isParallelCall_ The sequential call flag function _setOverrides(Parallel isParallelCall_) internal { - isParallelCall = isParallelCall_; + overrideParams.isParallelCall = isParallelCall_; + } + + /// @notice Sets isParallelCall overrides + /// @param isParallelCall_ The sequential call flag + /// @param readAt_ The read anchor value. Currently block number. + function _setOverrides(Parallel isParallelCall_, uint256 readAt_) internal { + overrideParams.isParallelCall = isParallelCall_; + overrideParams.readAt = readAt_; } /// @notice Sets isReadCall overrides /// @param isReadCall_ The read call flag function _setOverrides(Read isReadCall_) internal { - isReadCall = isReadCall_; + overrideParams.isReadCall = isReadCall_; + } + + /// @notice Sets isReadCall overrides + /// @param isReadCall_ The read call flag + /// @param readAt_ The read anchor value. Currently block number. + function _setOverrides(Read isReadCall_, uint256 readAt_) internal { + overrideParams.isReadCall = isReadCall_; + overrideParams.readAt = readAt_; } /// @notice Sets gasLimit overrides /// @param gasLimit_ The gas limit function _setOverrides(uint256 gasLimit_) internal { - gasLimit = gasLimit_; + overrideParams.gasLimit = gasLimit_; } /// @notice Sets fees overrides @@ -227,20 +275,35 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin fees = fees_; } + function getOverrideParams() + public + view + returns (Read, Parallel, WriteFinality, uint256, uint256, bytes32) + { + return ( + overrideParams.isReadCall, + overrideParams.isParallelCall, + overrideParams.writeFinality, + overrideParams.readAt, + overrideParams.gasLimit, + sbType + ); + } + //////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////// ASYNC BATCH HELPERS ///////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// /// @notice Reverts the transaction - /// @param asyncId_ The async ID - function _revertTx(bytes32 asyncId_) internal { - deliveryHelper().cancelTransaction(asyncId_); + /// @param requestCount_ The async ID + function _revertTx(uint40 requestCount_) internal { + deliveryHelper__().cancelRequest(requestCount_); } /// @notice increases the transaction fees - /// @param asyncId_ The async ID - function _increaseFees(bytes32 asyncId_, uint256 newMaxFees_) internal { - deliveryHelper().increaseFees(asyncId_, newMaxFees_); + /// @param requestCount_ The async ID + function _increaseFees(uint40 requestCount_, uint256 newMaxFees_) internal { + deliveryHelper__().increaseFees(requestCount_, newMaxFees_); } /// @notice Withdraws fee tokens @@ -253,8 +316,16 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin address token_, uint256 amount_, address receiver_ - ) internal { - deliveryHelper().withdrawTo(chainSlug_, token_, amount_, receiver_, auctionManager, fees); + ) internal returns (uint40) { + return + deliveryHelper__().withdrawTo( + chainSlug_, + token_, + amount_, + receiver_, + auctionManager, + fees + ); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -262,19 +333,12 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin //////////////////////////////////////////////////////////////////////////////////////////////// /// @notice Callback in pd promise to be called after all contracts are deployed - /// @param payloadBatch_ The payload batch + /// @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 onBatchComplete( - bytes32, - PayloadBatch memory payloadBatch_ - ) external override onlyDeliveryHelper { - if (payloadBatch_.onCompleteData.length == 0) return; - - (uint32 chainSlug, bool isDeploy) = abi.decode( - payloadBatch_.onCompleteData, - (uint32, bool) - ); + function onRequestComplete(uint40, bytes calldata onCompleteData_) external override { + if (onCompleteData_.length == 0) return; + (uint32 chainSlug, bool isDeploy) = abi.decode(onCompleteData_, (uint32, bool)); if (isDeploy) { initialize(chainSlug); } @@ -283,8 +347,8 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin function callFromChain( uint32 chainSlug_, address plug_, - bytes calldata payload_, - bytes32 params_ + bytes32 params_, + bytes calldata payload_ ) external virtual onlyWatcherPrecompile {} /// @notice Initializes the contract @@ -293,7 +357,10 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin /// @notice hook to handle the revert in callbacks or onchain executions /// @dev can be overridden by the app gateway to add custom logic - /// @param asyncId_ The async ID + /// @param requestCount_ The async ID /// @param payloadId_ The payload ID - function handleRevert(bytes32 asyncId_, bytes32 payloadId_) external override onlyPromises {} + function handleRevert( + uint40 requestCount_, + bytes32 payloadId_ + ) external override onlyPromises {} } diff --git a/contracts/base/PlugBase.sol b/contracts/base/PlugBase.sol index 66a1e943..4707cff4 100644 --- a/contracts/base/PlugBase.sol +++ b/contracts/base/PlugBase.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.21; -import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol"; import {ISocket} from "../interfaces/ISocket.sol"; import {IPlug} from "../interfaces/IPlug.sol"; import {NotSocket} from "../protocol/utils/common/Errors.sol"; + /// @title PlugBase /// @notice Abstract contract for plugs abstract contract PlugBase is IPlug { @@ -40,7 +40,7 @@ abstract contract PlugBase is IPlug { } /// @notice Disconnects the plug from the socket - function _disconnect() internal { + function _disconnectSocket() internal { (, address switchboard) = socket__.getPlugConfig(address(this)); socket__.connect(address(0), switchboard); emit ConnectorPlugDisconnected(); diff --git a/contracts/interfaces/IAddressResolver.sol b/contracts/interfaces/IAddressResolver.sol index a495af5d..7a34fcbd 100644 --- a/contracts/interfaces/IAddressResolver.sol +++ b/contracts/interfaces/IAddressResolver.sol @@ -13,7 +13,7 @@ interface IAddressResolver { event AddressSet(bytes32 indexed name, address oldAddress, address newAddress); /// @notice Gets the address of the delivery helper contract - /// @return IDeliveryHelper The delivery helper interface + /// @return IMiddleware The delivery helper interface /// @dev Returns interface pointing to zero address if not configured function deliveryHelper() external view returns (address); diff --git a/contracts/interfaces/IAppGateway.sol b/contracts/interfaces/IAppGateway.sol index 38e68fee..9bd9a649 100644 --- a/contracts/interfaces/IAppGateway.sol +++ b/contracts/interfaces/IAppGateway.sol @@ -1,27 +1,26 @@ // SPDX-License-Identifier: Unlicense pragma solidity ^0.8.21; -import {Fees, Read, Parallel, DeployParams, CallType, PayloadBatch} from "../protocol/utils/common/Structs.sol"; +import {Fees, Read, Parallel, QueuePayloadParams, OverrideParams, CallType, WriteFinality, PayloadParams} from "../protocol/utils/common/Structs.sol"; interface IAppGateway { - function isReadCall() external view returns (Read); - - function isParallelCall() external view returns (Parallel); - - function gasLimit() external view returns (uint256); - function isAsyncModifierSet() external view returns (bool); - function onBatchComplete(bytes32 asyncId_, PayloadBatch memory payloadBatch_) external; + function getOverrideParams() + external + view + returns (Read, Parallel, WriteFinality, uint256, uint256, bytes32); + + function onRequestComplete(uint40 requestCount_, bytes calldata onCompleteData_) external; function callFromChain( uint32 chainSlug_, address plug_, - bytes calldata payload_, - bytes32 params_ + bytes32 params_, + bytes calldata payload_ ) external; - function handleRevert(bytes32 asyncId_, bytes32 payloadId_) external; + function handleRevert(uint40 requestCount_, bytes32 payloadId_) external; /// @notice initialize the contracts on chain function initialize(uint32 chainSlug_) external; diff --git a/contracts/interfaces/IAuctionManager.sol b/contracts/interfaces/IAuctionManager.sol index 69b38a72..bee93dc1 100644 --- a/contracts/interfaces/IAuctionManager.sol +++ b/contracts/interfaces/IAuctionManager.sol @@ -5,15 +5,15 @@ import {Bid, Fees} from "../protocol/utils/common/Structs.sol"; interface IAuctionManager { function bid( - bytes32 asyncId_, + uint40 requestCount_, uint256 fee_, bytes memory transmitterSignature_, bytes memory extraData_ ) external; - function endAuction(bytes32 asyncId_) external; + function endAuction(uint40 requestCount_) external; - function auctionClosed(bytes32 asyncId_) external view returns (bool); + function auctionClosed(uint40 requestCount_) external view returns (bool); - function auctionStarted(bytes32 asyncId_) external view returns (bool); + function auctionStarted(uint40 requestCount_) external view returns (bool); } diff --git a/contracts/interfaces/IDeliveryHelper.sol b/contracts/interfaces/IDeliveryHelper.sol deleted file mode 100644 index 2f9d15ae..00000000 --- a/contracts/interfaces/IDeliveryHelper.sol +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.3; -import {PayloadDetails, Bid, Fees, DeployParams, CallType, PayloadBatch, Parallel, IsPlug} from "../protocol/utils/common/Structs.sol"; - -interface IDeliveryHelper { - event BidPlaced( - bytes32 indexed asyncId, - Bid bid // Replaced transmitter and bidAmount with Bid struct - ); - - event AuctionEnded( - bytes32 indexed asyncId, - Bid winningBid // Replaced winningTransmitter and winningBid with Bid struct - ); - - function bidTimeout() external view returns (uint128); - - function payloadBatches(bytes32) external view returns (PayloadBatch memory); - - function clearQueue() external; - - function queue( - IsPlug isPlug_, - Parallel isParallel_, - uint32 chainSlug_, - address target_, - address asyncPromise_, - uint256 value_, - CallType callType_, - bytes memory payload_, - bytes memory initCallData_ - ) external; - - function batch( - Fees memory fees_, - address auctionManager_, - bytes memory onCompleteData_, - bytes32 sbType_ - ) external returns (bytes32); - - function withdrawTo( - uint32 chainSlug_, - address token_, - uint256 amount_, - address receiver_, - address auctionManager_, - Fees memory fees_ - ) external; - - function cancelTransaction(bytes32 asyncId_) external; - - function increaseFees(bytes32 asyncId_, uint256 fees_) external; - - function startBatchProcessing(bytes32 asyncId_, Bid memory winningBid_) external; - - function getFees(bytes32 asyncId_) external view returns (Fees memory); - - function getCurrentAsyncId() external view returns (bytes32); - - function getAsyncBatchDetails(bytes32 asyncId_) external view returns (PayloadBatch memory); -} diff --git a/contracts/interfaces/IFeesManager.sol b/contracts/interfaces/IFeesManager.sol index 906e9ea5..a76d6d43 100644 --- a/contracts/interfaces/IFeesManager.sol +++ b/contracts/interfaces/IFeesManager.sol @@ -1,31 +1,31 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.3; -import {Fees, Bid, PayloadDetails} from "../protocol/utils/common/Structs.sol"; +import {Fees, Bid, QueuePayloadParams} from "../protocol/utils/common/Structs.sol"; interface IFeesManager { function blockFees( address appGateway_, Fees memory fees_, Bid memory winningBid_, - bytes32 asyncId_ + uint40 requestCount_ ) external; - function unblockFees(bytes32 asyncId_, address appGateway_) external; + function unblockFees(uint40 requestCount_) external; function isFeesEnough(address appGateway_, Fees memory fees_) external view returns (bool); function unblockAndAssignFees( - bytes32 asyncId_, + uint40 requestCount_, address transmitter_, address appGateway_ ) external; - function getWithdrawToPayload( + function withdrawFees( address appGateway_, uint32 chainSlug_, address token_, uint256 amount_, address receiver_ - ) external returns (PayloadDetails memory); + ) external; } diff --git a/contracts/interfaces/IMiddleware.sol b/contracts/interfaces/IMiddleware.sol new file mode 100644 index 00000000..3509457d --- /dev/null +++ b/contracts/interfaces/IMiddleware.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.3; +import {QueuePayloadParams, Bid, Fees, WriteFinality, CallType, Parallel, IsPlug, RequestMetadata} from "../protocol/utils/common/Structs.sol"; + +interface IMiddleware { + event AuctionEnded( + uint40 indexed requestCount, + Bid winningBid // Replaced winningTransmitter and winningBid with Bid struct + ); + + function bidTimeout() external view returns (uint128); + + function getRequestMetadata( + uint40 requestCount_ + ) external view returns (RequestMetadata memory); + + function clearQueue() external; + + function queue(QueuePayloadParams memory queuePayloadParams_) external; + + function batch( + Fees memory fees_, + address auctionManager_, + bytes memory onCompleteData_ + ) external returns (uint40 requestCount); + + function withdrawTo( + uint32 chainSlug_, + address token_, + uint256 amount_, + address receiver_, + address auctionManager_, + Fees memory fees_ + ) external returns (uint40); + + function cancelRequest(uint40 requestCount_) external; + + function increaseFees(uint40 requestCount_, uint256 fees_) external; + + function startRequestProcessing(uint40 requestCount_, Bid memory winningBid_) external; + + function getFees(uint40 requestCount_) external view returns (Fees memory); + + function finishRequest(uint40 requestCount_) external; + + function handleRequestReverts(uint40 requestCount_) external; +} diff --git a/contracts/interfaces/IPromise.sol b/contracts/interfaces/IPromise.sol index 426d4953..13318ac0 100644 --- a/contracts/interfaces/IPromise.sol +++ b/contracts/interfaces/IPromise.sol @@ -5,12 +5,12 @@ interface IPromise { function then(bytes4 selector_, bytes memory data_) external returns (address _promise); function markResolved( - bytes32 asyncId_, + uint40 requestCount_, bytes32 payloadId_, bytes memory returnData_ ) external returns (bool success); - function markOnchainRevert(bytes32 asyncId_, bytes32 payloadId_) external; + function markOnchainRevert(uint40 requestCount_, bytes32 payloadId_) external; function resolved() external view returns (bool); } diff --git a/contracts/interfaces/ISocket.sol b/contracts/interfaces/ISocket.sol index d46f6eca..1d7e1a1e 100644 --- a/contracts/interfaces/ISocket.sol +++ b/contracts/interfaces/ISocket.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; +import {ExecuteParams} from "../protocol/utils/common/Structs.sol"; /** * @title ISocket * @notice An interface for a Chain Abstraction contract @@ -48,22 +49,6 @@ interface ISocket { bytes payload ); - /** - * @notice params for executing a payload - * @param payloadId the id of the payload - * @param target the address of the contract to call - * @param executionGasLimit the gas limit for the execution - * @param deadline the deadline for the execution - * @param payload the data to be executed - */ - struct ExecuteParams { - bytes32 payloadId; - address target; - uint256 executionGasLimit; - uint256 deadline; - bytes payload; - } - /** * @notice To call the appGateway on EVMx. Should only be called by a plug. * @param payload_ bytes to be delivered to the Plug on EVMx @@ -78,8 +63,7 @@ interface ISocket { * @notice executes a payload */ function execute( - address appGateway_, - ExecuteParams memory params_, + ExecuteParams memory executeParams_, bytes memory transmitterSignature_ ) external payable returns (bytes memory); diff --git a/contracts/interfaces/ISocketBatcher.sol b/contracts/interfaces/ISocketBatcher.sol index 1626e0ae..ab753866 100644 --- a/contracts/interfaces/ISocketBatcher.sol +++ b/contracts/interfaces/ISocketBatcher.sol @@ -1,10 +1,13 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "../protocol/utils/common/Structs.sol"; +import {ExecuteParams} from "../protocol/utils/common/Structs.sol"; interface ISocketBatcher { function attestAndExecute( - AttestAndExecutePayloadParams calldata params_ - ) external returns (bytes memory); + ExecuteParams calldata executeParams_, + bytes32 digest_, + bytes calldata proof_, + bytes calldata transmitterSignature_ + ) external payable returns (bytes memory); } diff --git a/contracts/interfaces/ISwitchboard.sol b/contracts/interfaces/ISwitchboard.sol index 394d4044..c6998445 100644 --- a/contracts/interfaces/ISwitchboard.sol +++ b/contracts/interfaces/ISwitchboard.sol @@ -3,17 +3,17 @@ pragma solidity ^0.8.21; /** * @title ISwitchboard - * @dev The interface for a switchboard contract that is responsible for verification of packets between + * @dev The interface for a switchboard contract that is responsible for verification of payloadss between * different blockchain networks. */ interface ISwitchboard { /** - * @notice Checks if a packet can be allowed to go through the switchboard. - * @param digest_ the packet digest. - * @param packetId_ The unique identifier for the packet. - * @return A boolean indicating whether the packet is allowed to go through the switchboard or not. + * @notice Checks if a payloads can be allowed to go through the switchboard. + * @param digest_ the payloads digest. + * @param payloadId_ The unique identifier for the payloads. + * @return A boolean indicating whether the payloads is allowed to go through the switchboard or not. */ - function allowPacket(bytes32 digest_, bytes32 packetId_) external view returns (bool); + function allowPacket(bytes32 digest_, bytes32 payloadId_) external view returns (bool); - function attest(bytes32 payloadId_, bytes32 digest_, bytes calldata proof_) external; + function attest(bytes32 digest_, bytes calldata proof_) external; } diff --git a/contracts/interfaces/IWatcherPrecompile.sol b/contracts/interfaces/IWatcherPrecompile.sol index 0a54fa6a..5ce28d64 100644 --- a/contracts/interfaces/IWatcherPrecompile.sol +++ b/contracts/interfaces/IWatcherPrecompile.sol @@ -1,70 +1,124 @@ // SPDX-License-Identifier: Unlicense pragma solidity ^0.8.21; -import {PayloadDetails, AsyncRequest, FinalizeParams, PayloadDigestParams, AppGatewayConfig, PlugConfig, ResolvedPromises} from "../protocol/utils/common/Structs.sol"; +import {DigestParams, ResolvedPromises, PayloadParams, CallFromChainParams, PayloadSubmitParams, RequestParams} from "../protocol/utils/common/Structs.sol"; +import {IWatcherPrecompileLimits} from "./IWatcherPrecompileLimits.sol"; +import {IWatcherPrecompileConfig} from "./IWatcherPrecompileConfig.sol"; /// @title IWatcherPrecompile /// @notice Interface for the Watcher Precompile system that handles payload verification and execution /// @dev Defines core functionality for payload processing and promise resolution interface IWatcherPrecompile { - /// @notice Sets up app gateway configurations - /// @param configs_ Array of app gateway configurations - /// @param signatureNonce_ The nonce of the signature - /// @param signature_ The signature of the watcher - /// @dev Only callable by authorized addresses - function setAppGateways( - AppGatewayConfig[] calldata configs_, + event CalledAppGateway( + bytes32 callId, + uint32 chainSlug, + address plug, + address appGateway, + bytes32 params, + bytes payload + ); + + /// @notice Emitted when a new query is requested + event QueryRequested(PayloadParams params); + + /// @notice Emitted when a finalize request is made + event FinalizeRequested(bytes32 digest, PayloadParams params); + + /// @notice Emitted when a request is finalized + /// @param payloadId The unique identifier for the request + /// @param proof The proof from the watcher + event Finalized(bytes32 indexed payloadId, bytes proof); + + /// @notice Emitted when a promise is resolved + /// @param payloadId The unique identifier for the resolved promise + event PromiseResolved(bytes32 indexed payloadId, address asyncPromise); + + /// @notice Emitted when a promise is not resolved + /// @param payloadId The unique identifier for the not resolved promise + event PromiseNotResolved(bytes32 indexed payloadId, address asyncPromise); + + event MarkedRevert(bytes32 indexed payloadId, bool isRevertingOnchain); + event TimeoutRequested( + bytes32 timeoutId, + address target, + bytes payload, + uint256 executeAt // Epoch time when the task should execute + ); + + /// @notice Emitted when a timeout is resolved + /// @param timeoutId The unique identifier for the timeout + /// @param target The target address for the timeout + /// @param payload The payload data + /// @param executedAt The epoch time when the task was executed + event TimeoutResolved(bytes32 timeoutId, address target, bytes payload, uint256 executedAt); + + event RequestSubmitted( + address middleware, + uint40 requestCount, + PayloadParams[] payloadParamsArray + ); + + /// @notice Error thrown when an invalid chain slug is provided + error InvalidChainSlug(); + /// @notice Error thrown when an invalid app gateway reaches a plug + error InvalidConnection(); + /// @notice Error thrown if winning bid is assigned to an invalid transmitter + error InvalidTransmitter(); + /// @notice Error thrown when a timeout request is invalid + error InvalidTimeoutRequest(); + /// @notice Error thrown when a payload id is invalid + error InvalidPayloadId(); + /// @notice Error thrown when a caller is invalid + error InvalidCaller(); + /// @notice Error thrown when a gateway is invalid + error InvalidGateway(); + /// @notice Error thrown when a switchboard is invalid + error InvalidSwitchboard(); + /// @notice Error thrown when a request is already cancelled + error RequestAlreadyCancelled(); + + error RequestCancelled(); + error AlreadyStarted(); + error InvalidLevelNumber(); + + /// @notice Calculates the digest hash of payload parameters + /// @param params_ The payload parameters + /// @return digest The calculated digest + function getDigest(DigestParams memory params_) external pure returns (bytes32 digest); + + /// @notice Gets the batch IDs for a request + /// @param requestCount_ The request count + /// @return Array of batch IDs + function getBatches(uint40 requestCount_) external view returns (uint40[] memory); + + /// @notice Gets the payload IDs for a batch + /// @param batchCount_ The batch count + /// @return Array of payload IDs + function getBatchPayloadIds(uint40 batchCount_) external view returns (bytes32[] memory); + + /// @notice Gets the payload parameters for a payload ID + /// @param payloadId_ The payload ID + /// @return The payload parameters + function getPayloadParams(bytes32 payloadId_) external view returns (PayloadParams memory); + + function setTimeout( + uint256 delayInSeconds_, + bytes calldata payload_ + ) external returns (bytes32); + + function resolveTimeout( + bytes32 timeoutId_, uint256 signatureNonce_, bytes calldata signature_ ) external; - /// @notice Sets up on-chain contract configurations - /// @dev Only callable by authorized addresses - function setOnChainContracts( - uint32 chainSlug_, - bytes32 sbType_, - address switchboard_, - address socket_, - address contractFactoryPlug_, - address feesPlug_ - ) external; - - /// @notice Retrieves plug configuration for a specific network and plug - /// @param chainSlug_ The identifier of the network - /// @param plug_ The address of the plug - /// @return appGateway The configured app gateway address - /// @return switchboard The configured switchboard address - function getPlugConfigs( - uint32 chainSlug_, - address plug_ - ) external view returns (address appGateway, address switchboard); - - /// @notice Finalizes a payload execution request - /// @param params_ Parameters needed for finalization - /// @return payloadId The unique identifier for the request - /// @return digest The digest of the payload parameters function finalize( - address originAppGateway_, - FinalizeParams memory params_ - ) external returns (bytes32 payloadId, bytes32 digest); - - /// @notice Creates a new query request - /// @param chainSlug_ The identifier of the destination network - /// @param targetAddress_ The address of the target contract - /// @param asyncPromises_ Array of promise addresses to be resolved - /// @param payload_ The query payload data - /// @return payloadId The unique identifier for the query - function query( - uint32 chainSlug_, - address targetAddress_, - address appGateway_, - address[] memory asyncPromises_, - bytes memory payload_ - ) external returns (bytes32 payloadId); - - /// @notice Marks a request as finalized with a proof - /// @param payloadId_ The unique identifier of the request - /// @param proof_ The watcher's proof + PayloadParams memory params_, + address transmitter_ + ) external returns (bytes32 digest); + + function query(PayloadParams memory params_) external; + function finalized( bytes32 payloadId_, bytes calldata proof_, @@ -72,56 +126,44 @@ interface IWatcherPrecompile { bytes calldata signature_ ) external; - /// @notice Finalizes multiple payload execution requests with a new transmitter - /// @param payloadId_ The unique identifier of the request - /// @param params_ The parameters for finalization - function refinalize(bytes32 payloadId_, FinalizeParams memory params_) external; + function updateTransmitter(uint40 requestCount, address transmitter) external; + + function cancelRequest(uint40 requestCount) external; - /// @notice Resolves multiple promises with their return data - /// @param resolvedPromises_ Array of resolved promises and their return data function resolvePromises( ResolvedPromises[] calldata resolvedPromises_, uint256 signatureNonce_, bytes calldata signature_ ) external; - /// @notice Sets a timeout for payload execution - /// @param payload_ The payload data - /// @param delayInSeconds_ The timeout duration in seconds - function setTimeout( - address appGateway_, - bytes calldata payload_, - uint256 delayInSeconds_ + function markRevert( + bool isRevertingOnchain_, + bytes32 payloadId_, + uint256 signatureNonce_, + bytes calldata signature_ ) external; - /// @notice Resolves a timeout by executing the payload - /// @param timeoutId_ The unique identifier for the timeout - function resolveTimeout( - bytes32 timeoutId_, + function setMaxTimeoutDelayInSeconds(uint256 maxTimeoutDelayInSeconds_) external; + + function callAppGateways( + CallFromChainParams[] calldata params_, uint256 signatureNonce_, bytes calldata signature_ ) external; - /// @notice Calculates the Digest hash for payload parameters - /// @param params_ The payload parameters used to calculate the digest - /// @return digest The calculated digest hash - function getDigest(PayloadDigestParams memory params_) external pure returns (bytes32 digest); + function setExpiryTime(uint256 expiryTime_) external; - function setMaxTimeoutDelayInSeconds(uint256 maxTimeoutDelayInSeconds_) external; + function submitRequest( + PayloadSubmitParams[] calldata payloadSubmitParams + ) external returns (uint40 requestCount); - function switchboards(uint32 chainSlug_, bytes32 sbType_) external view returns (address); + function startProcessingRequest(uint40 requestCount, address transmitter) external; - function sockets(uint32 chainSlug_) external view returns (address); + function getCurrentRequestCount() external view returns (uint40); - function contractFactoryPlug(uint32 chainSlug_) external view returns (address); + function watcherPrecompileConfig__() external view returns (IWatcherPrecompileConfig); - function feesPlug(uint32 chainSlug_) external view returns (address); + function watcherPrecompileLimits__() external view returns (IWatcherPrecompileLimits); - function setIsValidPlug(uint32 chainSlug_, address plug_, bool isValid_) external; - - function checkAndConsumeLimit( - address appGateway_, - bytes32 limitType_, - uint256 consumeLimit_ - ) external; + function getRequestParams(uint40 requestCount) external view returns (RequestParams memory); } diff --git a/contracts/interfaces/IWatcherPrecompileConfig.sol b/contracts/interfaces/IWatcherPrecompileConfig.sol new file mode 100644 index 00000000..d42c7294 --- /dev/null +++ b/contracts/interfaces/IWatcherPrecompileConfig.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.21; + +import {AppGatewayConfig, PlugConfig} from "../protocol/utils/common/Structs.sol"; + +/// @title IWatcherPrecompileConfig +/// @notice Interface for the Watcher Precompile system that handles payload verification and execution +/// @dev Defines core functionality for payload processing and promise resolution +interface IWatcherPrecompileConfig { + /// @notice The chain slug of the watcher precompile + function evmxSlug() external view returns (uint32); + + /// @notice Maps chain slug to their associated switchboard + function switchboards(uint32 chainSlug, bytes32 sbType) external view returns (address); + + /// @notice Maps chain slug to their associated socket + function sockets(uint32 chainSlug) external view returns (address); + + /// @notice Maps chain slug to their associated contract factory plug + function contractFactoryPlug(uint32 chainSlug) external view returns (address); + + /// @notice Maps chain slug to their associated fees plug + function feesPlug(uint32 chainSlug) external view returns (address); + + /// @notice Maps nonce to whether it has been used + function isNonceUsed(uint256 nonce) external view returns (bool); + + /// @notice Maps app gateway, chain slug and plug to validity + function isValidPlug( + address appGateway, + uint32 chainSlug, + address plug + ) external view returns (bool); + + /// @notice Sets the switchboard for a network + function setSwitchboard(uint32 chainSlug_, bytes32 sbType_, address switchboard_) external; + + /// @notice Sets valid plugs for each chain slug + function setIsValidPlug(uint32 chainSlug_, address plug_, bool isValid_) external; + + /// @notice Retrieves the configuration for a specific plug on a network + function getPlugConfigs( + uint32 chainSlug_, + address plug_ + ) external view returns (address, address); + + /// @notice Verifies connections between components + function verifyConnections( + uint32 chainSlug_, + address target_, + address appGateway_, + address switchboard_ + ) external view; + + function setAppGateways( + AppGatewayConfig[] calldata configs_, + uint256 signatureNonce_, + bytes calldata signature_ + ) external; +} diff --git a/contracts/interfaces/IWatcherPrecompileLimits.sol b/contracts/interfaces/IWatcherPrecompileLimits.sol new file mode 100644 index 00000000..70a0c01a --- /dev/null +++ b/contracts/interfaces/IWatcherPrecompileLimits.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.21; + +import {LimitParams, UpdateLimitParams} from "../protocol/utils/common/Structs.sol"; + +/// @title IWatcherPrecompileLimits +/// @notice Interface for the Watcher Precompile system that handles payload verification and execution +/// @dev Defines core functionality for payload processing and promise resolution +interface IWatcherPrecompileLimits { + /// @notice Get the current limit for a specific app gateway and limit type + /// @param limitType_ The type of limit to query + /// @param appGateway_ The app gateway address + /// @return The current limit value + function getCurrentLimit( + bytes32 limitType_, + address appGateway_ + ) external view returns (uint256); + + /// @notice Get the limit parameters for a specific app gateway and limit type + /// @param limitType_ The type of limit to query + /// @param appGateway_ The app gateway address + /// @return The limit parameters + function getLimitParams( + bytes32 limitType_, + address appGateway_ + ) external view returns (LimitParams memory); + + /// @notice Update limit parameters for multiple app gateways + /// @param updates_ Array of limit parameter updates + function updateLimitParams(UpdateLimitParams[] calldata updates_) external; + + /// @notice Set the default limit value + /// @param defaultLimit_ The new default limit value + function setDefaultLimit(uint256 defaultLimit_) external; + + /// @notice Set the rate at which limit replenishes + /// @param defaultRatePerSecond_ The new rate per second + function setDefaultRatePerSecond(uint256 defaultRatePerSecond_) external; + + /// @notice Number of decimals used in limit calculations + function LIMIT_DECIMALS() external view returns (uint256); + + /// @notice Default limit value for any app gateway + function defaultLimit() external view returns (uint256); + + /// @notice Rate at which limit replenishes per second + function defaultRatePerSecond() external view returns (uint256); + + function consumeLimit(address appGateway_, bytes32 limitType_, uint256 consumeLimit_) external; + + /// @notice Emitted when limit parameters are updated + event LimitParamsUpdated(UpdateLimitParams[] updates); + + /// @notice Emitted when an app gateway is activated with default limits + event AppGatewayActivated(address indexed appGateway, uint256 maxLimit, uint256 ratePerSecond); + + error ActionNotSupported(address appGateway_, bytes32 limitType_); + error NotDeliveryHelper(); + error LimitExceeded( + address appGateway, + bytes32 limitType, + uint256 requested, + uint256 available + ); +} diff --git a/contracts/protocol/AddressResolver.sol b/contracts/protocol/AddressResolver.sol index 82c329f4..df9bf3b6 100644 --- a/contracts/protocol/AddressResolver.sol +++ b/contracts/protocol/AddressResolver.sol @@ -118,8 +118,7 @@ contract AddressResolver is AddressResolverStorage, Initializable, Ownable { Forwarder.initialize.selector, chainSlug_, chainContractAddress_, - address(this), - version + address(this) ); salt = keccak256(constructorArgs); } @@ -132,8 +131,7 @@ contract AddressResolver is AddressResolverStorage, Initializable, Ownable { AsyncPromise.initialize.selector, invoker_, msg.sender, - address(this), - version + address(this) ); salt = keccak256(abi.encodePacked(constructorArgs, asyncPromiseCounter)); diff --git a/contracts/protocol/AsyncPromise.sol b/contracts/protocol/AsyncPromise.sol index 4f5b0664..ff81e4b7 100644 --- a/contracts/protocol/AsyncPromise.sol +++ b/contracts/protocol/AsyncPromise.sol @@ -5,15 +5,7 @@ import {AddressResolverUtil} from "./utils/AddressResolverUtil.sol"; import {IPromise} from "../interfaces/IPromise.sol"; import {IAppGateway} from "../interfaces/IAppGateway.sol"; import {Initializable} from "solady/utils/Initializable.sol"; - -/// @notice The state of the async promise -enum AsyncPromiseState { - WAITING_FOR_SET_CALLBACK_SELECTOR, - WAITING_FOR_CALLBACK_EXECUTION, - CALLBACK_REVERTING, - ONCHAIN_REVERTING, - RESOLVED -} +import {AsyncPromiseState} from "../protocol/utils/common/Structs.sol"; abstract contract AsyncPromiseStorage is IPromise { // slots [0-49] reserved for gap @@ -85,11 +77,11 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil /// @param returnData_ The data returned from the async payload execution. /// @dev Only callable by the watcher precompile. function markResolved( - bytes32 asyncId, - bytes32 payloadId, + uint40 requestCount_, + bytes32 payloadId_, bytes memory returnData_ ) external override onlyWatcherPrecompile returns (bool success) { - if (resolved) return true; + if (resolved) revert PromiseAlreadyResolved(); resolved = true; state = AsyncPromiseState.RESOLVED; @@ -103,25 +95,29 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil (success, ) = localInvoker.call(combinedCalldata); if (success) return success; - _handleRevert(asyncId, payloadId, AsyncPromiseState.CALLBACK_REVERTING); + _handleRevert(requestCount_, payloadId_, AsyncPromiseState.CALLBACK_REVERTING); } /// @notice Marks the promise as onchain reverting. /// @dev Only callable by the watcher precompile. function markOnchainRevert( - bytes32 asyncId, - bytes32 payloadId + uint40 requestCount_, + bytes32 payloadId_ ) external override onlyWatcherPrecompile { - _handleRevert(asyncId, payloadId, AsyncPromiseState.ONCHAIN_REVERTING); + _handleRevert(requestCount_, payloadId_, AsyncPromiseState.ONCHAIN_REVERTING); } - function _handleRevert(bytes32 asyncId, bytes32 payloadId, AsyncPromiseState state_) internal { + function _handleRevert( + uint40 requestCount_, + bytes32 payloadId_, + AsyncPromiseState state_ + ) internal { // to update the state in case selector is bytes(0) but reverting onchain resolved = false; state = state_; (bool success, ) = localInvoker.call( - abi.encodeWithSelector(IAppGateway.handleRevert.selector, asyncId, payloadId) + abi.encodeWithSelector(IAppGateway.handleRevert.selector, requestCount_, payloadId_) ); if (!success) revert PromiseRevertFailed(); } diff --git a/contracts/protocol/Forwarder.sol b/contracts/protocol/Forwarder.sol index 13785b7b..d9231e1a 100644 --- a/contracts/protocol/Forwarder.sol +++ b/contracts/protocol/Forwarder.sol @@ -2,10 +2,12 @@ pragma solidity ^0.8.21; import "../interfaces/IAddressResolver.sol"; -import "../interfaces/IDeliveryHelper.sol"; +import "../interfaces/IMiddleware.sol"; import "../interfaces/IAppGateway.sol"; import "../interfaces/IPromise.sol"; import "../interfaces/IForwarder.sol"; + +import {AddressResolverUtil} from "./utils/AddressResolverUtil.sol"; import "solady/utils/Initializable.sol"; abstract contract ForwarderStorage is IForwarder { @@ -16,25 +18,20 @@ abstract contract ForwarderStorage is IForwarder { /// @notice chain id uint32 public chainSlug; - // slot 51 /// @notice on-chain address associated with this forwarder address public onChainAddress; - // slot 52 - /// @notice address resolver contract address for imp addresses - address public addressResolver; - - // slot 53 + // slot 51 /// @notice caches the latest async promise address for the last call address public latestAsyncPromise; - // slots [54-103] reserved for gap + // slots [52-101] reserved for gap uint256[50] _gap_after; } /// @title Forwarder Contract /// @notice This contract acts as a forwarder for async calls to the on-chain contracts. -contract Forwarder is ForwarderStorage, Initializable { +contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { error AsyncModifierNotUsed(); constructor() { @@ -52,7 +49,7 @@ contract Forwarder is ForwarderStorage, Initializable { ) public initializer { chainSlug = chainSlug_; onChainAddress = onChainAddress_; - addressResolver = addressResolver_; + _setAddressResolver(addressResolver_); } /// @notice Stores the callback address and data to be executed once the promise is resolved. @@ -82,8 +79,7 @@ contract Forwarder is ForwarderStorage, Initializable { /// @dev It queues the calls in the auction house and deploys the promise contract fallback() external payable { // Retrieve the auction house address from the address resolver. - address deliveryHelper = IAddressResolver(addressResolver).deliveryHelper(); - if (deliveryHelper == address(0)) { + if (address(deliveryHelper__()) == address(0)) { revert("Forwarder: deliveryHelper not found"); } @@ -91,25 +87,37 @@ contract Forwarder is ForwarderStorage, Initializable { if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); // Deploy a new async promise contract. - latestAsyncPromise = IAddressResolver(addressResolver).deployAsyncPromiseContract( - msg.sender - ); + latestAsyncPromise = addressResolver__.deployAsyncPromiseContract(msg.sender); // Determine if the call is a read or write operation. - Read isReadCall = IAppGateway(msg.sender).isReadCall(); - Parallel isParallelCall = IAppGateway(msg.sender).isParallelCall(); + ( + Read isReadCall, + Parallel isParallelCall, + WriteFinality writeFinality, + uint256 readAt, + uint256 gasLimit, + bytes32 sbType + ) = IAppGateway(msg.sender).getOverrideParams(); + address switchboard = watcherPrecompileConfig().switchboards(chainSlug, sbType); // Queue the call in the auction house. - IDeliveryHelper(deliveryHelper).queue( - IsPlug.NO, - isParallelCall, - chainSlug, - onChainAddress, - latestAsyncPromise, - 0, - isReadCall == Read.ON ? CallType.READ : CallType.WRITE, - msg.data, - bytes("") + deliveryHelper__().queue( + QueuePayloadParams({ + chainSlug: chainSlug, + callType: isReadCall == Read.ON ? CallType.READ : CallType.WRITE, + isParallel: isParallelCall, + isPlug: IsPlug.NO, + writeFinality: writeFinality, + asyncPromise: latestAsyncPromise, + switchboard: switchboard, + target: onChainAddress, + appGateway: msg.sender, + gasLimit: gasLimit, + value: 0, + readAt: readAt, + payload: msg.data, + initCallData: bytes("") + }) ); } diff --git a/contracts/protocol/payload-delivery/AuctionManager.sol b/contracts/protocol/payload-delivery/AuctionManager.sol index dd12f475..860d527e 100644 --- a/contracts/protocol/payload-delivery/AuctionManager.sol +++ b/contracts/protocol/payload-delivery/AuctionManager.sol @@ -3,15 +3,16 @@ pragma solidity ^0.8.0; import {ECDSA} from "solady/utils/ECDSA.sol"; import "solady/utils/Initializable.sol"; -import {Ownable} from "solady/auth/Ownable.sol"; +import "../utils/AccessControl.sol"; -import {IDeliveryHelper} from "../../interfaces/IDeliveryHelper.sol"; +import {IMiddleware} from "../../interfaces/IMiddleware.sol"; import {IFeesManager} from "../../interfaces/IFeesManager.sol"; import {IAuctionManager} from "../../interfaces/IAuctionManager.sol"; import {AddressResolverUtil} from "../utils/AddressResolverUtil.sol"; -import {Fees, Bid, PayloadBatch} from "../utils/common/Structs.sol"; +import {Fees, Bid, RequestMetadata, RequestParams} from "../utils/common/Structs.sol"; import {AuctionClosed, AuctionAlreadyStarted, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter} from "../utils/common/Errors.sol"; +import {TRANSMITTER_ROLE} from "../utils/common/AccessRoles.sol"; abstract contract AuctionManagerStorage is IAuctionManager { // slots [0-49] reserved for gap @@ -21,31 +22,48 @@ abstract contract AuctionManagerStorage is IAuctionManager { uint32 public evmxSlug; // slot 51 - mapping(bytes32 => Bid) public winningBids; + mapping(uint40 => Bid) public winningBids; // slot 52 - // asyncId => auction status - mapping(bytes32 => bool) public override auctionClosed; + // requestCount => auction status + mapping(uint40 => bool) public override auctionClosed; // slot 53 - mapping(bytes32 => bool) public override auctionStarted; + mapping(uint40 => bool) public override auctionStarted; // slot 54 uint256 public auctionEndDelaySeconds; - // slots [55-104] reserved for gap - uint256[50] _gap_after; + // slot 55 + mapping(address => bool) public whitelistedTransmitters; + + // slot 56 + mapping(uint40 => uint256) public reAuctionCount; + + // slot 57 + uint256 public maxReAuctionCount; + + // slots [57-104] reserved for gap + uint256[48] _gap_after; // slots 105-155 reserved for addr resolver util } /// @title AuctionManager /// @notice Contract for managing auctions and placing bids -contract AuctionManager is AuctionManagerStorage, Initializable, Ownable, AddressResolverUtil { - event AuctionRestarted(bytes32 asyncId); - event AuctionStarted(bytes32 asyncId); - event AuctionEnded(bytes32 asyncId, Bid winningBid); - event BidPlaced(bytes32 asyncId, Bid bid); +contract AuctionManager is + AuctionManagerStorage, + Initializable, + AccessControl, + AddressResolverUtil +{ + event AuctionRestarted(uint40 requestCount); + event AuctionStarted(uint40 requestCount); + event AuctionEnded(uint40 requestCount, Bid winningBid); + event BidPlaced(uint40 requestCount, Bid bid); + + error InvalidBid(); + error MaxReAuctionCountReached(); constructor() { _disableInitializers(); // disable for implementation @@ -56,120 +74,119 @@ contract AuctionManager is AuctionManagerStorage, Initializable, Ownable, Addres /// @param auctionEndDelaySeconds_ The delay in seconds before an auction can end /// @param addressResolver_ The address of the address resolver /// @param owner_ The address of the contract owner + /// @param maxReAuctionCount_ The maximum number of re-auctions allowed function initialize( uint32 evmxSlug_, uint256 auctionEndDelaySeconds_, address addressResolver_, - address owner_ + address owner_, + uint256 maxReAuctionCount_ ) public reinitializer(1) { _setAddressResolver(addressResolver_); _initializeOwner(owner_); evmxSlug = evmxSlug_; auctionEndDelaySeconds = auctionEndDelaySeconds_; + maxReAuctionCount = maxReAuctionCount_; } function setAuctionEndDelaySeconds(uint256 auctionEndDelaySeconds_) external onlyOwner { auctionEndDelaySeconds = auctionEndDelaySeconds_; } - function startAuction(bytes32 asyncId_) internal { - if (auctionClosed[asyncId_]) revert AuctionClosed(); - if (auctionStarted[asyncId_]) revert AuctionAlreadyStarted(); + function startAuction(uint40 requestCount_) internal { + if (auctionClosed[requestCount_]) revert AuctionClosed(); + if (auctionStarted[requestCount_]) revert AuctionAlreadyStarted(); - auctionStarted[asyncId_] = true; - emit AuctionStarted(asyncId_); + auctionStarted[requestCount_] = true; + emit AuctionStarted(requestCount_); } /// @notice Places a bid for an auction - /// @param asyncId_ The ID of the auction + /// @param requestCount_ The ID of the auction /// @param fee The bid amount /// @param transmitterSignature The signature of the transmitter function bid( - bytes32 asyncId_, + uint40 requestCount_, uint256 fee, bytes memory transmitterSignature, bytes memory extraData ) external { - if (auctionClosed[asyncId_]) revert AuctionClosed(); + if (auctionClosed[requestCount_]) revert AuctionClosed(); address transmitter = _recoverSigner( - keccak256(abi.encode(address(this), evmxSlug, asyncId_, fee, extraData)), + keccak256(abi.encode(address(this), evmxSlug, requestCount_, fee, extraData)), transmitterSignature ); + if (!_hasRole(TRANSMITTER_ROLE, transmitter)) revert InvalidTransmitter(); Bid memory newBid = Bid({fee: fee, transmitter: transmitter, extraData: extraData}); + RequestMetadata memory requestMetadata = IMiddleware(addressResolver__.deliveryHelper()) + .getRequestMetadata(requestCount_); + if (fee > requestMetadata.fees.amount) revert BidExceedsMaxFees(); + if (requestMetadata.auctionManager != address(this)) revert InvalidBid(); - PayloadBatch memory payloadBatch = IDeliveryHelper(addressResolver__.deliveryHelper()) - .payloadBatches(asyncId_); - if (fee > payloadBatch.fees.amount) revert BidExceedsMaxFees(); - - if (winningBids[asyncId_].transmitter != address(0) && fee >= winningBids[asyncId_].fee) - revert LowerBidAlreadyExists(); + if ( + winningBids[requestCount_].transmitter != address(0) && + fee >= winningBids[requestCount_].fee + ) revert LowerBidAlreadyExists(); - winningBids[asyncId_] = newBid; + winningBids[requestCount_] = newBid; IFeesManager(addressResolver__.feesManager()).blockFees( - payloadBatch.appGateway, - payloadBatch.fees, + requestMetadata.appGateway, + requestMetadata.fees, newBid, - asyncId_ + requestCount_ ); if (auctionEndDelaySeconds > 0) { - startAuction(asyncId_); + startAuction(requestCount_); watcherPrecompile__().setTimeout( - payloadBatch.appGateway, - abi.encodeWithSelector(this.endAuction.selector, asyncId_), - auctionEndDelaySeconds + auctionEndDelaySeconds, + abi.encodeWithSelector(this.endAuction.selector, requestCount_) ); } else { - _endAuction(asyncId_); + _endAuction(requestCount_); } - emit BidPlaced(asyncId_, newBid); - auctionClosed[asyncId_] = true; + emit BidPlaced(requestCount_, newBid); + auctionClosed[requestCount_] = true; } /// @notice Ends an auction - /// @param asyncId_ The ID of the auction - function endAuction(bytes32 asyncId_) external onlyWatcherPrecompile { - _endAuction(asyncId_); + /// @param requestCount_ The ID of the auction + function endAuction(uint40 requestCount_) external onlyWatcherPrecompile { + _endAuction(requestCount_); } - function _endAuction(bytes32 asyncId_) internal { - auctionClosed[asyncId_] = true; - Bid memory winningBid = winningBids[asyncId_]; + function _endAuction(uint40 requestCount_) internal { + auctionClosed[requestCount_] = true; + Bid memory winningBid = winningBids[requestCount_]; if (winningBid.transmitter == address(0)) revert InvalidTransmitter(); - emit AuctionEnded(asyncId_, winningBid); - - PayloadBatch memory payloadBatch = IDeliveryHelper(addressResolver__.deliveryHelper()) - .payloadBatches(asyncId_); - watcherPrecompile__().setTimeout( - payloadBatch.appGateway, - abi.encodeWithSelector(this.expireBid.selector, asyncId_), - IDeliveryHelper(addressResolver__.deliveryHelper()).bidTimeout() + IMiddleware(addressResolver__.deliveryHelper()).bidTimeout(), + abi.encodeWithSelector(this.expireBid.selector, requestCount_) ); - - IDeliveryHelper(addressResolver__.deliveryHelper()).startBatchProcessing( - asyncId_, + IMiddleware(addressResolver__.deliveryHelper()).startRequestProcessing( + requestCount_, winningBid ); + emit AuctionEnded(requestCount_, winningBid); } - function expireBid(bytes32 asyncId_) external onlyWatcherPrecompile { - PayloadBatch memory batch = IDeliveryHelper(addressResolver__.deliveryHelper()) - .payloadBatches(asyncId_); + function expireBid(uint40 requestCount_) external onlyWatcherPrecompile { + if (reAuctionCount[requestCount_] >= maxReAuctionCount) revert MaxReAuctionCountReached(); + RequestParams memory requestParams = watcherPrecompile__().getRequestParams(requestCount_); // if executed, bid is not expired - if (batch.totalPayloadsRemaining == 0 || batch.isBatchCancelled) return; - - IFeesManager(addressResolver__.feesManager()).unblockFees(asyncId_, batch.appGateway); - winningBids[asyncId_] = Bid({fee: 0, transmitter: address(0), extraData: ""}); - auctionClosed[asyncId_] = false; + if (requestParams.payloadsRemaining == 0 || requestParams.isRequestCancelled) return; + winningBids[requestCount_] = Bid({fee: 0, transmitter: address(0), extraData: ""}); + auctionClosed[requestCount_] = false; + reAuctionCount[requestCount_]++; - emit AuctionRestarted(asyncId_); + IFeesManager(addressResolver__.feesManager()).unblockFees(requestCount_); + emit AuctionRestarted(requestCount_); } function _recoverSigner( diff --git a/contracts/protocol/payload-delivery/FeesManager.sol b/contracts/protocol/payload-delivery/FeesManager.sol index 58a9323f..7b9804b5 100644 --- a/contracts/protocol/payload-delivery/FeesManager.sol +++ b/contracts/protocol/payload-delivery/FeesManager.sol @@ -9,9 +9,8 @@ import {IFeesPlug} from "../../interfaces/IFeesPlug.sol"; import {IFeesManager} from "../../interfaces/IFeesManager.sol"; import {AddressResolverUtil} from "../utils/AddressResolverUtil.sol"; -import {WITHDRAW} from "../utils/common/Constants.sol"; import {NotAuctionManager} from "../utils/common/Errors.sol"; -import {Bid, Fees, PayloadDetails, CallType, FinalizeParams, Parallel} from "../utils/common/Structs.sol"; +import {Bid, Fees, CallType, Parallel, WriteFinality, TokenBalance, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestParams, RequestMetadata} from "../utils/common/Structs.sol"; abstract contract FeesManagerStorage is IFeesManager { // slots [0-49] reserved for gap @@ -23,60 +22,57 @@ abstract contract FeesManagerStorage is IFeesManager { // slot 51 uint32 public evmxSlug; - /// @notice Struct containing fee amounts and status - struct TokenBalance { - uint256 deposited; // Amount deposited - uint256 blocked; // Amount blocked - } - // slot 52 + bytes32 public sbType; + + // slot 53 /// @notice Master mapping tracking all fee information /// @dev appGateway => chainSlug => token => TokenBalance mapping(address => mapping(uint32 => mapping(address => TokenBalance))) public appGatewayFeeBalances; - // slot 53 + // slot 54 /// @notice Mapping to track blocked fees for each async id - /// @dev asyncId => Fees - mapping(bytes32 => Fees) public asyncIdBlockedFees; + /// @dev requestCount => Fees + mapping(uint40 => Fees) public requestCountBlockedFees; - // slot 54 + // slot 55 /// @notice Mapping to track fees to be distributed to transmitters /// @dev transmitter => chainSlug => token => amount mapping(address => mapping(uint32 => mapping(address => uint256))) public transmitterFees; - // slot 55 + // slot 56 /// @notice Mapping to track nonce to whether it has been used /// @dev signatureNonce => isNonceUsed mapping(uint256 => bool) public isNonceUsed; - // slots [56-105] reserved for gap + // slots [57-106] reserved for gap uint256[50] _gap_after; - // slots 106-156 reserved for addr resolver util + // slots 107-157 reserved for addr resolver util } /// @title FeesManager /// @notice Contract for managing fees contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResolverUtil { /// @notice Emitted when fees are blocked for a batch - /// @param asyncId The batch identifier + /// @param requestCount The batch identifier /// @param chainSlug The chain identifier /// @param token The token address /// @param amount The blocked amount event FeesBlocked( - bytes32 indexed asyncId, + uint40 indexed requestCount, uint32 indexed chainSlug, address indexed token, uint256 amount ); /// @notice Emitted when transmitter fees are updated - /// @param asyncId The batch identifier + /// @param requestCount The batch identifier /// @param transmitter The transmitter address /// @param amount The new amount deposited event TransmitterFeesUpdated( - bytes32 indexed asyncId, + uint40 indexed requestCount, address indexed transmitter, uint256 amount ); @@ -94,19 +90,19 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol ); /// @notice Emitted when fees are unblocked and assigned to a transmitter - /// @param asyncId The batch identifier + /// @param requestCount The batch identifier /// @param transmitter The transmitter address /// @param amount The unblocked amount event FeesUnblockedAndAssigned( - bytes32 indexed asyncId, + uint40 indexed requestCount, address indexed transmitter, uint256 amount ); /// @notice Emitted when fees are unblocked - /// @param asyncId The batch identifier + /// @param requestCount The batch identifier /// @param appGateway The app gateway address - event FeesUnblocked(bytes32 indexed asyncId, address indexed appGateway); + event FeesUnblocked(uint40 indexed requestCount, address indexed appGateway); /// @notice Error thrown when insufficient fees are available error InsufficientFeesAvailable(); @@ -118,6 +114,8 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol error InvalidWatcherSignature(); /// @notice Error thrown when nonce is used error NonceUsed(); + /// @notice Error thrown when caller is invalid + error InvalidCaller(); constructor() { _disableInitializers(); // disable for implementation @@ -130,9 +128,11 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol function initialize( address addressResolver_, address owner_, - uint32 evmxSlug_ + uint32 evmxSlug_, + bytes32 sbType_ ) public reinitializer(1) { evmxSlug = evmxSlug_; + sbType = sbType_; _setAddressResolver(addressResolver_); _initializeOwner(owner_); } @@ -194,15 +194,15 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol /// @notice Blocks fees for transmitter /// @param originAppGateway_ The app gateway address /// @param feesGivenByApp_ The fees data struct given by the app gateway - /// @param asyncId_ The batch identifier + /// @param requestCount_ The batch identifier /// @dev Only callable by delivery helper function blockFees( address originAppGateway_, Fees memory feesGivenByApp_, Bid memory winningBid_, - bytes32 asyncId_ + uint40 requestCount_ ) external { - if (msg.sender != deliveryHelper().getAsyncBatchDetails(asyncId_).auctionManager) + if (msg.sender != deliveryHelper__().getRequestMetadata(requestCount_).auctionManager) revert NotAuctionManager(); address appGateway = _getCoreAppGateway(originAppGateway_); @@ -213,8 +213,8 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol feesGivenByApp_.feePoolToken ); - if (asyncIdBlockedFees[asyncId_].amount > 0) - availableFees += asyncIdBlockedFees[asyncId_].amount; + if (requestCountBlockedFees[requestCount_].amount > 0) + availableFees += requestCountBlockedFees[requestCount_].amount; if (availableFees < winningBid_.fee) revert InsufficientFeesAvailable(); TokenBalance storage tokenBalance = appGatewayFeeBalances[appGateway][ @@ -224,16 +224,16 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol tokenBalance.blocked = tokenBalance.blocked + winningBid_.fee - - asyncIdBlockedFees[asyncId_].amount; + requestCountBlockedFees[requestCount_].amount; - asyncIdBlockedFees[asyncId_] = Fees({ + requestCountBlockedFees[requestCount_] = Fees({ feePoolChain: feesGivenByApp_.feePoolChain, feePoolToken: feesGivenByApp_.feePoolToken, amount: winningBid_.fee }); emit FeesBlocked( - asyncId_, + requestCount_, feesGivenByApp_.feePoolChain, feesGivenByApp_.feePoolToken, winningBid_.fee @@ -241,15 +241,15 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol } /// @notice Unblocks fees after successful execution and assigns them to the transmitter - /// @param asyncId_ The async ID of the executed batch + /// @param requestCount_ The async ID of the executed batch /// @param transmitter_ The address of the transmitter who executed the batch function unblockAndAssignFees( - bytes32 asyncId_, + uint40 requestCount_, address transmitter_, address originAppGateway_ ) external override onlyDeliveryHelper { - Fees memory fees = asyncIdBlockedFees[asyncId_]; - if (fees.amount == 0) revert NoFeesBlocked(); + Fees memory fees = requestCountBlockedFees[requestCount_]; + if (fees.amount == 0) return; address appGateway = _getCoreAppGateway(originAppGateway_); TokenBalance storage tokenBalance = appGatewayFeeBalances[appGateway][fees.feePoolChain][ @@ -264,25 +264,33 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol transmitterFees[transmitter_][fees.feePoolChain][fees.feePoolToken] += fees.amount; // Clean up storage - delete asyncIdBlockedFees[asyncId_]; - emit FeesUnblockedAndAssigned(asyncId_, transmitter_, fees.amount); + delete requestCountBlockedFees[requestCount_]; + emit FeesUnblockedAndAssigned(requestCount_, transmitter_, fees.amount); } - function unblockFees(bytes32 asyncId_, address originAppGateway_) external onlyDeliveryHelper { - Fees memory fees = asyncIdBlockedFees[asyncId_]; - if (fees.amount == 0) revert NoFeesBlocked(); + function unblockFees(uint40 requestCount_) external { + RequestMetadata memory requestMetadata = deliveryHelper__().getRequestMetadata( + requestCount_ + ); - address appGateway = _getCoreAppGateway(originAppGateway_); - TokenBalance storage tokenBalance = appGatewayFeeBalances[appGateway][fees.feePoolChain][ - fees.feePoolToken - ]; + if ( + msg.sender != requestMetadata.auctionManager && + msg.sender != address(deliveryHelper__()) + ) revert InvalidCaller(); + + Fees memory fees = requestCountBlockedFees[requestCount_]; + if (fees.amount == 0) return; + + TokenBalance storage tokenBalance = appGatewayFeeBalances[requestMetadata.appGateway][ + fees.feePoolChain + ][fees.feePoolToken]; // Unblock fees from deposit tokenBalance.blocked -= fees.amount; tokenBalance.deposited += fees.amount; - delete asyncIdBlockedFees[asyncId_]; - emit FeesUnblocked(asyncId_, appGateway); + delete requestCountBlockedFees[requestCount_]; + emit FeesUnblocked(requestCount_, requestMetadata.appGateway); } /// @notice Withdraws fees to a specified receiver @@ -293,12 +301,13 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol uint32 chainSlug_, address token_, address receiver_ - ) external returns (bytes32 payloadId, bytes32 digest, PayloadDetails memory payloadDetails) { + ) external returns (uint40 requestCount) { address transmitter = msg.sender; - // Get all asyncIds for the transmitter + // Get total fees for the transmitter in given chain and token uint256 totalFees = transmitterFees[transmitter][chainSlug_][token_]; if (totalFees == 0) revert NoFeesForTransmitter(); + // Clean up storage transmitterFees[transmitter][chainSlug_][token_] = 0; // Create fee distribution payload @@ -308,34 +317,8 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol (token_, totalFees, receiver_, feesId) ); - // Create payload for plug contract - payloadDetails = _createPayloadDetails(CallType.WRITE, chainSlug_, payload); - FinalizeParams memory finalizeParams = FinalizeParams({ - payloadDetails: payloadDetails, - asyncId: bytes32(0), - transmitter: transmitter - }); - - (payloadId, digest) = watcherPrecompile__().finalize(address(this), finalizeParams); - } - - function _createPayloadDetails( - CallType callType_, - uint32 chainSlug_, - bytes memory payload_ - ) internal view returns (PayloadDetails memory) { - return - PayloadDetails({ - appGateway: address(this), - chainSlug: chainSlug_, - target: _getFeesPlugAddress(chainSlug_), - payload: payload_, - callType: callType_, - value: 0, - executionGasLimit: 1000000, - next: new address[](2), - isParallel: Parallel.OFF - }); + // finalize for plug contract + return _submitAndStartProcessing(chainSlug_, payload, transmitter); } /// @notice Withdraws funds to a specified receiver @@ -345,13 +328,13 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol /// @param token_ The address of the token /// @param amount_ The amount of tokens to withdraw /// @param receiver_ The address of the receiver - function getWithdrawToPayload( + function withdrawFees( address originAppGateway_, uint32 chainSlug_, address token_, uint256 amount_, address receiver_ - ) public returns (PayloadDetails memory) { + ) public { address appGateway = _getCoreAppGateway(originAppGateway_); // Check if amount is available in fees plug @@ -361,13 +344,68 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol TokenBalance storage tokenBalance = appGatewayFeeBalances[appGateway][chainSlug_][token_]; tokenBalance.deposited -= amount_; - // Create payload for pool contract + // Add it to the queue and submit request + _queue(chainSlug_, abi.encodeCall(IFeesPlug.withdrawFees, (token_, amount_, receiver_))); + } + + function _submitAndStartProcessing( + uint32 chainSlug_, + bytes memory payload_, + address transmitter_ + ) internal returns (uint40 requestCount) { + PayloadSubmitParams[] memory payloadSubmitParamsArray = new PayloadSubmitParams[](1); + payloadSubmitParamsArray[0] = PayloadSubmitParams({ + levelNumber: 0, + chainSlug: chainSlug_, + callType: CallType.WRITE, + isParallel: Parallel.OFF, + writeFinality: WriteFinality.LOW, + asyncPromise: address(0), + switchboard: _getSwitchboard(chainSlug_), + target: _getFeesPlugAddress(chainSlug_), + appGateway: address(this), + gasLimit: 10000000, + value: 0, + readAt: 0, + payload: payload_ + }); + requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray); + watcherPrecompile__().startProcessingRequest(requestCount, transmitter_); + } + + function _getSwitchboard(uint32 chainSlug_) internal view returns (address) { + return watcherPrecompile__().watcherPrecompileConfig__().switchboards(chainSlug_, sbType); + } + + function _createQueuePayloadParams( + uint32 chainSlug_, + bytes memory payload_ + ) internal view returns (QueuePayloadParams memory) { return - _createPayloadDetails( - CallType.WITHDRAW, - chainSlug_, - abi.encodeCall(IFeesPlug.withdrawFees, (token_, amount_, receiver_)) - ); + QueuePayloadParams({ + chainSlug: chainSlug_, + callType: CallType.WRITE, + isParallel: Parallel.OFF, + isPlug: IsPlug.NO, + writeFinality: WriteFinality.LOW, + asyncPromise: address(0), + switchboard: _getSwitchboard(chainSlug_), + target: _getFeesPlugAddress(chainSlug_), + appGateway: address(this), + gasLimit: 10000000, + value: 0, + readAt: 0, + payload: payload_, + initCallData: bytes("") + }); + } + + function _queue(uint32 chainSlug_, bytes memory payload_) internal { + QueuePayloadParams memory queuePayloadParams = _createQueuePayloadParams( + chainSlug_, + payload_ + ); + deliveryHelper__().queue(queuePayloadParams); } function _encodeFeesId(uint256 feesCounter_) internal view returns (bytes32) { @@ -376,7 +414,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol } function _getFeesPlugAddress(uint32 chainSlug_) internal view returns (address) { - return watcherPrecompile__().feesPlug(chainSlug_); + return watcherPrecompileConfig().feesPlug(chainSlug_); } function _isWatcherSignatureValid( diff --git a/contracts/protocol/payload-delivery/FeesPlug.sol b/contracts/protocol/payload-delivery/FeesPlug.sol index a6a1afdf..77778f05 100644 --- a/contracts/protocol/payload-delivery/FeesPlug.sol +++ b/contracts/protocol/payload-delivery/FeesPlug.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.21; -import "solmate/utils/SafeTransferLib.sol"; +import "solady/utils/SafeTransferLib.sol"; import "../../base/PlugBase.sol"; import "../utils/AccessControl.sol"; import {RESCUE_ROLE} from "../utils/common/AccessRoles.sol"; @@ -84,7 +84,7 @@ contract FeesPlug is PlugBase, AccessControl { balanceOf[token_] += amount_; if (token_ != ETH_ADDRESS) { - SafeTransferLib.safeTransferFrom(ERC20(token_), msg.sender, address(this), amount_); + SafeTransferLib.safeTransferFrom(token_, msg.sender, address(this), amount_); } emit FeesDeposited(appGateway_, token_, amount_); @@ -96,9 +96,9 @@ contract FeesPlug is PlugBase, AccessControl { /// @param receiver_ The receiver address function _transferTokens(address token_, uint256 amount_, address receiver_) internal { if (token_ == ETH_ADDRESS) { - SafeTransferLib.safeTransferETH(payable(receiver_), amount_); + SafeTransferLib.forceSafeTransferETH(receiver_, amount_); } else { - SafeTransferLib.safeTransfer(ERC20(token_), receiver_, amount_); + SafeTransferLib.safeTransfer(token_, receiver_, amount_); } } diff --git a/contracts/protocol/payload-delivery/app-gateway/BatchAsync.sol b/contracts/protocol/payload-delivery/app-gateway/BatchAsync.sol deleted file mode 100644 index 825a3149..00000000 --- a/contracts/protocol/payload-delivery/app-gateway/BatchAsync.sol +++ /dev/null @@ -1,322 +0,0 @@ -// SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.21; - -import "./QueueAsync.sol"; - -/// @title BatchAsync -/// @notice Abstract contract for managing asynchronous payload batches -abstract contract BatchAsync is QueueAsync { - // slots [210-259] reserved for gap - uint256[50] _gap_batch_async; - - /// @notice Error thrown when attempting to executed payloads after all have been executed - error AllPayloadsExecuted(); - /// @notice Error thrown request did not come from Forwarder address - error NotFromForwarder(); - /// @notice Error thrown when a payload call fails - error CallFailed(bytes32 payloadId); - /// @notice Error thrown if payload is too large - error PayloadTooLarge(); - /// @notice Error thrown if trying to cancel a batch without being the application gateway - error OnlyAppGateway(); - /// @notice Error thrown when a winning bid exists - error WinningBidExists(); - /// @notice Error thrown when a bid is insufficient - error InsufficientFees(); - - event PayloadSubmitted( - bytes32 indexed asyncId, - address indexed appGateway, - PayloadDetails[] payloads, - Fees fees, - address auctionManager - ); - - /// @notice Emitted when fees are increased - event FeesIncreased(address indexed appGateway, bytes32 indexed asyncId, uint256 newMaxFees); - - /// @notice Emitted when a payload is requested asynchronously - event PayloadAsyncRequested( - bytes32 indexed asyncId, - bytes32 indexed payloadId, - bytes32 indexed digest, - PayloadDetails payloadDetails - ); - - /// @notice Emitted when a batch is cancelled - event BatchCancelled(bytes32 indexed asyncId); - - /// @notice Initiates a batch of payloads - /// @param fees_ The fees data - /// @param auctionManager_ The auction manager address - /// @return asyncId The ID of the batch - function batch( - Fees memory fees_, - address auctionManager_, - bytes memory onCompleteData_, - bytes32 sbType_ - ) external returns (bytes32) { - PayloadDetails[] memory payloadDetailsArray = _createPayloadDetailsArray(sbType_); - - if (payloadDetailsArray.length == 0) { - return bytes32(0); - } - - // Default flow for other cases (including mixed read/write) - if (auctionManager_ == address(0)) { - auctionManager_ = IAddressResolver(addressResolver__).defaultAuctionManager(); - } - return _deliverPayload(payloadDetailsArray, fees_, auctionManager_, onCompleteData_); - } - - /// @notice Callback function for handling promises - /// @param asyncId_ The ID of the batch - /// @param payloadDetails_ The payload details - function callback(bytes memory asyncId_, bytes memory payloadDetails_) external virtual {} - - /// @notice Delivers a payload batch - /// @param payloadDetails_ The payload details - /// @param fees_ The fees data - /// @param auctionManager_ The auction manager address - /// @return asyncId The ID of the batch - function _deliverPayload( - PayloadDetails[] memory payloadDetails_, - Fees memory fees_, - address auctionManager_, - bytes memory onCompleteData_ - ) internal returns (bytes32) { - bytes32 asyncId = getCurrentAsyncId(); - asyncCounter++; - - if (!IFeesManager(addressResolver__.feesManager()).isFeesEnough(msg.sender, fees_)) - revert InsufficientFees(); - - // Handle initial read operations first - uint256 readEndIndex = _processReadOperations(payloadDetails_, asyncId); - - watcherPrecompile__().checkAndConsumeLimit( - payloadDetails_[0].appGateway, - QUERY, - readEndIndex - ); - - // If only reads, return early - if (readEndIndex == payloadDetails_.length) { - emit PayloadSubmitted( - asyncId, - _getCoreAppGateway(msg.sender), - payloadDetails_, - fees_, - auctionManager_ - ); - return asyncId; - } - - address appGateway = _processRemainingPayloads(payloadDetails_, readEndIndex, asyncId); - _payloadBatches[asyncId].totalPayloadsRemaining = payloadDetails_.length - readEndIndex; - - _initializeBatch( - asyncId, - appGateway, - fees_, - auctionManager_, - onCompleteData_, - readEndIndex, - payloadDetails_ - ); - - return asyncId; - } - - function _processReadOperations( - PayloadDetails[] memory payloadDetails_, - bytes32 asyncId - ) internal returns (uint256) { - uint256 readEndIndex = 0; - - // Find the end of parallel reads - while ( - readEndIndex < payloadDetails_.length && - payloadDetails_[readEndIndex].callType == CallType.READ && - payloadDetails_[readEndIndex].isParallel == Parallel.ON - ) { - readEndIndex++; - } - - // If we have parallel reads, process them as a batch - if (readEndIndex > 0) { - address[] memory lastBatchPromises = new address[](readEndIndex); - address batchPromise = IAddressResolver(addressResolver__).deployAsyncPromiseContract( - address(this) - ); - isValidPromise[batchPromise] = true; - - for (uint256 i = 0; i < readEndIndex; i++) { - payloadDetails_[i].next[1] = batchPromise; - lastBatchPromises[i] = payloadDetails_[i].next[0]; - - bytes32 payloadId = watcherPrecompile__().query( - payloadDetails_[i].chainSlug, - payloadDetails_[i].target, - payloadDetails_[i].appGateway, - payloadDetails_[i].next, - payloadDetails_[i].payload - ); - payloadIdToBatchHash[payloadId] = asyncId; - payloadBatchDetails[asyncId].push(payloadDetails_[i]); - emit PayloadAsyncRequested(asyncId, payloadId, bytes32(0), payloadDetails_[i]); - } - - _payloadBatches[asyncId].lastBatchPromises = lastBatchPromises; - IPromise(batchPromise).then(this.callback.selector, abi.encode(asyncId)); - } - - return readEndIndex; - } - - function _processRemainingPayloads( - PayloadDetails[] memory payloadDetails_, - uint256 readEndIndex, - bytes32 asyncId - ) internal returns (address) { - // later changed to main app gateway if its a write call - address appGateway = msg.sender; - - uint256 writes = 0; - for (uint256 i = readEndIndex; i < payloadDetails_.length; i++) { - if (payloadDetails_[i].payload.length > 24.5 * 1024) revert PayloadTooLarge(); - - if (payloadDetails_[i].callType == CallType.DEPLOY) { - // contract factory plug deploys new contracts - payloadDetails_[i].target = getDeliveryHelperPlugAddress( - payloadDetails_[i].chainSlug - ); - writes++; - } else if (payloadDetails_[i].callType == CallType.WRITE) { - appGateway = _getCoreAppGateway(appGateway); - payloadDetails_[i].appGateway = appGateway; - writes++; - } - - payloadBatchDetails[asyncId].push(payloadDetails_[i]); - } - - watcherPrecompile__().checkAndConsumeLimit( - appGateway, - QUERY, - // remaining reads - payloadDetails_.length - writes - readEndIndex - ); - watcherPrecompile__().checkAndConsumeLimit(appGateway, FINALIZE, writes); - - return appGateway; - } - - function _initializeBatch( - bytes32 asyncId, - address appGateway, - Fees memory fees_, - address auctionManager_, - bytes memory onCompleteData_, - uint256 readEndIndex, - PayloadDetails[] memory payloadDetails_ - ) internal { - _payloadBatches[asyncId] = PayloadBatch({ - appGateway: appGateway, - fees: fees_, - currentPayloadIndex: readEndIndex, - auctionManager: auctionManager_, - winningBid: Bid({fee: 0, transmitter: address(0), extraData: new bytes(0)}), - isBatchCancelled: false, - totalPayloadsRemaining: _payloadBatches[asyncId].totalPayloadsRemaining, - lastBatchPromises: _payloadBatches[asyncId].lastBatchPromises, - lastBatchOfPayloads: new bytes32[](0), - onCompleteData: onCompleteData_ - }); - - emit PayloadSubmitted(asyncId, appGateway, payloadDetails_, fees_, auctionManager_); - } - - function endTimeout(bytes32 asyncId_) external onlyWatcherPrecompile { - IAuctionManager(_payloadBatches[asyncId_].auctionManager).endAuction(asyncId_); - } - - /// @notice Cancels a transaction - /// @param asyncId_ The ID of the batch - function cancelTransaction(bytes32 asyncId_) external { - if (msg.sender != _payloadBatches[asyncId_].appGateway) { - revert OnlyAppGateway(); - } - - _payloadBatches[asyncId_].isBatchCancelled = true; - - if (_payloadBatches[asyncId_].winningBid.transmitter != address(0)) { - IFeesManager(addressResolver__.feesManager()).unblockAndAssignFees( - asyncId_, - _payloadBatches[asyncId_].winningBid.transmitter, - _payloadBatches[asyncId_].appGateway - ); - } else { - IFeesManager(addressResolver__.feesManager()).unblockFees( - asyncId_, - _payloadBatches[asyncId_].appGateway - ); - } - - emit BatchCancelled(asyncId_); - } - - function increaseFees(bytes32 asyncId_, uint256 newMaxFees_) external override { - address appGateway = _getCoreAppGateway(msg.sender); - if (appGateway != _payloadBatches[asyncId_].appGateway) { - revert OnlyAppGateway(); - } - - if (_payloadBatches[asyncId_].winningBid.transmitter != address(0)) - revert WinningBidExists(); - - _payloadBatches[asyncId_].fees.amount = newMaxFees_; - emit FeesIncreased(appGateway, asyncId_, newMaxFees_); - } - - /// @notice Gets the payload delivery plug address - /// @param chainSlug_ The chain identifier - /// @return address The address of the payload delivery plug - function getDeliveryHelperPlugAddress(uint32 chainSlug_) public view returns (address) { - return watcherPrecompile__().contractFactoryPlug(chainSlug_); - } - - /// @notice Gets the current async ID - /// @return bytes32 The current async ID - function getCurrentAsyncId() public view returns (bytes32) { - return bytes32((uint256(uint160(address(this))) << 64) | asyncCounter); - } - - /// @notice Withdraws funds to a specified receiver - /// @param chainSlug_ The chain identifier - /// @param token_ The address of the token - /// @param amount_ The amount of tokens to withdraw - /// @param receiver_ The address of the receiver - /// @param fees_ The fees data - function withdrawTo( - uint32 chainSlug_, - address token_, - uint256 amount_, - address receiver_, - address auctionManager_, - Fees memory fees_ - ) external { - PayloadDetails[] memory payloadDetailsArray = new PayloadDetails[](1); - payloadDetailsArray[0] = IFeesManager(addressResolver__.feesManager()).getWithdrawToPayload( - msg.sender, - chainSlug_, - token_, - amount_, - receiver_ - ); - if (auctionManager_ == address(0)) { - auctionManager_ = IAddressResolver(addressResolver__).defaultAuctionManager(); - } - _deliverPayload(payloadDetailsArray, fees_, auctionManager_, new bytes(0)); - } -} diff --git a/contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol b/contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol index c3e5de15..81d9e7b3 100644 --- a/contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol +++ b/contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol @@ -1,11 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./BatchAsync.sol"; - -contract DeliveryHelper is BatchAsync { - event CallBackReverted(bytes32 asyncId_, bytes32 payloadId_); +import "./FeesHelpers.sol"; +contract DeliveryHelper is FeesHelpers { constructor() { _disableInitializers(); // disable for implementation } @@ -23,214 +21,85 @@ contract DeliveryHelper is BatchAsync { _initializeOwner(owner_); } - function startBatchProcessing( - bytes32 asyncId_, - Bid memory winningBid_ - ) external onlyAuctionManager(asyncId_) { - if (winningBid_.transmitter == address(0)) revert InvalidTransmitter(); - - bool isRestarted = _payloadBatches[asyncId_].winningBid.transmitter != address(0); - _payloadBatches[asyncId_].winningBid = winningBid_; - - if (!isRestarted) return _process(asyncId_, false); - - // Re-finalize all payloads in the batch if a new transmitter is assigned - bytes32[] memory payloadIds = _payloadBatches[asyncId_].lastBatchOfPayloads; - for (uint256 i = 0; i < payloadIds.length; i++) { - watcherPrecompile__().refinalize( - payloadIds[i], - FinalizeParams({ - payloadDetails: payloadIdToPayloadDetails[payloadIds[i]], - asyncId: asyncId_, - transmitter: winningBid_.transmitter - }) - ); - } + function endTimeout(uint40 requestCount_) external onlyWatcherPrecompile { + IAuctionManager(requests[requestCount_].auctionManager).endAuction(requestCount_); } - function callback(bytes memory asyncId_, bytes memory) external override onlyPromises { - bytes32 asyncId = abi.decode(asyncId_, (bytes32)); - _process(asyncId, true); - } - - function _process(bytes32 asyncId_, bool isCallback_) internal { - PayloadBatch storage payloadBatch = _payloadBatches[asyncId_]; - if (payloadBatch.isBatchCancelled) return; + function startRequestProcessing( + uint40 requestCount_, + Bid memory winningBid_ + ) external onlyAuctionManager(requestCount_) { + if (requests[requestCount_].onlyReadRequests) revert ReadOnlyRequests(); + if (winningBid_.transmitter == address(0)) revert InvalidTransmitter(); - // Check if there are remaining payloads to process - // Check if there are promises from last batch that need to be resolved - if (payloadBatch.lastBatchPromises.length > 0) { - // Check if all promises are resolved - for (uint256 i = 0; i < payloadBatch.lastBatchPromises.length; i++) { - if (payloadBatch.lastBatchPromises[i] == address(0)) continue; - if (!IPromise(payloadBatch.lastBatchPromises[i]).resolved()) { - if (isCallback_) revert PromisesNotResolved(); - } - } - // Clear promises array after all are resolved - if (isCallback_) { - delete payloadBatch.lastBatchPromises; - } - } + RequestMetadata storage requestMetadata_ = requests[requestCount_]; + bool isRestarted = requestMetadata_.winningBid.transmitter != address(0); - if (payloadBatch.totalPayloadsRemaining > 0) { - delete tempPayloadIds; + requestMetadata_.winningBid.transmitter = winningBid_.transmitter; - // Proceed with next payload only if all promises are resolved - _finalizeNextPayload(asyncId_); - payloadBatch.lastBatchOfPayloads = tempPayloadIds; + if (!isRestarted) { + watcherPrecompile__().startProcessingRequest(requestCount_, winningBid_.transmitter); } else { - _finishBatch(asyncId_, payloadBatch); + watcherPrecompile__().updateTransmitter(requestCount_, winningBid_.transmitter); } - - isValidPromise[msg.sender] = false; - } - - function _finishBatch(bytes32 asyncId_, PayloadBatch storage payloadBatch_) internal { - IFeesManager(addressResolver__.feesManager()).unblockAndAssignFees( - asyncId_, - payloadBatch_.winningBid.transmitter, - payloadBatch_.appGateway - ); - IAppGateway(payloadBatch_.appGateway).onBatchComplete(asyncId_, payloadBatch_); } - function _finalizeNextPayload(bytes32 asyncId_) internal { - PayloadBatch storage payloadBatch_ = _payloadBatches[asyncId_]; - uint256 currentIndex = payloadBatch_.currentPayloadIndex; - PayloadDetails[] storage payloads = payloadBatchDetails[asyncId_]; + function finishRequest(uint40 requestCount_) external onlyWatcherPrecompile { + RequestMetadata storage requestMetadata_ = requests[requestCount_]; - // Check for empty payloads or index out of bounds - if (payloads.length == 0 || currentIndex >= payloads.length) { - revert InvalidIndex(); - } + if (requestMetadata_.winningBid.transmitter != address(0)) + IFeesManager(addressResolver__.feesManager()).unblockAndAssignFees( + requestCount_, + requestMetadata_.winningBid.transmitter, + requestMetadata_.appGateway + ); - // Deploy single promise for the next batch of operations - address batchPromise = IAddressResolver(addressResolver__).deployAsyncPromiseContract( - address(this) + IAppGateway(requestMetadata_.appGateway).onRequestComplete( + requestCount_, + requestMetadata_.onCompleteData ); - - isValidPromise[batchPromise] = true; - IPromise(batchPromise).then(this.callback.selector, abi.encode(asyncId_)); - - // Handle batch processing based on type - if (payloads[currentIndex].isParallel == Parallel.ON) { - _processParallelCalls(asyncId_, payloadBatch_, payloads, currentIndex, batchPromise); - } else { - _processSequentialCall( - asyncId_, - payloadBatch_, - payloads, - currentIndex, - batchPromise, - payloads[currentIndex].callType == CallType.READ - ); - } } - function _executeWatcherCall( - bytes32 asyncId_, - PayloadDetails storage payloadDetails_, - PayloadBatch storage payloadBatch_, - address batchPromise_, - bool isRead_ - ) internal returns (bytes32 payloadId, bytes32 digest) { - payloadDetails_.next[1] = batchPromise_; - if (isRead_) { - payloadId = watcherPrecompile__().query( - payloadDetails_.chainSlug, - payloadDetails_.target, - payloadDetails_.appGateway, - payloadDetails_.next, - payloadDetails_.payload + /// @notice Cancels a request + /// @param requestCount_ The ID of the request + function cancelRequest(uint40 requestCount_) external { + if (msg.sender != requests[requestCount_].appGateway) { + revert OnlyAppGateway(); + } + // If the request has a winning bid, ie. transmitter already assigned, unblock and assign fees + if (requests[requestCount_].winningBid.transmitter != address(0)) { + IFeesManager(addressResolver__.feesManager()).unblockAndAssignFees( + requestCount_, + requests[requestCount_].winningBid.transmitter, + requests[requestCount_].appGateway ); - digest = bytes32(0); } else { - FinalizeParams memory finalizeParams = FinalizeParams({ - payloadDetails: payloadDetails_, - asyncId: asyncId_, - transmitter: payloadBatch_.winningBid.transmitter - }); - (payloadId, digest) = watcherPrecompile__().finalize( - payloadBatch_.appGateway, - finalizeParams - ); + // If the request has no winning bid, ie. transmitter not assigned, unblock fees + IFeesManager(addressResolver__.feesManager()).unblockFees(requestCount_); } - tempPayloadIds.push(payloadId); - payloadIdToBatchHash[payloadId] = asyncId_; - payloadIdToPayloadDetails[payloadId] = payloadDetails_; - - emit PayloadAsyncRequested(asyncId_, payloadId, digest, payloadDetails_); + watcherPrecompile__().cancelRequest(requestCount_); + emit RequestCancelled(requestCount_); } - function _processParallelCalls( - bytes32 asyncId_, - PayloadBatch storage payloadBatch_, - PayloadDetails[] storage payloads_, - uint256 startIndex_, - address batchPromise_ - ) internal { - // Validate input parameters - if (startIndex_ >= payloads_.length) revert InvalidIndex(); - - uint256 endIndex = startIndex_; - while ( - endIndex + 1 < payloads_.length && payloads_[endIndex + 1].isParallel == Parallel.ON - ) { - endIndex++; - } - - address[] memory promises = new address[](endIndex - startIndex_ + 1); - for (uint256 i = startIndex_; i <= endIndex; i++) { - promises[i - startIndex_] = payloads_[i].next[0]; - if (payloads_[i].callType == CallType.READ) { - _executeWatcherCall(asyncId_, payloads_[i], payloadBatch_, batchPromise_, true); - } else { - _executeWatcherCall(asyncId_, payloads_[i], payloadBatch_, batchPromise_, false); - } + /// @notice Handles request reverts + /// @param requestCount_ The ID of the request + function handleRequestReverts(uint40 requestCount_) external onlyWatcherPrecompile { + // assign fees after expiry time + if (requests[requestCount_].winningBid.transmitter != address(0)) { + IFeesManager(addressResolver__.feesManager()).unblockAndAssignFees( + requestCount_, + requests[requestCount_].winningBid.transmitter, + requests[requestCount_].appGateway + ); + } else { + IFeesManager(addressResolver__.feesManager()).unblockFees(requestCount_); } - - _updateBatchState(payloadBatch_, promises, endIndex - startIndex_ + 1, endIndex + 1); - } - - function _processSequentialCall( - bytes32 asyncId_, - PayloadBatch storage payloadBatch_, - PayloadDetails[] storage payloads_, - uint256 currentIndex_, - address batchPromise_, - bool isRead_ - ) internal { - // Validate input parameters - if (currentIndex_ >= payloads_.length) revert InvalidIndex(); - - address[] memory promises = new address[](1); - promises[0] = payloads_[currentIndex_].next[0]; - - _executeWatcherCall( - asyncId_, - payloads_[currentIndex_], - payloadBatch_, - batchPromise_, - isRead_ - ); - _updateBatchState(payloadBatch_, promises, 1, currentIndex_ + 1); - } - - function _updateBatchState( - PayloadBatch storage batch_, - address[] memory promises_, - uint256 completedCount_, - uint256 nextIndex_ - ) internal { - batch_.totalPayloadsRemaining -= completedCount_; - - batch_.currentPayloadIndex = nextIndex_; - batch_.lastBatchPromises = promises_; } - function handleRevert(bytes32 asyncId_, bytes32 payloadId_) external onlyPromises { - emit CallBackReverted(asyncId_, payloadId_); + function getRequestMetadata( + uint40 requestCount_ + ) external view returns (RequestMetadata memory) { + return requests[requestCount_]; } } diff --git a/contracts/protocol/payload-delivery/app-gateway/DeliveryHelperStorage.sol b/contracts/protocol/payload-delivery/app-gateway/DeliveryHelperStorage.sol index 1801385a..d6daf1f4 100644 --- a/contracts/protocol/payload-delivery/app-gateway/DeliveryHelperStorage.sol +++ b/contracts/protocol/payload-delivery/app-gateway/DeliveryHelperStorage.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Unlicense pragma solidity ^0.8.21; -import {IDeliveryHelper} from "../../../interfaces/IDeliveryHelper.sol"; +import {IMiddleware} from "../../../interfaces/IMiddleware.sol"; import {IPromise} from "../../../interfaces/IPromise.sol"; import {IAddressResolver} from "../../../interfaces/IAddressResolver.sol"; import {IContractFactoryPlug} from "../../../interfaces/IContractFactoryPlug.sol"; @@ -11,46 +11,23 @@ import {IAddressResolver} from "../../../interfaces/IAddressResolver.sol"; import {IAuctionManager} from "../../../interfaces/IAuctionManager.sol"; import {IFeesManager} from "../../../interfaces/IFeesManager.sol"; -import {CallParams, Fees, PayloadDetails, CallType, Bid, PayloadBatch, Parallel, IsPlug, FinalizeParams} from "../../utils/common/Structs.sol"; +import {QueuePayloadParams, Fees, CallType, Bid, Parallel, IsPlug, WriteFinality, RequestMetadata} from "../../utils/common/Structs.sol"; import {NotAuctionManager, InvalidPromise, InvalidIndex, PromisesNotResolved, InvalidTransmitter} from "../../utils/common/Errors.sol"; -import {FORWARD_CALL, DISTRIBUTE_FEE, DEPLOY, WITHDRAW, QUERY, FINALIZE} from "../../utils/common/Constants.sol"; +import {FORWARD_CALL, DISTRIBUTE_FEE, DEPLOY, QUERY, FINALIZE} from "../../utils/common/Constants.sol"; /// @title DeliveryHelperStorage /// @notice Storage contract for DeliveryHelper -abstract contract DeliveryHelperStorage is IDeliveryHelper { +abstract contract DeliveryHelperStorage is IMiddleware { // slots [0-49] reserved for gap uint256[50] _gap_before; - // slot 50 - uint256 public saltCounter; - - // slot 51 - uint128 public asyncCounter; uint128 public bidTimeout; + uint256 public saltCounter; - // slot 52 - bytes32[] public tempPayloadIds; - - // slot 53 /// @notice The call parameters array - CallParams[] public callParamsArray; - - // slot 54 - /// @notice The mapping of valid promises - mapping(address => bool) public isValidPromise; - - // slot 55 - payloadIdToBatchHash - mapping(bytes32 => bytes32) public payloadIdToBatchHash; - // slot 56 - payloadIdToPayloadDetails - mapping(bytes32 => PayloadDetails) public payloadIdToPayloadDetails; - - // slot 57 - // asyncId => PayloadDetails[] - mapping(bytes32 => PayloadDetails[]) public payloadBatchDetails; + QueuePayloadParams[] public queuePayloadParams; - // slot 58 - // asyncId => PayloadBatch - mapping(bytes32 => PayloadBatch) internal _payloadBatches; + mapping(uint40 => RequestMetadata) public requests; // slots [59-108] reserved for gap uint256[50] _gap_after; diff --git a/contracts/protocol/payload-delivery/app-gateway/DeliveryUtils.sol b/contracts/protocol/payload-delivery/app-gateway/DeliveryUtils.sol new file mode 100644 index 00000000..6532aae7 --- /dev/null +++ b/contracts/protocol/payload-delivery/app-gateway/DeliveryUtils.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.21; + +import {Ownable} from "solady/auth/Ownable.sol"; +import "solady/utils/Initializable.sol"; +import {AddressResolverUtil} from "../../utils/AddressResolverUtil.sol"; +import "./DeliveryHelperStorage.sol"; +import {PayloadSubmitParams} from "../../utils/common/Structs.sol"; + +/// @notice Abstract contract for managing asynchronous payloads +abstract contract DeliveryUtils is + DeliveryHelperStorage, + Initializable, + Ownable, + AddressResolverUtil +{ + // slots [0-108] reserved for delivery helper storage and [109-159] reserved for addr resolver util + // slots [160-209] reserved for gap + uint256[50] _gap_delivery_utils; + + /// @notice Error thrown when attempting to executed payloads after all have been executed + error AllPayloadsExecuted(); + /// @notice Error thrown request did not come from Forwarder address + error NotFromForwarder(); + /// @notice Error thrown when a payload call fails + error CallFailed(bytes32 payloadId); + /// @notice Error thrown if payload is too large + error PayloadTooLarge(); + /// @notice Error thrown if trying to cancel a batch without being the application gateway + error OnlyAppGateway(); + /// @notice Error thrown when a winning bid exists + error WinningBidExists(); + /// @notice Error thrown when a bid is insufficient + error InsufficientFees(); + /// @notice Error thrown when a request contains only reads + error ReadOnlyRequests(); + + event CallBackReverted(uint40 requestCount_, bytes32 payloadId_); + event RequestCancelled(uint40 indexed requestCount); + event BidTimeoutUpdated(uint256 newBidTimeout); + event PayloadSubmitted( + uint40 indexed requestCount, + address indexed appGateway, + PayloadSubmitParams[] payloadSubmitParams, + Fees fees, + address auctionManager, + bool onlyReadRequests + ); + /// @notice Emitted when fees are increased + event FeesIncreased( + address indexed appGateway, + uint40 indexed requestCount, + uint256 newMaxFees + ); + + modifier onlyAuctionManager(uint40 requestCount_) { + if (msg.sender != requests[requestCount_].auctionManager) revert NotAuctionManager(); + _; + } + + /// @notice Gets the payload delivery plug address + /// @param chainSlug_ The chain identifier + /// @return address The address of the payload delivery plug + function getDeliveryHelperPlugAddress(uint32 chainSlug_) public view returns (address) { + return watcherPrecompileConfig().contractFactoryPlug(chainSlug_); + } + + /// @notice Updates the bid timeout + /// @param newBidTimeout_ The new bid timeout value + function updateBidTimeout(uint128 newBidTimeout_) external onlyOwner { + bidTimeout = newBidTimeout_; + emit BidTimeoutUpdated(newBidTimeout_); + } +} diff --git a/contracts/protocol/payload-delivery/app-gateway/FeesHelpers.sol b/contracts/protocol/payload-delivery/app-gateway/FeesHelpers.sol new file mode 100644 index 00000000..4655c8b8 --- /dev/null +++ b/contracts/protocol/payload-delivery/app-gateway/FeesHelpers.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.21; + +import "./RequestQueue.sol"; + +/// @title RequestAsync +/// @notice Abstract contract for managing asynchronous payload batches +abstract contract FeesHelpers is RequestQueue { + // slots [210-259] reserved for gap + uint256[50] _gap_batch_async; + + function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external override { + address appGateway = _getCoreAppGateway(msg.sender); + if (appGateway != requests[requestCount_].appGateway) { + revert OnlyAppGateway(); + } + + if (requests[requestCount_].winningBid.transmitter != address(0)) revert WinningBidExists(); + requests[requestCount_].fees.amount = newMaxFees_; + emit FeesIncreased(appGateway, requestCount_, newMaxFees_); + } + + /// @notice Withdraws funds to a specified receiver + /// @param chainSlug_ The chain identifier + /// @param token_ The address of the token + /// @param amount_ The amount of tokens to withdraw + /// @param receiver_ The address of the receiver + /// @param fees_ The fees data + function withdrawTo( + uint32 chainSlug_, + address token_, + uint256 amount_, + address receiver_, + address auctionManager_, + Fees memory fees_ + ) external returns (uint40) { + IFeesManager(addressResolver__.feesManager()).withdrawFees( + msg.sender, + chainSlug_, + token_, + amount_, + receiver_ + ); + + return _batch(msg.sender, auctionManager_, fees_, bytes("")); + } + + function getFees(uint40 requestCount_) external view returns (Fees memory) { + return requests[requestCount_].fees; + } +} diff --git a/contracts/protocol/payload-delivery/app-gateway/QueueAsync.sol b/contracts/protocol/payload-delivery/app-gateway/QueueAsync.sol deleted file mode 100644 index c08b0f93..00000000 --- a/contracts/protocol/payload-delivery/app-gateway/QueueAsync.sol +++ /dev/null @@ -1,169 +0,0 @@ -// SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.21; - -import {Ownable} from "solady/auth/Ownable.sol"; -import "solady/utils/Initializable.sol"; - -import {AddressResolverUtil} from "../../utils/AddressResolverUtil.sol"; - -import "./DeliveryHelperStorage.sol"; - -/// @notice Abstract contract for managing asynchronous payloads -abstract contract QueueAsync is DeliveryHelperStorage, Initializable, Ownable, AddressResolverUtil { - // slots [0-108] reserved for delivery helper storage and [109-159] reserved for addr resolver util - // slots [160-209] reserved for gap - uint256[50] _gap_queue_async; - - event PayloadBatchCancelled(bytes32 asyncId); - event BidTimeoutUpdated(uint256 newBidTimeout); - - modifier onlyPromises() { - if (!isValidPromise[msg.sender]) revert InvalidPromise(); - _; - } - - modifier onlyAuctionManager(bytes32 asyncId_) { - if (msg.sender != _payloadBatches[asyncId_].auctionManager) revert NotAuctionManager(); - _; - } - - function payloadBatches(bytes32 asyncId_) external view override returns (PayloadBatch memory) { - return _payloadBatches[asyncId_]; - } - - function getPayloadDetails(bytes32 payloadId_) external view returns (PayloadDetails memory) { - return payloadIdToPayloadDetails[payloadId_]; - } - - /// @notice Clears the call parameters array - function clearQueue() public { - delete callParamsArray; - } - - /// @notice Queues a new payload - /// @param chainSlug_ The chain identifier - /// @param target_ The target address - /// @param asyncPromise_ The async promise or ID - /// @param callType_ The call type - /// @param payload_ The payload - function queue( - IsPlug isPlug_, - Parallel isParallel_, - uint32 chainSlug_, - address target_, - address asyncPromise_, - uint256 value_, - CallType callType_, - bytes memory payload_, - bytes memory initCallData_ - ) external { - // todo: sb related details - callParamsArray.push( - CallParams({ - isPlug: isPlug_, - callType: callType_, - asyncPromise: asyncPromise_, - chainSlug: chainSlug_, - target: target_, - payload: payload_, - value: value_, - gasLimit: 10000000, - isParallel: isParallel_, - initCallData: initCallData_ - }) - ); - } - - /// @notice Creates an array of payload details - /// @return payloadDetailsArray An array of payload details - function _createPayloadDetailsArray( - bytes32 sbType_ - ) internal returns (PayloadDetails[] memory payloadDetailsArray) { - if (callParamsArray.length == 0) return payloadDetailsArray; - - payloadDetailsArray = new PayloadDetails[](callParamsArray.length); - for (uint256 i = 0; i < callParamsArray.length; i++) { - CallParams memory params = callParamsArray[i]; - - // getting switchboard address for sbType given. It is updated by watcherPrecompile by watcher - address switchboard = watcherPrecompile__().switchboards(params.chainSlug, sbType_); - - PayloadDetails memory payloadDetails = _createPayloadDetails(params, switchboard); - payloadDetailsArray[i] = payloadDetails; - } - - clearQueue(); - } - - /// @notice Gets the payload details for a given call parameters - /// @param params_ The call parameters - /// @param switchboard_ The switchboard address - /// @return payloadDetails The payload details - function _createPayloadDetails( - CallParams memory params_, - address switchboard_ - ) internal returns (PayloadDetails memory) { - address[] memory next = new address[](2); - next[0] = params_.asyncPromise; - - bytes memory payload_ = params_.payload; - address appGateway_ = msg.sender; - if (params_.callType == CallType.DEPLOY) { - // getting app gateway for deployer as the plug is connected to the app gateway - address appGatewayForPlug_ = _getCoreAppGateway(appGateway_); - bytes32 salt_ = keccak256( - abi.encode(appGatewayForPlug_, params_.chainSlug, saltCounter++) - ); - - // app gateway is set in the plug deployed on chain - payload_ = abi.encodeWithSelector( - IContractFactoryPlug.deployContract.selector, - params_.isPlug, - salt_, - appGatewayForPlug_, - switchboard_, - payload_, - params_.initCallData - ); - - // for deploy, we set delivery helper as app gateway of contract factory plug - appGateway_ = address(this); - } - - return - PayloadDetails({ - appGateway: appGateway_, - chainSlug: params_.chainSlug, - target: params_.target, - value: params_.value, - payload: payload_, - callType: params_.callType, - executionGasLimit: params_.gasLimit == 0 ? 1_000_000 : params_.gasLimit, - next: next, - isParallel: params_.isParallel - }); - } - - /// @notice Updates the bid timeout - /// @param newBidTimeout_ The new bid timeout value - function updateBidTimeout(uint128 newBidTimeout_) external onlyOwner { - bidTimeout = newBidTimeout_; - emit BidTimeoutUpdated(newBidTimeout_); - } - - function getPayloadIndexDetails( - bytes32 asyncId_, - uint256 index_ - ) external view returns (PayloadDetails memory) { - if (index_ >= payloadBatchDetails[asyncId_].length) revert InvalidIndex(); - return payloadBatchDetails[asyncId_][index_]; - } - - function getFees(bytes32 asyncId_) external view returns (Fees memory) { - return _payloadBatches[asyncId_].fees; - } - - function getAsyncBatchDetails(bytes32 asyncId_) external view returns (PayloadBatch memory) { - return _payloadBatches[asyncId_]; - } -} diff --git a/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol b/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol new file mode 100644 index 00000000..de8e7f36 --- /dev/null +++ b/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.21; + +import {Ownable} from "solady/auth/Ownable.sol"; +import "solady/utils/Initializable.sol"; +import {AddressResolverUtil} from "../../utils/AddressResolverUtil.sol"; +import "./DeliveryUtils.sol"; + +/// @notice Abstract contract for managing asynchronous payloads +abstract contract RequestQueue is DeliveryUtils { + // slots [0-108] reserved for delivery helper storage and [109-159] reserved for addr resolver util + // slots [160-209] reserved for gap + uint256[50] _gap_queue_async; + + /// @notice Clears the call parameters array + function clearQueue() public { + delete queuePayloadParams; + } + + /// @notice Queues a new payload + /// @param queuePayloadParams_ The call parameters + function queue(QueuePayloadParams memory queuePayloadParams_) external { + queuePayloadParams.push(queuePayloadParams_); + } + + /// @notice Initiates a batch of payloads + /// @param fees_ The fees data + /// @param auctionManager_ The auction manager address + /// @return requestCount The ID of the batch + function batch( + Fees memory fees_, + address auctionManager_, + bytes memory onCompleteData_ + ) external returns (uint40 requestCount) { + address appGateway = _getCoreAppGateway(msg.sender); + return _batch(appGateway, auctionManager_, fees_, onCompleteData_); + } + + function _batch( + address appGateway_, + address auctionManager_, + Fees memory fees_, + bytes memory onCompleteData_ + ) internal returns (uint40 requestCount) { + if (queuePayloadParams.length == 0) return 0; + + if (!IFeesManager(addressResolver__.feesManager()).isFeesEnough(appGateway_, fees_)) + revert InsufficientFees(); + + ( + PayloadSubmitParams[] memory payloadSubmitParamsArray, + , + bool onlyReadRequests + ) = _createPayloadSubmitParamsArray(); + if (auctionManager_ == address(0)) + auctionManager_ = IAddressResolver(addressResolver__).defaultAuctionManager(); + + RequestMetadata memory requestMetadata = RequestMetadata({ + appGateway: appGateway_, + auctionManager: auctionManager_, + fees: fees_, + winningBid: Bid({fee: 0, transmitter: address(0), extraData: new bytes(0)}), + onCompleteData: onCompleteData_, + onlyReadRequests: onlyReadRequests + }); + + requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray); + requests[requestCount] = requestMetadata; + + // send query directly if request contains only reads + // transmitter should ignore the batch for auction, the transaction will also revert if someone bids + if (onlyReadRequests) + watcherPrecompile__().startProcessingRequest(requestCount, address(0)); + + emit PayloadSubmitted( + requestCount, + appGateway_, + payloadSubmitParamsArray, + fees_, + auctionManager_, + onlyReadRequests + ); + } + + /// @notice Creates an array of payload details + /// @return payloadDetailsArray An array of payload details + function _createPayloadSubmitParamsArray() + internal + returns ( + PayloadSubmitParams[] memory payloadDetailsArray, + uint256 totalLevels, + bool onlyReadRequests + ) + { + if (queuePayloadParams.length == 0) + return (payloadDetailsArray, totalLevels, onlyReadRequests); + payloadDetailsArray = new PayloadSubmitParams[](queuePayloadParams.length); + + totalLevels = 0; + onlyReadRequests = queuePayloadParams[0].callType == CallType.READ; + for (uint256 i = 0; i < queuePayloadParams.length; i++) { + if (queuePayloadParams[i].callType != CallType.READ) { + onlyReadRequests = false; + } + + // Update level for sequential calls + if (i > 0 && queuePayloadParams[i].isParallel != Parallel.ON) { + totalLevels = totalLevels + 1; + } + + payloadDetailsArray[i] = _createPayloadDetails(totalLevels, queuePayloadParams[i]); + } + + clearQueue(); + } + + /// @notice Creates the payload details for a given call parameters + /// @param queuePayloadParams_ The call parameters + /// @return payloadDetails The payload details + function _createPayloadDetails( + uint256 level_, + QueuePayloadParams memory queuePayloadParams_ + ) internal returns (PayloadSubmitParams memory) { + bytes memory payload_ = queuePayloadParams_.payload; + address target = queuePayloadParams_.target; + if (queuePayloadParams_.callType == CallType.DEPLOY) { + // getting app gateway for deployer as the plug is connected to the app gateway + bytes32 salt_ = keccak256( + abi.encode( + queuePayloadParams_.appGateway, + queuePayloadParams_.chainSlug, + saltCounter++ + ) + ); + + // app gateway is set in the plug deployed on chain + payload_ = abi.encodeWithSelector( + IContractFactoryPlug.deployContract.selector, + queuePayloadParams_.isPlug, + salt_, + queuePayloadParams_.appGateway, + queuePayloadParams_.switchboard, + payload_, + queuePayloadParams_.initCallData + ); + + if (payload_.length > 24.5 * 1024) revert PayloadTooLarge(); + target = getDeliveryHelperPlugAddress(queuePayloadParams_.chainSlug); + } + + return + PayloadSubmitParams({ + levelNumber: level_, + chainSlug: queuePayloadParams_.chainSlug, + callType: queuePayloadParams_.callType, + isParallel: queuePayloadParams_.isParallel, + writeFinality: queuePayloadParams_.writeFinality, + asyncPromise: queuePayloadParams_.asyncPromise, + switchboard: queuePayloadParams_.switchboard, + target: target, + appGateway: queuePayloadParams_.appGateway, + gasLimit: queuePayloadParams_.gasLimit == 0 + ? 10_000_000 + : queuePayloadParams_.gasLimit, + value: queuePayloadParams_.value, + readAt: queuePayloadParams_.readAt, + payload: payload_ + }); + } +} diff --git a/contracts/protocol/socket/Socket.sol b/contracts/protocol/socket/Socket.sol index bd70a175..84b588af 100644 --- a/contracts/protocol/socket/Socket.sol +++ b/contracts/protocol/socket/Socket.sol @@ -16,24 +16,15 @@ contract Socket is SocketUtils { //////////////////////////////////////////////////////// ////////////////////// ERRORS ////////////////////////// //////////////////////////////////////////////////////// - /** - * @dev Error emitted when proof is invalid - */ - /** * @dev Error emitted when a payload has already been executed */ error PayloadAlreadyExecuted(ExecutionStatus status); - /** - * @dev Error emitted when the executor is not valid - */ /** * @dev Error emitted when verification fails */ error VerificationFailed(); - /** - * @dev Error emitted when source slugs deduced from packet id and msg id don't match - */ + /** * @dev Error emitted when less gas limit is provided for execution than expected */ @@ -41,22 +32,6 @@ contract Socket is SocketUtils { error InvalidSlug(); error DeadlinePassed(); - //////////////////////////////////////////////////////////// - ////////////////////// State Vars ////////////////////////// - //////////////////////////////////////////////////////////// - uint64 public callCounter; - - enum ExecutionStatus { - NotExecuted, - Executed, - Reverted - } - - /** - * @dev keeps track of whether a payload has been executed or not using payload id - */ - mapping(bytes32 => ExecutionStatus) public payloadExecuted; - constructor( uint32 chainSlug_, address owner_, @@ -96,64 +71,38 @@ contract Socket is SocketUtils { * @notice Executes a payload that has been delivered by transmitters and authenticated by switchboards */ function execute( - address appGateway_, - ExecuteParams memory params_, + ExecuteParams memory executeParams_, bytes memory transmitterSignature_ ) external payable returns (bytes memory) { - // make sure payload is not executed already - if (payloadExecuted[params_.payloadId] != ExecutionStatus.NotExecuted) - revert PayloadAlreadyExecuted(payloadExecuted[params_.payloadId]); - // update state to make sure no reentrancy - payloadExecuted[params_.payloadId] = ExecutionStatus.Executed; - - if (params_.deadline < block.timestamp) revert DeadlinePassed(); - - // extract plug address from msgID - address switchboard = _decodeSwitchboard(params_.payloadId); - uint32 localSlug = _decodeChainSlug(params_.payloadId); - - PlugConfig memory plugConfig = _plugConfigs[params_.target]; + if (executeParams_.deadline < block.timestamp) revert DeadlinePassed(); + PlugConfig memory plugConfig = _plugConfigs[executeParams_.target]; + if (plugConfig.appGateway == address(0)) revert PlugDisconnected(); - if (switchboard != address(plugConfig.switchboard__)) revert InvalidSwitchboard(); - if (localSlug != chainSlug) revert InvalidSlug(); + bytes32 payloadId = _createPayloadId(plugConfig.switchboard, executeParams_); + _validateExecutionStatus(payloadId); address transmitter = _recoverSigner( - keccak256(abi.encode(address(this), params_.payloadId)), + keccak256(abi.encode(address(this), payloadId)), transmitterSignature_ ); - // create packed payload - bytes32 digest = _packPayload( - params_.payloadId, - appGateway_, + bytes32 digest = _createDigest( transmitter, - params_.target, - msg.value, - params_.deadline, - params_.executionGasLimit, - params_.payload + payloadId, + plugConfig.appGateway, + executeParams_ ); - - // verify payload was part of the packet and - // authenticated by respective switchboard - _verify(digest, params_.payloadId, ISwitchboard(switchboard)); - - // execute payload - return - _execute(params_.target, params_.payloadId, params_.executionGasLimit, params_.payload); + _verify(digest, payloadId, plugConfig.switchboard); + return _execute(payloadId, executeParams_); } //////////////////////////////////////////////////////// ////////////////// INTERNAL FUNCS ////////////////////// //////////////////////////////////////////////////////// - - function _verify( - bytes32 digest_, - bytes32 payloadId_, - ISwitchboard switchboard__ - ) internal view { + function _verify(bytes32 digest_, bytes32 payloadId_, address switchboard_) internal view { // NOTE: is the the first un-trusted call in the system, another one is Plug.call - if (!switchboard__.allowPacket(digest_, payloadId_)) revert VerificationFailed(); + if (!ISwitchboard(switchboard_).allowPacket(digest_, payloadId_)) + revert VerificationFailed(); } /** @@ -162,18 +111,16 @@ contract Socket is SocketUtils { * code exists in the given address. */ function _execute( - address localPlug_, bytes32 payloadId_, - uint256 executionGasLimit_, - bytes memory payload_ + ExecuteParams memory executeParams_ ) internal returns (bytes memory) { - if (gasleft() < executionGasLimit_) revert LowGasLimit(); + if (gasleft() < executeParams_.gasLimit) revert LowGasLimit(); // NOTE: external un-trusted call - (bool success, bytes memory returnData) = localPlug_.call{ - gas: executionGasLimit_, + (bool success, bytes memory returnData) = executeParams_.target.call{ + gas: executeParams_.gasLimit, value: msg.value - }(payload_); + }(executeParams_.payload); if (!success) { payloadExecuted[payloadId_] = ExecutionStatus.Reverted; @@ -185,31 +132,9 @@ contract Socket is SocketUtils { return returnData; } - /** - * @dev Decodes the switchboard address from a given payload id. - * @param id_ The ID of the msg to decode the switchboard from. - * @return switchboard_ The address of switchboard decoded from the payload ID. - */ - function _decodeSwitchboard(bytes32 id_) internal pure returns (address switchboard_) { - switchboard_ = address(uint160(uint256(id_) >> 64)); - } - - /** - * @dev Decodes the chain ID from a given packet/payload ID. - * @param id_ The ID of the packet/msg to decode the chain slug from. - * @return chainSlug_ The chain slug decoded from the packet/payload ID. - */ - function _decodeChainSlug(bytes32 id_) internal pure returns (uint32 chainSlug_) { - chainSlug_ = uint32(uint256(id_) >> 224); - } - - // Packs the local plug, local chain slug, remote chain slug and nonce - // callCount++ will take care of call id overflow as well - // callId(256) = localChainSlug(32) | appGateway_(160) | nonce(64) - function _encodeCallId(address appGateway_) internal returns (bytes32) { - return - bytes32( - (uint256(chainSlug) << 224) | (uint256(uint160(appGateway_)) << 64) | callCounter++ - ); + function _validateExecutionStatus(bytes32 payloadId_) internal { + if (payloadExecuted[payloadId_] != ExecutionStatus.NotExecuted) + revert PayloadAlreadyExecuted(payloadExecuted[payloadId_]); + payloadExecuted[payloadId_] = ExecutionStatus.Executed; } } diff --git a/contracts/protocol/socket/SocketBatcher.sol b/contracts/protocol/socket/SocketBatcher.sol index 726101e8..49eb1966 100644 --- a/contracts/protocol/socket/SocketBatcher.sol +++ b/contracts/protocol/socket/SocketBatcher.sol @@ -5,13 +5,14 @@ import "solady/auth/Ownable.sol"; import "../../interfaces/ISocket.sol"; import "../../interfaces/ISwitchboard.sol"; import "../utils/RescueFundsLib.sol"; -import {AttestAndExecutePayloadParams} from "../../protocol/utils/common/Structs.sol"; +import {ExecuteParams} from "../../protocol/utils/common/Structs.sol"; +import "../../interfaces/ISocketBatcher.sol"; /** * @title SocketBatcher * @notice The SocketBatcher contract is responsible for batching payloads and transmitting them to the destination chain */ -contract SocketBatcher is Ownable { +contract SocketBatcher is ISocketBatcher, Ownable { // socket contract ISocket public immutable socket__; @@ -26,23 +27,13 @@ contract SocketBatcher is Ownable { } function attestAndExecute( - AttestAndExecutePayloadParams calldata params_ + ExecuteParams calldata executeParams_, + bytes32 digest_, + bytes calldata proof_, + bytes calldata transmitterSignature_ ) external payable returns (bytes memory) { - ISwitchboard(params_.switchboard).attest(params_.payloadId, params_.digest, params_.proof); - - ISocket.ExecuteParams memory executeParams = ISocket.ExecuteParams({ - payloadId: params_.payloadId, - target: params_.target, - executionGasLimit: params_.executionGasLimit, - deadline: params_.deadline, - payload: params_.payload - }); - return - socket__.execute{value: msg.value}( - params_.appGateway, - executeParams, - params_.transmitterSignature - ); + ISwitchboard(executeParams_.switchboard).attest(digest_, proof_); + return socket__.execute{value: msg.value}(executeParams_, transmitterSignature_); } function rescueFunds(address token_, address to_, uint256 amount_) external onlyOwner { diff --git a/contracts/protocol/socket/SocketConfig.sol b/contracts/protocol/socket/SocketConfig.sol index 4ff8a904..346a6da9 100644 --- a/contracts/protocol/socket/SocketConfig.sol +++ b/contracts/protocol/socket/SocketConfig.sol @@ -5,6 +5,7 @@ import "../../interfaces/ISocket.sol"; import "../../interfaces/ISwitchboard.sol"; import "../utils/AccessControl.sol"; import {GOVERNANCE_ROLE, RESCUE_ROLE} from "../utils/common/AccessRoles.sol"; +import {PlugConfig, SwitchboardStatus, ExecutionStatus} from "../utils/common/Structs.sol"; /** * @title SocketConfig @@ -13,32 +14,16 @@ import {GOVERNANCE_ROLE, RESCUE_ROLE} from "../utils/common/AccessRoles.sol"; * @dev This contract is meant to be inherited by other contracts that require socket configuration functionality */ abstract contract SocketConfig is ISocket, AccessControl { - /** - * @dev Struct to store the configuration for a plug connection - */ - struct PlugConfig { - // address of the sibling plug on the remote chain - address appGateway; - // switchboard instance for the plug connection - ISwitchboard switchboard__; - } - - enum SwitchboardStatus { - NOT_REGISTERED, - REGISTERED, - DISABLED - } - // Error triggered when a switchboard already exists mapping(address => SwitchboardStatus) public isValidSwitchboard; // plug => (appGateway, switchboard__) mapping(address => PlugConfig) internal _plugConfigs; - error SwitchboardExists(); // Error triggered when a connection is invalid error InvalidConnection(); error InvalidSwitchboard(); + error SwitchboardExists(); error SwitchboardExistsOrDisabled(); // Event triggered when a new switchboard is added @@ -68,7 +53,7 @@ abstract contract SocketConfig is ISocket, AccessControl { PlugConfig storage _plugConfig = _plugConfigs[msg.sender]; _plugConfig.appGateway = appGateway_; - _plugConfig.switchboard__ = ISwitchboard(switchboard_); + _plugConfig.switchboard = switchboard_; emit PlugConnected(msg.sender, appGateway_, switchboard_); } @@ -79,8 +64,8 @@ abstract contract SocketConfig is ISocket, AccessControl { */ function getPlugConfig( address plugAddress_ - ) external view returns (address appGateway, address switchboard__) { + ) external view returns (address appGateway, address switchboard) { PlugConfig memory _plugConfig = _plugConfigs[plugAddress_]; - return (_plugConfig.appGateway, address(_plugConfig.switchboard__)); + return (_plugConfig.appGateway, _plugConfig.switchboard); } } diff --git a/contracts/protocol/socket/SocketUtils.sol b/contracts/protocol/socket/SocketUtils.sol index e46dd0fb..97aa46ba 100644 --- a/contracts/protocol/socket/SocketUtils.sol +++ b/contracts/protocol/socket/SocketUtils.sol @@ -11,11 +11,22 @@ import {ECDSA} from "solady/utils/ECDSA.sol"; * setters and inherits SocketConfig */ abstract contract SocketUtils is SocketConfig { + //////////////////////////////////////////////////////////// + ////////////////////// State Vars ////////////////////////// + //////////////////////////////////////////////////////////// + // Version string for this socket instance bytes32 public immutable version; // ChainSlug for this deployed socket instance uint32 public immutable chainSlug; + uint64 public callCounter; + + /** + * @dev keeps track of whether a payload has been executed or not using payload id + */ + mapping(bytes32 => ExecutionStatus) public payloadExecuted; + /* * @notice constructor for creating a new Socket contract instance. * @param chainSlug_ The unique identifier of the chain this socket is deployed on. @@ -38,36 +49,56 @@ abstract contract SocketUtils is SocketConfig { error InvalidTransmitter(); /** - * @notice Packs the payload into a bytes32 hash - * @param payloadId_ The ID of the payload - * @param appGateway_ The address of the application gateway + * @notice creates the digest for the payload * @param transmitter_ The address of the transmitter - * @param target_ The address of the target contract - * @param executionGasLimit_ The gas limit for the execution - * @param payload_ The payload to be packed + * @param payloadId_ The ID of the payload + * @param appGateway_ The address of the app gateway + * @param executeParams_ The parameters of the payload * @return The packed payload as a bytes32 hash */ - function _packPayload( + function _createDigest( + address transmitter_, bytes32 payloadId_, address appGateway_, - address transmitter_, - address target_, - uint256 value_, - uint256 deadline_, - uint256 executionGasLimit_, - bytes memory payload_ - ) internal pure returns (bytes32) { + ExecuteParams memory executeParams_ + ) internal view returns (bytes32) { return keccak256( abi.encode( + transmitter_, payloadId_, + executeParams_.deadline, + executeParams_.callType, + executeParams_.writeFinality, + executeParams_.gasLimit, + msg.value, + executeParams_.readAt, + executeParams_.payload, + executeParams_.target, appGateway_, - transmitter_, - target_, - value_, - deadline_, - executionGasLimit_, - payload_ + executeParams_.prevDigestsHash + ) + ); + } + + /** + * @notice creates the payload ID + * @param switchboard_ The address of the switchboard + * @param executeParams_ The parameters of the payload + */ + function _createPayloadId( + address switchboard_, + ExecuteParams memory executeParams_ + ) internal view returns (bytes32) { + // todo: match with watcher + return + keccak256( + abi.encode( + executeParams_.requestCount, + executeParams_.batchCount, + executeParams_.payloadCount, + switchboard_, + chainSlug ) ); } @@ -81,6 +112,16 @@ abstract contract SocketUtils is SocketConfig { signer = ECDSA.recover(digest, signature_); } + // Packs the local plug, local chain slug, remote chain slug and nonce + // callCount++ will take care of call id overflow as well + // callId(256) = localChainSlug(32) | appGateway_(160) | nonce(64) + function _encodeCallId(address appGateway_) internal returns (bytes32) { + return + bytes32( + (uint256(chainSlug) << 224) | (uint256(uint160(appGateway_)) << 64) | callCounter++ + ); + } + ////////////////////////////////////////////// //////////// Rescue role actions //////////// ///////////////////////////////////////////// diff --git a/contracts/protocol/socket/switchboard/FastSwitchboard.sol b/contracts/protocol/socket/switchboard/FastSwitchboard.sol index 874e7d19..308e07f6 100644 --- a/contracts/protocol/socket/switchboard/FastSwitchboard.sol +++ b/contracts/protocol/socket/switchboard/FastSwitchboard.sol @@ -6,22 +6,26 @@ import "./SwitchboardBase.sol"; /** * @title FastSwitchboard contract * @dev This contract implements a fast version of the SwitchboardBase contract - * that enables packet attestations and watchers registration. + * that enables packet attestations */ contract FastSwitchboard is SwitchboardBase { - // used to track which watcher have attested a digest - // watcher => digest => isAttested + // used to track if watcher have attested a digest + // digest => isAttested mapping(bytes32 => bool) public isAttested; - // Error emitted when a digest is already attested by a specific watcher. - // This is hit even if they are attesting a new proposalCount with same digest. + // Error emitted when a digest is already attested by watcher. error AlreadyAttested(); + // Error emitted when watcher is not valid error WatcherNotFound(); - event Attested(bytes32 payloadId, bytes32 digest_, address watcher); + + // Event emitted when watcher attests a digest + event Attested(bytes32 digest_, address watcher); /** * @dev Constructor function for the FastSwitchboard 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_, @@ -31,21 +35,18 @@ contract FastSwitchboard is SwitchboardBase { /** * @dev Function to attest a packet - * @param payloadId_ Packet ID - * @param digest_ Digest of the packet - * @param proof_ Proof of the watcher - * @notice we are attesting a digest uniquely identified with packetId and proposalCount. However, - * there can be multiple proposals for same digest. To avoid need to re-attest for different proposals - * with same digest, we are storing attestations against digest instead of packetId and proposalCount. + * @param digest_ digest of the payload to be executed + * @param proof_ proof from watcher + * @notice we are attesting a digest uniquely identified with payloadId. */ - function attest(bytes32 payloadId_, bytes32 digest_, bytes calldata proof_) external { + function attest(bytes32 digest_, bytes calldata proof_) external { address watcher = _recoverSigner(keccak256(abi.encode(address(this), digest_)), proof_); if (isAttested[digest_]) revert AlreadyAttested(); if (!_hasRole(WATCHER_ROLE, watcher)) revert WatcherNotFound(); - isAttested[digest_] = true; - emit Attested(payloadId_, digest_, watcher); + + emit Attested(digest_, watcher); } /** @@ -53,26 +54,7 @@ contract FastSwitchboard is SwitchboardBase { */ function allowPacket(bytes32 digest_, bytes32) external view returns (bool) { // digest has enough attestations - if (isAttested[digest_]) return true; - - // not enough attestations and timeout not hit - return false; - } - - /** - * @notice adds a watcher for `srcChainSlug_` chain - * @param watcher_ watcher address - */ - function grantWatcherRole(address watcher_) external onlyOwner { - _grantRole(WATCHER_ROLE, watcher_); - } - - /** - * @notice removes a watcher from `srcChainSlug_` chain list - * @param watcher_ watcher address - */ - function revokeWatcherRole(address watcher_) external onlyOwner { - _revokeRole(WATCHER_ROLE, watcher_); + return isAttested[digest_]; } function registerSwitchboard() external onlyOwner { diff --git a/contracts/protocol/utils/AddressResolverUtil.sol b/contracts/protocol/utils/AddressResolverUtil.sol index 38005e15..f168022c 100644 --- a/contracts/protocol/utils/AddressResolverUtil.sol +++ b/contracts/protocol/utils/AddressResolverUtil.sol @@ -2,8 +2,10 @@ pragma solidity ^0.8.21; import "../../interfaces/IAddressResolver.sol"; -import "../../interfaces/IDeliveryHelper.sol"; +import "../../interfaces/IMiddleware.sol"; import "../../interfaces/IWatcherPrecompile.sol"; +import "../../interfaces/IWatcherPrecompileConfig.sol"; +import "../../interfaces/IWatcherPrecompileLimits.sol"; /// @title AddressResolverUtil /// @notice Utility contract for resolving system contract addresses @@ -21,6 +23,8 @@ abstract contract AddressResolverUtil { error OnlyPayloadDelivery(); /// @notice Error thrown when an invalid address attempts to call the Watcher only function error OnlyWatcherPrecompile(); + /// @notice Error thrown when an invalid address attempts to call the Watcher precompile or delivery helper + error OnlyWatcherPrecompileOrDeliveryHelper(); /// @notice Restricts function access to the auction house contract /// @dev Validates that msg.sender matches the registered auction house address @@ -42,18 +46,45 @@ abstract contract AddressResolverUtil { _; } + /// @notice Restricts function access to the watcher precompile contract + /// @dev Validates that msg.sender matches the registered watcher precompile address + modifier onlyWatcherPrecompileOrDeliveryHelper() { + if ( + msg.sender != address(addressResolver__.watcherPrecompile__()) && + msg.sender != addressResolver__.deliveryHelper() + ) { + revert OnlyWatcherPrecompileOrDeliveryHelper(); + } + + _; + } + /// @notice Gets the auction house contract interface - /// @return IDeliveryHelper interface of the registered auction house + /// @return IMiddleware interface of the registered auction house /// @dev Resolves and returns the auction house contract for interaction - function deliveryHelper() public view returns (IDeliveryHelper) { - return IDeliveryHelper(addressResolver__.deliveryHelper()); + function deliveryHelper__() public view returns (IMiddleware) { + return IMiddleware(addressResolver__.deliveryHelper()); } /// @notice Gets the watcher precompile contract interface /// @return IWatcherPrecompile interface of the registered watcher precompile /// @dev Resolves and returns the watcher precompile contract for interaction function watcherPrecompile__() public view returns (IWatcherPrecompile) { - return IWatcherPrecompile(addressResolver__.watcherPrecompile__()); + return addressResolver__.watcherPrecompile__(); + } + + /// @notice Gets the watcher precompile config contract interface + /// @return IWatcherPrecompileConfig interface of the registered watcher precompile config + /// @dev Resolves and returns the watcher precompile config contract for interaction + function watcherPrecompileConfig() public view returns (IWatcherPrecompileConfig) { + return addressResolver__.watcherPrecompile__().watcherPrecompileConfig__(); + } + + /// @notice Gets the watcher precompile limits contract interface + /// @return IWatcherPrecompileLimits interface of the registered watcher precompile limits + /// @dev Resolves and returns the watcher precompile limits contract for interaction + function watcherPrecompileLimits() public view returns (IWatcherPrecompileLimits) { + return addressResolver__.watcherPrecompile__().watcherPrecompileLimits__(); } /// @notice Internal function to set the address resolver diff --git a/contracts/protocol/utils/RescueFundsLib.sol b/contracts/protocol/utils/RescueFundsLib.sol index a6319036..189f2a7b 100644 --- a/contracts/protocol/utils/RescueFundsLib.sol +++ b/contracts/protocol/utils/RescueFundsLib.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "solmate/utils/SafeTransferLib.sol"; -import "solmate/tokens/ERC20.sol"; +import "solady/utils/SafeTransferLib.sol"; import {ZeroAddress, InvalidTokenAddress} from "./common/Errors.sol"; import {ETH_ADDRESS} from "./common/Constants.sol"; @@ -22,10 +21,10 @@ library RescueFundsLib { if (rescueTo_ == address(0)) revert ZeroAddress(); if (token_ == ETH_ADDRESS) { - SafeTransferLib.safeTransferETH(rescueTo_, amount_); + SafeTransferLib.forceSafeTransferETH(rescueTo_, amount_); } else { if (token_.code.length == 0) revert InvalidTokenAddress(); - SafeTransferLib.safeTransfer(ERC20(token_), rescueTo_, amount_); + SafeTransferLib.safeTransfer(token_, rescueTo_, amount_); } } } diff --git a/contracts/protocol/utils/common/Constants.sol b/contracts/protocol/utils/common/Constants.sol index c1ee9a6a..082dcf62 100644 --- a/contracts/protocol/utils/common/Constants.sol +++ b/contracts/protocol/utils/common/Constants.sol @@ -8,7 +8,6 @@ address constant ZERO_ADDRESS = address(0); bytes32 constant FORWARD_CALL = keccak256("FORWARD_CALL"); bytes32 constant DISTRIBUTE_FEE = keccak256("DISTRIBUTE_FEE"); bytes32 constant DEPLOY = keccak256("DEPLOY"); -bytes32 constant WITHDRAW = keccak256("WITHDRAW"); bytes32 constant CONFIGURE = keccak256("CONFIGURE"); bytes32 constant CONNECT = keccak256("CONNECT"); bytes32 constant QUERY = keccak256("QUERY"); diff --git a/contracts/protocol/utils/common/Errors.sol b/contracts/protocol/utils/common/Errors.sol index 9a1fe4ca..bdebefd1 100644 --- a/contracts/protocol/utils/common/Errors.sol +++ b/contracts/protocol/utils/common/Errors.sol @@ -39,3 +39,4 @@ error AuctionAlreadyStarted(); error BidExceedsMaxFees(); /// @notice Error thrown if a lower bid already exists error LowerBidAlreadyExists(); +error AsyncModifierNotUsed(); diff --git a/contracts/protocol/utils/common/Structs.sol b/contracts/protocol/utils/common/Structs.sol index 3774291b..2b7c1f55 100644 --- a/contracts/protocol/utils/common/Structs.sol +++ b/contracts/protocol/utils/common/Structs.sol @@ -2,12 +2,10 @@ pragma solidity ^0.8.21; //// ENUMS //// - enum CallType { READ, WRITE, - DEPLOY, - WITHDRAW + DEPLOY } enum IsPlug { @@ -25,161 +23,230 @@ enum Read { ON } -//// STRUCTS //// +enum WriteFinality { + LOW, + MEDIUM, + HIGH +} + +enum SwitchboardStatus { + NOT_REGISTERED, + REGISTERED, + DISABLED +} +/// @notice The state of the async promise +enum AsyncPromiseState { + WAITING_FOR_SET_CALLBACK_SELECTOR, + WAITING_FOR_CALLBACK_EXECUTION, + CALLBACK_REVERTING, + ONCHAIN_REVERTING, + RESOLVED +} + +enum ExecutionStatus { + NotExecuted, + Executed, + Reverted +} + +//// STRUCTS //// +// plug: +struct LimitParams { + uint256 lastUpdateTimestamp; + uint256 ratePerSecond; + uint256 maxLimit; + uint256 lastUpdateLimit; +} +struct UpdateLimitParams { + bytes32 limitType; + address appGateway; + uint256 maxLimit; + uint256 ratePerSecond; +} struct AppGatewayConfig { address plug; address appGateway; address switchboard; uint32 chainSlug; } - -struct AsyncRequest { - address finalizedBy; +// Plug config: +struct PlugConfig { address appGateway; - address transmitter; - address target; address switchboard; - uint256 executionGasLimit; - uint256 deadline; - bytes32 asyncId; - bytes32 digest; - bytes payload; - address[] next; } - -struct AttestAndExecutePayloadParams { - bytes32 payloadId; - bytes32 digest; - address switchboard; +//inbox: +struct CallFromChainParams { + bytes32 callId; + bytes32 params; + address plug; address appGateway; + uint32 chainSlug; + bytes payload; +} +// timeout: +struct TimeoutRequest { + bytes32 timeoutId; address target; - uint256 executionGasLimit; - uint256 deadline; - bytes proof; - bytes transmitterSignature; + uint256 delayInSeconds; + uint256 executeAt; + uint256 executedAt; + bool isResolved; bytes payload; } +struct QueryResults { + address target; + uint256 queryCounter; + bytes functionSelector; + bytes returnData; + bytes callback; +} +struct ResolvedPromises { + bytes32 payloadId; + bytes returnData; +} +// AM struct Bid { address transmitter; uint256 fee; bytes extraData; } -struct CallParams { - IsPlug isPlug; - address asyncPromise; - address target; - uint32 chainSlug; - CallType callType; - Parallel isParallel; +// App gateway base: +struct OverrideParams { + Read isReadCall; + Parallel isParallelCall; + WriteFinality writeFinality; uint256 gasLimit; - uint256 value; - bytes payload; - bytes initCallData; -} - -struct CallFromChainParams { - bytes32 callId; - bytes32 params; - address plug; - address appGateway; - uint32 chainSlug; - bytes payload; -} - -struct DeployParams { - address contractAddr; - bytes bytecode; + uint256 readAt; } +// FM: struct Fees { uint32 feePoolChain; address feePoolToken; uint256 amount; } -struct FinalizeParams { +// digest: +struct DigestParams { address transmitter; - bytes32 asyncId; - PayloadDetails payloadDetails; -} - -struct LimitParams { - uint256 lastUpdateTimestamp; - uint256 ratePerSecond; - uint256 maxLimit; - uint256 lastUpdateLimit; + bytes32 payloadId; + uint256 deadline; + CallType callType; + WriteFinality writeFinality; + uint256 gasLimit; + uint256 value; + uint256 readAt; + bytes payload; + address target; + address appGateway; + bytes32 prevDigestsHash; // should be id? hash of hashes } -struct PayloadBatch { +struct QueuePayloadParams { + uint32 chainSlug; + CallType callType; + Parallel isParallel; + IsPlug isPlug; + WriteFinality writeFinality; + address asyncPromise; + address switchboard; + address target; address appGateway; - address auctionManager; - bool isBatchCancelled; - uint256 currentPayloadIndex; - uint256 totalPayloadsRemaining; - Fees fees; - Bid winningBid; - address[] lastBatchPromises; - bytes32[] lastBatchOfPayloads; - bytes onCompleteData; + uint256 gasLimit; + uint256 value; + uint256 readAt; + bytes payload; + bytes initCallData; } -struct PayloadDetails { - address appGateway; - address target; +struct PayloadSubmitParams { + uint256 levelNumber; uint32 chainSlug; - Parallel isParallel; CallType callType; + Parallel isParallel; + WriteFinality writeFinality; + address asyncPromise; + address switchboard; + address target; + address appGateway; + uint256 gasLimit; uint256 value; - uint256 executionGasLimit; + uint256 readAt; bytes payload; - address[] next; } -struct PayloadDigestParams { - address appGateway; - address transmitter; +struct PayloadParams { + // uint40 requestCount + uint40 batchCount + uint40 payloadCount + uint32 chainSlug + // CallType callType + Parallel isParallel + WriteFinality writeFinality + bytes32 dump; + // uint40 requestCount; + // uint40 batchCount; + // uint40 payloadCount; + // uint32 chainSlug; + // CallType callType; + // Parallel isParallel; + // WriteFinality writeFinality; + address asyncPromise; + address switchboard; address target; + address appGateway; bytes32 payloadId; + bytes32 prevDigestsHash; + uint256 gasLimit; uint256 value; - uint256 executionGasLimit; + uint256 readAt; uint256 deadline; bytes payload; + address finalizedTransmitter; } -struct PlugConfig { - address appGateway; - address switchboard; +struct RequestParams { + bool isRequestCancelled; + uint40 currentBatch; + uint256 currentBatchPayloadsLeft; + uint256 payloadsRemaining; + address middleware; + address transmitter; + PayloadParams[] payloadParamsArray; } -struct QueryResults { - address target; - uint256 queryCounter; - bytes functionSelector; - bytes returnData; - bytes callback; +struct RequestMetadata { + address appGateway; + address auctionManager; + Fees fees; + Bid winningBid; + bytes onCompleteData; + bool onlyReadRequests; } -struct ResolvedPromises { - bytes32 payloadId; - bytes[] returnData; +struct ExecuteParams { + uint256 deadline; + CallType callType; + WriteFinality writeFinality; + uint256 gasLimit; + uint256 readAt; + bytes payload; + address target; + uint40 requestCount; + uint40 batchCount; + uint40 payloadCount; + bytes32 prevDigestsHash; // should be id? hash of hashes + address switchboard; } -struct TimeoutRequest { - bytes32 timeoutId; - address target; - uint256 delayInSeconds; - uint256 executeAt; - uint256 executedAt; - bool isResolved; - bytes payload; +struct PayloadIdParams { + uint40 requestCount; + uint40 batchCount; + uint40 payloadCount; + address switchboard; + uint32 chainSlug; } -struct UpdateLimitParams { - bytes32 limitType; - address appGateway; - uint256 maxLimit; - uint256 ratePerSecond; +/// @notice Struct containing fee amounts and status +struct TokenBalance { + uint256 deposited; // Amount deposited + uint256 blocked; // Amount blocked } diff --git a/contracts/protocol/watcherPrecompile/DumpDecoder.sol b/contracts/protocol/watcherPrecompile/DumpDecoder.sol new file mode 100644 index 00000000..fb98c56c --- /dev/null +++ b/contracts/protocol/watcherPrecompile/DumpDecoder.sol @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.21; + +import {CallType, Parallel, WriteFinality} from "../utils/common/Structs.sol"; + +library DumpDecoder { + // Corrected mapping (most significant bits on the left): + // [256.....................................................................80][79.............................................0] + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // requestCount(40) | batchCount(40) | payloadCount(40) | chainSlug(32) | callType(8) | isParallel(8) | writeFinality(8) + // + // Bits: + // requestCount: [216..255] (shift >> 216) + // batchCount: [176..215] (shift >> 176, mask 0xFFFFFFFFFF) + // payloadCount: [136..175] + // chainSlug: [104..135] + // callType: [96..103] + // isParallel: [88..95] + // writeFinality: [80..87] + + // ------------------------------------------------------------------------- + // GETTERS + // ------------------------------------------------------------------------- + function getRequestCount(bytes32 dump_) internal pure returns (uint40) { + // Top 40 bits => shift right by 216 + return uint40(uint256(dump_) >> 216); + } + + function getBatchCount(bytes32 dump_) internal pure returns (uint40) { + return uint40((uint256(dump_) >> 176) & 0xFFFFFFFFFF); + } + + function getPayloadCount(bytes32 dump_) internal pure returns (uint40) { + return uint40((uint256(dump_) >> 136) & 0xFFFFFFFFFF); + } + + function getChainSlug(bytes32 dump_) internal pure returns (uint32) { + return uint32((uint256(dump_) >> 104) & 0xFFFFFFFF); + } + + function getCallType(bytes32 dump_) internal pure returns (CallType) { + return CallType(uint8((uint256(dump_) >> 96) & 0xFF)); + } + + function getIsParallel(bytes32 dump_) internal pure returns (Parallel) { + return Parallel(uint8((uint256(dump_) >> 88) & 0xFF)); + } + + function getWriteFinality(bytes32 dump_) internal pure returns (WriteFinality) { + return WriteFinality(uint8((uint256(dump_) >> 80) & 0xFF)); + } + + // ------------------------------------------------------------------------- + // SETTERS + // ------------------------------------------------------------------------- + + /// @notice Sets the request count in a dump (top 40 bits) + function setRequestCount(bytes32 dump_, uint40 requestCount_) internal pure returns (bytes32) { + // Clear bits [216..255], then OR in the new requestCount << 216 + return + bytes32( + (uint256(dump_) & ~((uint256(0xFFFFFFFFFF)) << 216)) | + (uint256(requestCount_) << 216) + ); + } + + /// @notice Sets the batch count in a dump [176..215] + function setBatchCount(bytes32 dump_, uint40 batchCount_) internal pure returns (bytes32) { + return + bytes32( + (uint256(dump_) & ~((uint256(0xFFFFFFFFFF)) << 176)) | + ((uint256(batchCount_) & 0xFFFFFFFFFF) << 176) + ); + } + + /// @notice Sets the payload count [136..175] + function setPayloadCount(bytes32 dump_, uint40 payloadCount_) internal pure returns (bytes32) { + return + bytes32( + (uint256(dump_) & ~((uint256(0xFFFFFFFFFF)) << 136)) | + ((uint256(payloadCount_) & 0xFFFFFFFFFF) << 136) + ); + } + + /// @notice Sets the chain slug [104..135] + function setChainSlug(bytes32 dump_, uint32 chainSlug_) internal pure returns (bytes32) { + return + bytes32( + (uint256(dump_) & ~((uint256(0xFFFFFFFF)) << 104)) | + ((uint256(chainSlug_) & 0xFFFFFFFF) << 104) + ); + } + + /// @notice Sets the call type [96..103] + function setCallType(bytes32 dump_, CallType callType_) internal pure returns (bytes32) { + return + bytes32( + (uint256(dump_) & ~((uint256(0xFF)) << 96)) | + ((uint256(uint8(callType_)) & 0xFF) << 96) + ); + } + + /// @notice Sets the parallel flag [88..95] + function setIsParallel(bytes32 dump_, Parallel isParallel_) internal pure returns (bytes32) { + return + bytes32( + (uint256(dump_) & ~((uint256(0xFF)) << 88)) | + ((uint256(uint8(isParallel_)) & 0xFF) << 88) + ); + } + + /// @notice Sets the write finality [80..87] + function setWriteFinality( + bytes32 dump_, + WriteFinality writeFinality_ + ) internal pure returns (bytes32) { + return + bytes32( + (uint256(dump_) & ~((uint256(0xFF)) << 80)) | + ((uint256(uint8(writeFinality_)) & 0xFF) << 80) + ); + } + + // ------------------------------------------------------------------------- + // CREATE + // ------------------------------------------------------------------------- + /// @notice Creates a new dump with all fields set + function createDump( + uint40 requestCount_, + uint40 batchCount_, + uint40 payloadCount_, + uint32 chainSlug_, + CallType callType_, + Parallel isParallel_, + WriteFinality writeFinality_ + ) internal pure returns (bytes32) { + return + bytes32( + (uint256(requestCount_) << 216) | + ((uint256(batchCount_) & 0xFFFFFFFFFF) << 176) | + ((uint256(payloadCount_) & 0xFFFFFFFFFF) << 136) | + ((uint256(chainSlug_) & 0xFFFFFFFF) << 104) | + ((uint256(uint8(callType_)) & 0xFF) << 96) | + ((uint256(uint8(isParallel_)) & 0xFF) << 88) | + ((uint256(uint8(writeFinality_)) & 0xFF) << 80) + ); + } +} diff --git a/contracts/protocol/watcherPrecompile/RequestHandler.sol b/contracts/protocol/watcherPrecompile/RequestHandler.sol new file mode 100644 index 00000000..da161179 --- /dev/null +++ b/contracts/protocol/watcherPrecompile/RequestHandler.sol @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.21; + +import "./WatcherPrecompileCore.sol"; + +abstract contract RequestHandler is WatcherPrecompileCore { + using DumpDecoder for bytes32; + + function submitRequest( + PayloadSubmitParams[] calldata payloadSubmitParams + ) public returns (uint40 requestCount) { + requestCount = nextRequestCount++; + uint40 batchCount = nextBatchCount; + uint40 currentBatch = batchCount; + + address appGateway = _checkAppGateways(payloadSubmitParams); + + uint256 readCount; + uint256 writeCount; + PayloadSubmitParams memory lastP; + + for (uint256 i = 0; i < payloadSubmitParams.length; i++) { + PayloadSubmitParams memory p = payloadSubmitParams[i]; + + // Count reads and writes + if (p.callType == CallType.READ) { + readCount++; + } else writeCount++; + + if (i > 0) { + if (p.levelNumber != lastP.levelNumber && p.levelNumber != lastP.levelNumber + 1) + revert InvalidLevelNumber(); + if (p.levelNumber == lastP.levelNumber + 1) { + requestBatchIds[requestCount].push(batchCount); + batchCount = ++nextBatchCount; + } + } + + uint40 localPayloadCount = payloadCounter++; + bytes32 payloadId = _createPayloadId(p, requestCount, batchCount, localPayloadCount); + batchPayloadIds[batchCount].push(payloadId); + + bytes32 dump; + dump = dump.setRequestCount(requestCount); + dump = dump.setBatchCount(batchCount); + dump = dump.setPayloadCount(localPayloadCount); + dump = dump.setChainSlug(p.chainSlug); + dump = dump.setCallType(p.callType); + dump = dump.setIsParallel(p.isParallel); + dump = dump.setWriteFinality(p.writeFinality); + + payloads[payloadId].dump = dump; + payloads[payloadId].asyncPromise = p.asyncPromise; + payloads[payloadId].switchboard = p.switchboard; + payloads[payloadId].target = p.target; + payloads[payloadId].appGateway = p.callType == CallType.DEPLOY + ? addressResolver__.deliveryHelper() + : p.appGateway; + payloads[payloadId].payloadId = payloadId; + payloads[payloadId].prevDigestsHash = bytes32(0); + payloads[payloadId].gasLimit = p.gasLimit; + payloads[payloadId].value = p.value; + payloads[payloadId].readAt = p.readAt; + payloads[payloadId].deadline = 0; + payloads[payloadId].payload = p.payload; + payloads[payloadId].finalizedTransmitter = address(0); + + requestParams[requestCount].payloadParamsArray.push(payloads[payloadId]); + lastP = p; + } + + requestBatchIds[requestCount].push(nextBatchCount++); + + watcherPrecompileLimits__.consumeLimit(appGateway, QUERY, readCount); + watcherPrecompileLimits__.consumeLimit(appGateway, FINALIZE, writeCount); + requestParams[requestCount].isRequestCancelled = false; + requestParams[requestCount].currentBatch = currentBatch; + requestParams[requestCount].currentBatchPayloadsLeft = 0; + requestParams[requestCount].payloadsRemaining = payloadSubmitParams.length; + requestParams[requestCount].middleware = msg.sender; + requestParams[requestCount].transmitter = address(0); + + emit RequestSubmitted( + msg.sender, + requestCount, + requestParams[requestCount].payloadParamsArray + ); + } + + function _checkAppGateways( + PayloadSubmitParams[] calldata payloadSubmitParams + ) internal view returns (address appGateway) { + bool isDeliveryHelper = msg.sender == addressResolver__.deliveryHelper(); + address coreAppGateway = isDeliveryHelper + ? payloadSubmitParams[0].appGateway + : _getCoreAppGateway(payloadSubmitParams[0].appGateway); + for (uint256 i = 0; i < payloadSubmitParams.length; i++) { + address callerAppGateway = isDeliveryHelper + ? payloadSubmitParams[i].appGateway + : msg.sender; + appGateway = _getCoreAppGateway(callerAppGateway); + if (appGateway != coreAppGateway) revert InvalidGateway(); + } + } + + function startProcessingRequest(uint40 requestCount, address transmitter) public { + RequestParams storage r = requestParams[requestCount]; + if (r.middleware != msg.sender) revert InvalidCaller(); + if (r.transmitter != address(0)) revert AlreadyStarted(); + if (r.currentBatchPayloadsLeft > 0) revert AlreadyStarted(); + + uint40 batchCount = r.payloadParamsArray[0].dump.getBatchCount(); + r.transmitter = transmitter; + r.currentBatch = batchCount; + + uint256 totalPayloadsLeft = _processBatch(requestCount, batchCount); + // todo: for retry cases + r.currentBatchPayloadsLeft = totalPayloadsLeft; + } + + function _processBatch( + uint40 requestCount_, + uint40 batchCount_ + ) internal returns (uint256 totalPayloadsLeft) { + RequestParams memory r = requestParams[requestCount_]; + PayloadParams[] memory payloadParamsArray = _getBatch(batchCount_); + + if (r.isRequestCancelled) revert RequestCancelled(); + + for (uint40 i = 0; i < payloadParamsArray.length; i++) { + bool executed = isPromiseExecuted[payloadParamsArray[i].payloadId]; + if (executed) continue; + totalPayloadsLeft++; + + if (payloadParamsArray[i].dump.getCallType() != CallType.READ) { + _finalize(payloadParamsArray[i], r.transmitter); + } else { + _query(payloadParamsArray[i]); + } + } + } + + function getCurrentRequestCount() external view returns (uint40) { + return nextRequestCount; + } +} diff --git a/contracts/protocol/watcherPrecompile/WatcherPrecompile.sol b/contracts/protocol/watcherPrecompile/WatcherPrecompile.sol index d9c55f32..c8bc8a76 100644 --- a/contracts/protocol/watcherPrecompile/WatcherPrecompile.sol +++ b/contracts/protocol/watcherPrecompile/WatcherPrecompile.sol @@ -1,72 +1,12 @@ // SPDX-License-Identifier: Unlicense pragma solidity ^0.8.21; -import "./WatcherPrecompileConfig.sol"; +import "./RequestHandler.sol"; /// @title WatcherPrecompile /// @notice Contract that handles payload verification, execution and app configurations -contract WatcherPrecompile is WatcherPrecompileConfig { - /// @notice Error thrown when an invalid chain slug is provided - error InvalidChainSlug(); - /// @notice Error thrown when an invalid app gateway reaches a plug - error InvalidConnection(); - /// @notice Error thrown if winning bid is assigned to an invalid transmitter - error InvalidTransmitter(); - /// @notice Error thrown when a timeout request is invalid - error InvalidTimeoutRequest(); - /// @notice Error thrown when a payload id is invalid - error InvalidPayloadId(); - /// @notice Error thrown when a caller is invalid - error InvalidCaller(); - - event CalledAppGateway( - bytes32 callId, - uint32 chainSlug, - address plug, - address appGateway, - bytes32 params, - bytes payload - ); - - /// @notice Emitted when a new query is requested - /// @param chainSlug The identifier of the destination chain - /// @param targetAddress The address of the target contract - /// @param payloadId The unique identifier for the query - /// @param payload The query data - event QueryRequested(uint32 chainSlug, address targetAddress, bytes32 payloadId, bytes payload); - - /// @notice Emitted when a finalize request is made - /// @param payloadId The unique identifier for the request - /// @param asyncRequest The async request details - event FinalizeRequested(bytes32 indexed payloadId, AsyncRequest asyncRequest); - - /// @notice Emitted when a request is finalized - /// @param payloadId The unique identifier for the request - /// @param asyncRequest The async request details - /// @param proof The proof from the watcher - event Finalized(bytes32 indexed payloadId, AsyncRequest asyncRequest, bytes proof); - - /// @notice Emitted when a promise is resolved - /// @param payloadId The unique identifier for the resolved promise - event PromiseResolved(bytes32 indexed payloadId, bool success, address asyncPromise); - - /// @notice Emitted when a promise is not resolved - /// @param payloadId The unique identifier for the not resolved promise - event PromiseNotResolved(bytes32 indexed payloadId, bool success, address asyncPromise); - - event TimeoutRequested( - bytes32 timeoutId, - address target, - bytes payload, - uint256 executeAt // Epoch time when the task should execute - ); - - /// @notice Emitted when a timeout is resolved - /// @param timeoutId The unique identifier for the timeout - /// @param target The target address for the timeout - /// @param payload The payload data - /// @param executedAt The epoch time when the task was executed - event TimeoutResolved(bytes32 timeoutId, address target, bytes payload, uint256 executedAt); +contract WatcherPrecompile is RequestHandler { + using DumpDecoder for bytes32; constructor() { _disableInitializers(); // disable for implementation @@ -76,20 +16,19 @@ contract WatcherPrecompile is WatcherPrecompileConfig { function initialize( address owner_, address addressResolver_, - uint256 defaultLimit_, uint256 expiryTime_, - uint32 evmxSlug_ + uint32 evmxSlug_, + address watcherPrecompileLimits_, + address watcherPrecompileConfig_ ) public reinitializer(1) { _setAddressResolver(addressResolver_); _initializeOwner(owner_); + + watcherPrecompileLimits__ = IWatcherPrecompileLimits(watcherPrecompileLimits_); + watcherPrecompileConfig__ = IWatcherPrecompileConfig(watcherPrecompileConfig_); maxTimeoutDelayInSeconds = 24 * 60 * 60; // 24 hours expiryTime = expiryTime_; - // limit per day - defaultLimit = defaultLimit_ * 10 ** LIMIT_DECIMALS; - // limit per second - defaultRatePerSecond = defaultLimit / (24 * 60 * 60); - evmxSlug = evmxSlug_; } @@ -99,26 +38,10 @@ contract WatcherPrecompile is WatcherPrecompileConfig { /// @param payload_ The payload data /// @param delayInSeconds_ The delay in seconds function setTimeout( - address appGateway_, - bytes calldata payload_, - uint256 delayInSeconds_ - ) external { - if (delayInSeconds_ > maxTimeoutDelayInSeconds) revert TimeoutDelayTooLarge(); - - // from auction manager - _consumeLimit(appGateway_, SCHEDULE, 1); - uint256 executeAt = block.timestamp + delayInSeconds_; - bytes32 timeoutId = _encodeId(evmxSlug, address(this)); - timeoutRequests[timeoutId] = TimeoutRequest( - timeoutId, - msg.sender, - delayInSeconds_, - executeAt, - 0, - false, - payload_ - ); - emit TimeoutRequested(timeoutId, msg.sender, payload_, executeAt); + uint256 delayInSeconds_, + bytes calldata payload_ + ) external returns (bytes32) { + return _setTimeout(payload_, delayInSeconds_); } /// @notice Ends the timeouts and calls the target address with the callback payload @@ -157,126 +80,27 @@ contract WatcherPrecompile is WatcherPrecompileConfig { // ================== Finalize functions ================== /// @notice Finalizes a payload request, requests the watcher to release the proofs to execute on chain - /// @param params_ The finalization parameters - /// @return payloadId The unique identifier for the finalized request - /// @return digest The digest of the payload parameters + /// @param params_ The payload parameters + /// @param transmitter_ The address of the transmitter function finalize( - address originAppGateway_, - FinalizeParams memory params_ - ) external returns (bytes32 payloadId, bytes32 digest) { - // Generate a unique payload ID by combining chain, target, and counter - payloadId = _encodeWritePayloadId( - params_.payloadDetails.chainSlug, - params_.payloadDetails.target - ); - - digest = _finalize(payloadId, originAppGateway_, params_); - } - - function refinalize(bytes32 payloadId_, FinalizeParams memory params_) external { - if (asyncRequests[payloadId_].appGateway == address(0)) revert InvalidPayloadId(); - if (asyncRequests[payloadId_].finalizedBy != msg.sender) revert InvalidCaller(); - - _finalize(payloadId_, asyncRequests[payloadId_].appGateway, params_); - } - - function _finalize( - bytes32 payloadId_, - address originAppGateway_, - FinalizeParams memory params_ - ) internal returns (bytes32 digest) { - if (params_.transmitter == address(0)) revert InvalidTransmitter(); - - // The app gateway is the caller of this function - _consumeLimit(originAppGateway_, FINALIZE, 1); - - // Verify that the app gateway is properly configured for this chain and target - _verifyConnections( - params_.payloadDetails.chainSlug, - params_.payloadDetails.target, - params_.payloadDetails.appGateway - ); - - // Get the switchboard address from plug configurations - (, address switchboard) = getPlugConfigs( - params_.payloadDetails.chainSlug, - params_.payloadDetails.target - ); - - // Construct parameters for digest calculation - PayloadDigestParams memory digestParams_ = PayloadDigestParams( - params_.payloadDetails.appGateway, - params_.transmitter, - params_.payloadDetails.target, - payloadId_, - params_.payloadDetails.value, - params_.payloadDetails.executionGasLimit, - block.timestamp + expiryTime, - params_.payloadDetails.payload - ); - - // Calculate digest from payload parameters - digest = getDigest(digestParams_); - - // Create and store the async request with all necessary details - AsyncRequest memory asyncRequest = AsyncRequest( - msg.sender, - params_.payloadDetails.appGateway, - params_.transmitter, - params_.payloadDetails.target, - switchboard, - params_.payloadDetails.executionGasLimit, - block.timestamp + expiryTime, - params_.asyncId, - digest, - params_.payloadDetails.payload, - params_.payloadDetails.next - ); - asyncRequests[payloadId_] = asyncRequest; - emit FinalizeRequested(payloadId_, asyncRequest); + PayloadParams memory params_, + address transmitter_ + ) external returns (bytes32 digest) { + digest = _finalize(params_, transmitter_); } // ================== Query functions ================== /// @notice Creates a new query request - /// @param chainSlug_ The identifier of the destination chain - /// @param targetAddress_ The address of the target contract - /// @param asyncPromises_ Array of promise addresses to be resolved - /// @param payload_ The query payload data - /// @return payloadId The unique identifier for the query - function query( - uint32 chainSlug_, - address targetAddress_, - address appGateway_, - address[] memory asyncPromises_, - bytes memory payload_ - ) public returns (bytes32 payloadId) { - // from payload delivery - _consumeLimit(appGateway_, QUERY, 1); - // Generate unique payload ID from query counter - payloadId = _encodeId(evmxSlug, address(this)); - - // Create async request with minimal information for queries - // Note: addresses set to 0 as they're not needed for queries - AsyncRequest memory asyncRequest_ = AsyncRequest( - msg.sender, - address(0), - address(0), - targetAddress_, - address(0), - 0, - block.timestamp + expiryTime, - bytes32(0), - bytes32(0), - payload_, - asyncPromises_ - ); - asyncRequests[payloadId] = asyncRequest_; - emit QueryRequested(chainSlug_, targetAddress_, payloadId, payload_); + /// @param params_ The payload parameters + function query(PayloadParams memory params_) external { + _query(params_); } /// @notice Marks a request as finalized with a proof on digest /// @param payloadId_ The unique identifier of the request /// @param proof_ The watcher's proof + /// @param signatureNonce_ The nonce of the signature + /// @param signature_ The signature of the watcher /// @dev Only callable by the contract owner /// @dev Watcher signs on following digest for validation on switchboard: /// @dev keccak256(abi.encode(switchboard, digest)) @@ -293,7 +117,26 @@ contract WatcherPrecompile is WatcherPrecompileConfig { ); watcherProofs[payloadId_] = proof_; - emit Finalized(payloadId_, asyncRequests[payloadId_], proof_); + emit Finalized(payloadId_, proof_); + } + + function updateTransmitter(uint40 requestCount, address transmitter) public { + RequestParams storage r = requestParams[requestCount]; + if (r.isRequestCancelled) revert RequestCancelled(); + if (r.middleware != msg.sender) revert InvalidCaller(); + if (r.transmitter != address(0)) revert AlreadyStarted(); + + r.transmitter = transmitter; + /// todo: recheck limits + _processBatch(requestCount, r.currentBatch); + } + + function cancelRequest(uint40 requestCount) external { + RequestParams storage r = requestParams[requestCount]; + if (r.isRequestCancelled) revert RequestAlreadyCancelled(); + if (r.middleware != msg.sender) revert InvalidCaller(); + + r.isRequestCancelled = true; } /// @notice Resolves multiple promises with their return data @@ -312,26 +155,46 @@ contract WatcherPrecompile is WatcherPrecompileConfig { for (uint256 i = 0; i < resolvedPromises_.length; i++) { // Get the array of promise addresses for this payload - AsyncRequest memory asyncRequest_ = asyncRequests[resolvedPromises_[i].payloadId]; - address[] memory next = asyncRequest_.next; + PayloadParams memory payloadParams = payloads[resolvedPromises_[i].payloadId]; + address asyncPromise = payloadParams.asyncPromise; + if (asyncPromise == address(0)) continue; // Resolve each promise with its corresponding return data - bool success; - for (uint256 j = 0; j < next.length; j++) { - if (next[j] == address(0)) continue; - success = IPromise(next[j]).markResolved( - asyncRequest_.asyncId, - resolvedPromises_[i].payloadId, - resolvedPromises_[i].returnData[j] + bool success = IPromise(asyncPromise).markResolved( + payloadParams.dump.getRequestCount(), + resolvedPromises_[i].payloadId, + resolvedPromises_[i].returnData + ); + + isPromiseExecuted[resolvedPromises_[i].payloadId] = true; + if (!success) { + emit PromiseNotResolved(resolvedPromises_[i].payloadId, asyncPromise); + continue; + } + + RequestParams storage requestParams_ = requestParams[ + payloadParams.dump.getRequestCount() + ]; + + requestParams_.currentBatchPayloadsLeft--; + requestParams_.payloadsRemaining--; + + if ( + requestParams_.currentBatchPayloadsLeft == 0 && requestParams_.payloadsRemaining > 0 + ) { + uint256 totalPayloadsLeft = _processBatch( + payloadParams.dump.getRequestCount(), + ++requestParams_.currentBatch ); + requestParams_.currentBatchPayloadsLeft = totalPayloadsLeft; + } - if (!success) { - emit PromiseNotResolved(resolvedPromises_[i].payloadId, success, next[j]); - break; - } else { - emit PromiseResolved(resolvedPromises_[i].payloadId, success, next[j]); - } + if (requestParams_.payloadsRemaining == 0) { + IMiddleware(requestParams_.middleware).finishRequest( + payloadParams.dump.getRequestCount() + ); } + emit PromiseResolved(resolvedPromises_[i].payloadId, asyncPromise); } } @@ -348,40 +211,23 @@ contract WatcherPrecompile is WatcherPrecompileConfig { signature_ ); - AsyncRequest memory asyncRequest_ = asyncRequests[payloadId_]; - address[] memory next = asyncRequest_.next; - - for (uint256 j = 0; j < next.length; j++) { - if (isRevertingOnchain_) - IPromise(next[j]).markOnchainRevert(asyncRequest_.asyncId, payloadId_); + PayloadParams storage payloadParams = payloads[payloadId_]; + RequestParams storage currentRequestParams = requestParams[ + payloadParams.dump.getRequestCount() + ]; + currentRequestParams.isRequestCancelled = true; - // assign fees after expiry time - IFeesManager(asyncRequest_.appGateway).unblockAndAssignFees( - asyncRequest_.asyncId, - asyncRequest_.transmitter, - asyncRequest_.appGateway + if (isRevertingOnchain_) + IPromise(payloadParams.asyncPromise).markOnchainRevert( + payloadParams.dump.getRequestCount(), + payloadId_ ); - // batch.isBatchCancelled - } - } - - /// @notice Calculates the digest hash of payload parameters - /// @param params_ The payload parameters - /// @return digest The calculated digest - function getDigest(PayloadDigestParams memory params_) public pure returns (bytes32 digest) { - digest = keccak256( - abi.encode( - params_.payloadId, - params_.appGateway, - params_.transmitter, - params_.target, - params_.value, - params_.deadline, - params_.executionGasLimit, - params_.payload - ) + IMiddleware(currentRequestParams.middleware).handleRequestReverts( + payloadParams.dump.getRequestCount() ); + + emit MarkedRevert(payloadId_, isRevertingOnchain_); } function setMaxTimeoutDelayInSeconds(uint256 maxTimeoutDelayInSeconds_) external onlyOwner { @@ -403,15 +249,22 @@ contract WatcherPrecompile is WatcherPrecompileConfig { for (uint256 i = 0; i < params_.length; i++) { if (appGatewayCalled[params_[i].callId]) revert AppGatewayAlreadyCalled(); - if (!isValidPlug[params_[i].appGateway][params_[i].chainSlug][params_[i].plug]) - revert InvalidInboxCaller(); + if ( + !watcherPrecompileConfig__.isValidPlug( + params_[i].appGateway, + params_[i].chainSlug, + params_[i].plug + ) + ) revert InvalidInboxCaller(); + appGatewayCalled[params_[i].callId] = true; IAppGateway(params_[i].appGateway).callFromChain( params_[i].chainSlug, params_[i].plug, - params_[i].payload, - params_[i].params + params_[i].params, + params_[i].payload ); + emit CalledAppGateway( params_[i].callId, params_[i].chainSlug, @@ -425,46 +278,11 @@ contract WatcherPrecompile is WatcherPrecompileConfig { // ================== Helper functions ================== - /// @notice Verifies the connection between chain slug, target, and app gateway - /// @param chainSlug_ The identifier of the chain - /// @param target_ The target address - /// @param appGateway_ The app gateway address to verify - /// @dev Internal function to validate connections - function _verifyConnections( - uint32 chainSlug_, - address target_, - address appGateway_ - ) internal view { - (address appGateway, ) = getPlugConfigs(chainSlug_, target_); - if (appGateway != appGateway_) revert InvalidConnection(); - } - - /// @notice Encodes a unique payload ID from chain slug, plug address, and counter - /// @param chainSlug_ The identifier of the chain - /// @param plug_ The plug address - /// @return The encoded payload ID as bytes32 - /// @dev Reverts if chainSlug is 0 - function _encodeWritePayloadId(uint32 chainSlug_, address plug_) internal returns (bytes32) { - if (chainSlug_ == 0) revert InvalidChainSlug(); - (, address switchboard) = getPlugConfigs(chainSlug_, plug_); - return _encodeId(chainSlug_, switchboard); - } - - function _encodeId( - uint32 chainSlug_, - address switchboardOrWatcher_ - ) internal returns (bytes32) { - // Encode payload ID by bit-shifting and combining: - // chainSlug (32 bits) | switchboard or watcher precompile address (160 bits) | counter (64 bits) - return - bytes32( - (uint256(chainSlug_) << 224) | - (uint256(uint160(switchboardOrWatcher_)) << 64) | - payloadCounter++ - ); - } - function setExpiryTime(uint256 expiryTime_) external onlyOwner { expiryTime = expiryTime_; } + + function getRequestParams(uint40 requestCount) external view returns (RequestParams memory) { + return requestParams[requestCount]; + } } diff --git a/contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol b/contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol index ca5e6fac..881b3706 100644 --- a/contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol +++ b/contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol @@ -3,13 +3,55 @@ pragma solidity ^0.8.21; import "./WatcherPrecompileLimits.sol"; import {ECDSA} from "solady/utils/ECDSA.sol"; +import "solady/utils/Initializable.sol"; +import "../../interfaces/IWatcherPrecompileConfig.sol"; /// @title WatcherPrecompileConfig /// @notice Configuration contract for the Watcher Precompile system /// @dev Handles the mapping between networks, plugs, and app gateways for payload execution -abstract contract WatcherPrecompileConfig is WatcherPrecompileLimits { - // slot 322-371: gap for future storage variables - uint256[50] _gap_watcher_precompile_config; +contract WatcherPrecompileConfig is + IWatcherPrecompileConfig, + Initializable, + AccessControl, + AddressResolverUtil +{ + // slot 52: evmxSlug + /// @notice The chain slug of the watcher precompile + uint32 public evmxSlug; + + // slot 55: _plugConfigs + /// @notice Maps network and plug to their configuration + /// @dev chainSlug => plug => PlugConfig + mapping(uint32 => mapping(address => PlugConfig)) internal _plugConfigs; + + // slot 56: switchboards + /// @notice Maps chain slug to their associated switchboard + /// @dev chainSlug => sb type => switchboard address + mapping(uint32 => mapping(bytes32 => address)) public switchboards; + + // slot 57: sockets + /// @notice Maps chain slug to their associated socket + /// @dev chainSlug => socket address + mapping(uint32 => address) public sockets; + + // slot 58: contractFactoryPlug + /// @notice Maps chain slug to their associated contract factory plug + /// @dev chainSlug => contract factory plug address + mapping(uint32 => address) public contractFactoryPlug; + + // slot 59: feesPlug + /// @notice Maps chain slug to their associated fees plug + /// @dev chainSlug => fees plug address + mapping(uint32 => address) public feesPlug; + + // slot 60: isNonceUsed + /// @notice Maps nonce to whether it has been used + /// @dev signatureNonce => isValid + mapping(uint256 => bool) public isNonceUsed; + + // slot 61: isValidPlug + // appGateway => chainSlug => plug => isValid + mapping(address => mapping(uint32 => mapping(address => bool))) public isValidPlug; /// @notice Emitted when a new plug is configured for an app gateway /// @param appGateway The address of the app gateway @@ -25,20 +67,35 @@ abstract contract WatcherPrecompileConfig is WatcherPrecompileLimits { /// @notice Emitted when contracts are set for a network /// @param chainSlug The identifier of the network - /// @param sbType The type of switchboard - /// @param switchboard The address of the switchboard /// @param socket The address of the socket /// @param contractFactoryPlug The address of the contract factory plug /// @param feesPlug The address of the fees plug event OnChainContractSet( uint32 chainSlug, - bytes32 sbType, - address switchboard, address socket, address contractFactoryPlug, address feesPlug ); + error InvalidGateway(); + error InvalidSwitchboard(); + error NonceUsed(); + error InvalidWatcherSignature(); + + /// @notice Initial initialization (version 1) + function initialize( + address owner_, + address addressResolver_, + uint32 evmxSlug_ + ) public reinitializer(1) { + _setAddressResolver(addressResolver_); + _initializeOwner(owner_); + + evmxSlug = evmxSlug_; + } + + /// @notice Emitted when a plug is set as valid for an app gateway + /// @notice Configures app gateways with their respective plugs and switchboards /// @param configs_ Array of configurations containing app gateway, network, plug, and switchboard details /// @dev Only callable by the contract owner @@ -67,28 +124,29 @@ abstract contract WatcherPrecompileConfig is WatcherPrecompileLimits { /// @notice Sets the switchboard for a network /// @param chainSlug_ The identifier of the network - /// @param switchboard_ The address of the switchboard function setOnChainContracts( uint32 chainSlug_, - bytes32 sbType_, - address switchboard_, address socket_, address contractFactoryPlug_, address feesPlug_ - ) external override onlyOwner { - switchboards[chainSlug_][sbType_] = switchboard_; + ) external onlyOwner { sockets[chainSlug_] = socket_; contractFactoryPlug[chainSlug_] = contractFactoryPlug_; feesPlug[chainSlug_] = feesPlug_; - emit OnChainContractSet( - chainSlug_, - sbType_, - switchboard_, - socket_, - contractFactoryPlug_, - feesPlug_ - ); + emit OnChainContractSet(chainSlug_, socket_, contractFactoryPlug_, feesPlug_); + } + + /// @notice Sets the switchboard for a network + /// @param chainSlug_ The identifier of the network + /// @param switchboard_ The address of the switchboard + function setSwitchboard( + uint32 chainSlug_, + bytes32 sbType_, + address switchboard_ + ) external onlyOwner { + switchboards[chainSlug_][sbType_] = switchboard_; + emit SwitchboardSet(chainSlug_, sbType_, switchboard_); } // @dev app gateway can set the valid plugs for each chain slug @@ -111,6 +169,21 @@ abstract contract WatcherPrecompileConfig is WatcherPrecompileLimits { ); } + function verifyConnections( + uint32 chainSlug_, + address target_, + address appGateway_, + address switchboard_ + ) external view { + // todo: revisit this + // if target is contractFactoryPlug, return + if (target_ == contractFactoryPlug[chainSlug_]) return; + + (address appGateway, address switchboard) = getPlugConfigs(chainSlug_, target_); + if (appGateway != appGateway_) revert InvalidGateway(); + if (switchboard != switchboard_) revert InvalidSwitchboard(); + } + function _isWatcherSignatureValid( bytes memory digest_, uint256 signatureNonce_, diff --git a/contracts/protocol/watcherPrecompile/WatcherPrecompileCore.sol b/contracts/protocol/watcherPrecompile/WatcherPrecompileCore.sol new file mode 100644 index 00000000..7950823e --- /dev/null +++ b/contracts/protocol/watcherPrecompile/WatcherPrecompileCore.sol @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.21; + +import "./WatcherPrecompileStorage.sol"; +import {ECDSA} from "solady/utils/ECDSA.sol"; +import {AccessControl} from "../utils/AccessControl.sol"; +import "solady/utils/Initializable.sol"; +import {AddressResolverUtil} from "../utils/AddressResolverUtil.sol"; + +/// @title WatcherPrecompile +/// @notice Contract that handles payload verification, execution and app configurations +abstract contract WatcherPrecompileCore is + IWatcherPrecompile, + WatcherPrecompileStorage, + Initializable, + AccessControl, + AddressResolverUtil +{ + using DumpDecoder for bytes32; + + // ================== Timeout functions ================== + + /// @notice Sets a timeout for a payload execution on app gateway + /// @param payload_ The payload data + /// @param delayInSeconds_ The delay in seconds + function _setTimeout( + bytes calldata payload_, + uint256 delayInSeconds_ + ) internal returns (bytes32 timeoutId) { + if (delayInSeconds_ > maxTimeoutDelayInSeconds) revert TimeoutDelayTooLarge(); + + // from auction manager + watcherPrecompileLimits__.consumeLimit(_getCoreAppGateway(msg.sender), SCHEDULE, 1); + uint256 executeAt = block.timestamp + delayInSeconds_; + timeoutId = _encodeId(evmxSlug, address(this)); + timeoutRequests[timeoutId] = TimeoutRequest( + timeoutId, + msg.sender, + delayInSeconds_, + executeAt, + 0, + false, + payload_ + ); + emit TimeoutRequested(timeoutId, msg.sender, payload_, executeAt); + } + + function _finalize( + PayloadParams memory params_, + address transmitter_ + ) internal returns (bytes32 digest) { + // Verify that the app gateway is properly configured for this chain and target + watcherPrecompileConfig__.verifyConnections( + params_.dump.getChainSlug(), + params_.target, + params_.appGateway, + params_.switchboard + ); + + uint256 deadline = block.timestamp + expiryTime; + payloads[params_.payloadId].deadline = deadline; + payloads[params_.payloadId].finalizedTransmitter = transmitter_; + + bytes32 prevDigestsHash = _getPreviousDigestsHash( + params_.dump.getRequestCount(), + params_.dump.getBatchCount() + ); + payloads[params_.payloadId].prevDigestsHash = prevDigestsHash; + + // Construct parameters for digest calculation + DigestParams memory digestParams_ = DigestParams( + transmitter_, + params_.payloadId, + deadline, + params_.dump.getCallType(), + params_.dump.getWriteFinality(), + params_.gasLimit, + params_.value, + params_.readAt, + params_.payload, + params_.target, + params_.appGateway, + prevDigestsHash + ); + + // Calculate digest from payload parameters + digest = getDigest(digestParams_); + emit FinalizeRequested(digest, payloads[params_.payloadId]); + } + + function _getBatch(uint40 batchCount) internal view returns (PayloadParams[] memory) { + bytes32[] memory payloadIds = batchPayloadIds[batchCount]; + PayloadParams[] memory payloadParamsArray = new PayloadParams[](payloadIds.length); + + for (uint40 i = 0; i < payloadIds.length; i++) { + payloadParamsArray[i] = payloads[payloadIds[i]]; + } + return payloadParamsArray; + } + + // ================== Query functions ================== + /// @notice Creates a new query request + /// @param params_ The payload parameters + function _query(PayloadParams memory params_) internal { + bytes32 prevDigestsHash = _getPreviousDigestsHash( + params_.dump.getRequestCount(), + params_.dump.getBatchCount() + ); + payloads[params_.payloadId].prevDigestsHash = prevDigestsHash; + emit QueryRequested(params_); + } + + /// @notice Calculates the digest hash of payload parameters + /// @param params_ The payload parameters + /// @return digest The calculated digest + function getDigest(DigestParams memory params_) public pure returns (bytes32 digest) { + digest = keccak256( + abi.encode( + params_.transmitter, + params_.payloadId, + params_.deadline, + params_.callType, + params_.writeFinality, + params_.gasLimit, + params_.value, + params_.readAt, + params_.payload, + params_.target, + params_.appGateway, + params_.prevDigestsHash + ) + ); + } + + function _getPreviousDigestsHash( + uint40 requestCount_, + uint40 batchCount_ + ) internal view returns (bytes32) { + RequestParams memory r = requestParams[requestCount_]; + + // If this is the first batch of the request, return 0 bytes + if (batchCount_ == r.payloadParamsArray[0].dump.getBatchCount()) { + return bytes32(0); + } + + PayloadParams[] memory previousPayloads = _getBatch(batchCount_ - 1); + bytes32 prevDigestsHash = bytes32(0); + + for (uint40 i = 0; i < previousPayloads.length; i++) { + PayloadParams memory p = payloads[previousPayloads[i].payloadId]; + DigestParams memory digestParams = DigestParams( + p.finalizedTransmitter, + p.payloadId, + p.deadline, + p.dump.getCallType(), + p.dump.getWriteFinality(), + p.gasLimit, + p.value, + p.readAt, + p.payload, + p.target, + p.appGateway, + p.prevDigestsHash + ); + prevDigestsHash = keccak256(abi.encodePacked(prevDigestsHash, getDigest(digestParams))); + } + return prevDigestsHash; + } + + // ================== Helper functions ================== + + /// @notice Verifies the connection between chain slug, target, and app gateway + /// @param chainSlug_ The identifier of the chain + /// @param target_ The target address + /// @param appGateway_ The app gateway address to verify + /// @dev Internal function to validate connections + function _verifyConnections( + uint32 chainSlug_, + address target_, + address appGateway_, + address switchboard_ + ) internal view { + // todo: revisit this + // if target is contractFactoryPlug, return + if (target_ == watcherPrecompileConfig__.contractFactoryPlug(chainSlug_)) return; + + (address appGateway, address switchboard) = watcherPrecompileConfig__.getPlugConfigs( + chainSlug_, + target_ + ); + if (appGateway != appGateway_) revert InvalidGateway(); + if (switchboard != switchboard_) revert InvalidSwitchboard(); + } + + // todo: revisit when we do timeout precompile + function _encodeId( + uint32 chainSlug_, + address switchboardOrWatcher_ + ) internal returns (bytes32) { + // Encode payload ID by bit-shifting and combining: + // chainSlug (32 bits) | switchboard or watcher precompile address (160 bits) | counter (64 bits) + return + bytes32( + (uint256(chainSlug_) << 224) | + (uint256(uint160(switchboardOrWatcher_)) << 64) | + payloadCounter++ + ); + } + + function _createPayloadId( + PayloadSubmitParams memory p_, + uint40 requestCount_, + uint40 batchCount_, + uint40 payloadCount_ + ) internal pure returns (bytes32) { + return + keccak256( + abi.encode(requestCount_, batchCount_, payloadCount_, p_.switchboard, p_.chainSlug) + ); + } + + function _isWatcherSignatureValid( + bytes memory digest_, + uint256 signatureNonce_, + bytes memory signature_ + ) internal { + if (isNonceUsed[signatureNonce_]) revert NonceUsed(); + isNonceUsed[signatureNonce_] = true; + + bytes32 digest = keccak256(abi.encode(address(this), evmxSlug, signatureNonce_, digest_)); + digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest)); + + // recovered signer is checked for the valid roles later + address signer = ECDSA.recover(digest, signature_); + if (signer != owner()) revert InvalidWatcherSignature(); + } + + function getBatches(uint40 requestCount_) external view returns (uint40[] memory) { + return requestBatchIds[requestCount_]; + } + + function getBatchPayloadIds(uint40 batchCount_) external view returns (bytes32[] memory) { + return batchPayloadIds[batchCount_]; + } + + function getPayloadParams(bytes32 payloadId_) external view returns (PayloadParams memory) { + return payloads[payloadId_]; + } +} diff --git a/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol b/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol index 7f62d344..42f1d2b4 100644 --- a/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol +++ b/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol @@ -5,11 +5,12 @@ import {AccessControl} from "../utils/AccessControl.sol"; import {Gauge} from "../utils/Gauge.sol"; import {AddressResolverUtil} from "../utils/AddressResolverUtil.sol"; import {WATCHER_ROLE} from "../utils/common/AccessRoles.sol"; -import "./WatcherPrecompileStorage.sol"; +import "../../interfaces/IWatcherPrecompileLimits.sol"; import "solady/utils/Initializable.sol"; +import {SCHEDULE, QUERY, FINALIZE} from "../utils/common/Constants.sol"; -abstract contract WatcherPrecompileLimits is - WatcherPrecompileStorage, +contract WatcherPrecompileLimits is + IWatcherPrecompileLimits, Initializable, AccessControl, Gauge, @@ -24,23 +25,37 @@ abstract contract WatcherPrecompileLimits is // slots 271-320: gap for future storage variables uint256[50] _gap_watcher_precompile_limits; - //////////////////////////////////////////////////////// - ////////////////////// EVENTS ////////////////////////// - //////////////////////////////////////////////////////// - - // Emitted when limit parameters are updated - event LimitParamsUpdated(UpdateLimitParams[] updates); - // Emitted when an app gateway is activated with default limits - event AppGatewayActivated(address indexed appGateway, uint256 maxLimit, uint256 ratePerSecond); - - error ActionNotSupported(address appGateway_, bytes32 limitType_); - error NotDeliveryHelper(); - error LimitExceeded( - address appGateway, - bytes32 limitType, - uint256 requested, - uint256 available - ); + /// @notice Number of decimals used in limit calculations + uint256 public constant LIMIT_DECIMALS = 18; + // slot 50: defaultLimit + /// @notice Default limit value for any app gateway + uint256 public defaultLimit; + // slot 51: defaultRatePerSecond + /// @notice Rate at which limit replenishes per second + uint256 public defaultRatePerSecond; + + // slot 53: _limitParams + // appGateway => limitType => receivingLimitParams + mapping(address => mapping(bytes32 => LimitParams)) internal _limitParams; + + // slot 54: _activeAppGateways + // Mapping to track active app gateways + mapping(address => bool) internal _activeAppGateways; + + /// @notice Initial initialization (version 1) + function initialize( + address owner_, + address addressResolver_, + uint256 defaultLimit_ + ) public reinitializer(1) { + _setAddressResolver(addressResolver_); + _initializeOwner(owner_); + + // limit per day + defaultLimit = defaultLimit_ * 10 ** LIMIT_DECIMALS; + // limit per second + defaultRatePerSecond = defaultLimit / (24 * 60 * 60); + } /** * @notice Get the current limit for a specific app gateway and limit type @@ -68,21 +83,6 @@ abstract contract WatcherPrecompileLimits is return _limitParams[appGateway_][limitType_]; } - /** - * @notice Check and update limit for a specific app gateway - * @param appGateway_ The app gateway address - * @param limitType_ The type of limit to check - * @param consumeLimit_ The amount of limit to consume - */ - function checkAndConsumeLimit( - address appGateway_, - bytes32 limitType_, - uint256 consumeLimit_ - ) external { - if (msg.sender != addressResolver__.deliveryHelper()) revert NotDeliveryHelper(); - _consumeLimit(appGateway_, limitType_, consumeLimit_); - } - /** * @notice Update limit parameters for multiple app gateways * @param updates_ Array of limit parameter updates @@ -112,21 +112,16 @@ abstract contract WatcherPrecompileLimits is * @param appGateway_ The app gateway address * @param limitType_ The type of limit to consume * @param consumeLimit_ The amount of limit to consume - * @return appGateway The resolved app gateway address */ - function _consumeLimit( + function consumeLimit( address appGateway_, bytes32 limitType_, uint256 consumeLimit_ - ) internal returns (address appGateway) { - // delivery helper consumes the limit while batching hence returned here - if (msg.sender == addressResolver__.deliveryHelper()) return appGateway_; - - appGateway = _getAppGateway(appGateway_); - LimitParams storage limitParams = _limitParams[appGateway][limitType_]; + ) external override onlyWatcherPrecompile { + LimitParams storage limitParams = _limitParams[appGateway_][limitType_]; // Initialize limit if not active - if (!_activeAppGateways[appGateway]) { + if (!_activeAppGateways[appGateway_]) { LimitParams memory limitParam = LimitParams({ maxLimit: defaultLimit, ratePerSecond: defaultRatePerSecond, @@ -134,31 +129,18 @@ abstract contract WatcherPrecompileLimits is lastUpdateLimit: defaultLimit }); - _limitParams[appGateway][QUERY] = limitParam; - _limitParams[appGateway][FINALIZE] = limitParam; - _limitParams[appGateway][SCHEDULE] = limitParam; + _limitParams[appGateway_][QUERY] = limitParam; + _limitParams[appGateway_][FINALIZE] = limitParam; + _limitParams[appGateway_][SCHEDULE] = limitParam; - _activeAppGateways[appGateway] = true; - emit AppGatewayActivated(appGateway, defaultLimit, defaultRatePerSecond); + _activeAppGateways[appGateway_] = true; + emit AppGatewayActivated(appGateway_, defaultLimit, defaultRatePerSecond); } // Update the limit _consumeFullLimit(consumeLimit_ * 10 ** LIMIT_DECIMALS, limitParams); } - /** - * @notice Internal function to get the core app gateway address - * @param originAppGateway_ The input app gateway address - * @return appGateway The resolved core app gateway address - */ - function _getAppGateway(address originAppGateway_) internal view returns (address appGateway) { - address originAppGateway = msg.sender == addressResolver__.deliveryHelper() - ? originAppGateway_ - : msg.sender; - - appGateway = _getCoreAppGateway(originAppGateway); - } - /** * @notice Set the default limit value * @param defaultLimit_ The new default limit value diff --git a/contracts/protocol/watcherPrecompile/WatcherPrecompileStorage.sol b/contracts/protocol/watcherPrecompile/WatcherPrecompileStorage.sol index e5142824..974a0b03 100644 --- a/contracts/protocol/watcherPrecompile/WatcherPrecompileStorage.sol +++ b/contracts/protocol/watcherPrecompile/WatcherPrecompileStorage.sol @@ -1,102 +1,82 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {IWatcherPrecompile} from "../../interfaces/IWatcherPrecompile.sol"; +import "../../interfaces/IWatcherPrecompile.sol"; import {IAppGateway} from "../../interfaces/IAppGateway.sol"; import {IFeesManager} from "../../interfaces/IFeesManager.sol"; import {IPromise} from "../../interfaces/IPromise.sol"; +import "./DumpDecoder.sol"; +import {IMiddleware} from "../../interfaces/IMiddleware.sol"; import {QUERY, FINALIZE, SCHEDULE} from "../utils/common/Constants.sol"; import {TimeoutDelayTooLarge, TimeoutAlreadyResolved, InvalidInboxCaller, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed} from "../utils/common/Errors.sol"; -import {ResolvedPromises, AppGatewayConfig, LimitParams, UpdateLimitParams, PlugConfig, PayloadDigestParams, AsyncRequest, FinalizeParams, TimeoutRequest, CallFromChainParams} from "../utils/common/Structs.sol"; +import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, TimeoutRequest, CallFromChainParams, QueuePayloadParams, PayloadParams, RequestParams} from "../utils/common/Structs.sol"; abstract contract WatcherPrecompileStorage is IWatcherPrecompile { - // slot 0-49: gap for future storage variables + // slots [0-49]: gap for future storage variables uint256[50] _gap_before; - /// @notice Number of decimals used in limit calculations - uint256 public constant LIMIT_DECIMALS = 18; - - // slot 50: defaultLimit - /// @notice Default limit value for any app gateway - uint256 public defaultLimit; - // slot 51: defaultRatePerSecond - /// @notice Rate at which limit replenishes per second - uint256 public defaultRatePerSecond; - - // slot 52: evmxSlug + // slot 50: evmxSlug /// @notice The chain slug of the watcher precompile uint32 public evmxSlug; - // slot 53: _limitParams - // appGateway => limitType => receivingLimitParams - mapping(address => mapping(bytes32 => LimitParams)) internal _limitParams; - - // slot 54: _activeAppGateways - // Mapping to track active app gateways - mapping(address => bool) internal _activeAppGateways; - - // slot 55: _plugConfigs - /// @notice Maps network and plug to their configuration - /// @dev chainSlug => plug => PlugConfig - mapping(uint32 => mapping(address => PlugConfig)) internal _plugConfigs; - - // slot 56: switchboards - /// @notice Maps chain slug to their associated switchboard - /// @dev chainSlug => sb type => switchboard address - mapping(uint32 => mapping(bytes32 => address)) public switchboards; - - // slot 57: sockets - /// @notice Maps chain slug to their associated socket - /// @dev chainSlug => socket address - mapping(uint32 => address) public sockets; - - // slot 58: contractFactoryPlug - /// @notice Maps chain slug to their associated contract factory plug - /// @dev chainSlug => contract factory plug address - mapping(uint32 => address) public contractFactoryPlug; - - // slot 59: feesPlug - /// @notice Maps chain slug to their associated fees plug - /// @dev chainSlug => fees plug address - mapping(uint32 => address) public feesPlug; - - // slot 60: isNonceUsed + // slot 51: isNonceUsed /// @notice Maps nonce to whether it has been used /// @dev signatureNonce => isValid mapping(uint256 => bool) public isNonceUsed; - // slot 61: isValidPlug - // appGateway => chainSlug => plug => isValid - mapping(address => mapping(uint32 => mapping(address => bool))) public isValidPlug; - - // slot 62: maxTimeoutDelayInSeconds + // slot 52: maxTimeoutDelayInSeconds uint256 public maxTimeoutDelayInSeconds; - // slot 63: payloadCounter + + // slot 53: payloadCounter /// @notice Counter for tracking payload requests - uint256 public payloadCounter; - // slot 64: expiryTime + uint40 public payloadCounter; + + // slot 54: timeoutCounter + /// @notice Counter for tracking timeout requests + uint40 public timeoutCounter; + + // slot 55: expiryTime /// @notice The expiry time for the payload uint256 public expiryTime; - // slot 65: asyncRequests - /// @notice Mapping to store async requests - /// @dev payloadId => AsyncRequest struct - mapping(bytes32 => AsyncRequest) public asyncRequests; - // slot 66: timeoutRequests + // slot 56: timeoutRequests /// @notice Mapping to store timeout requests /// @dev timeoutId => TimeoutRequest struct mapping(bytes32 => TimeoutRequest) public timeoutRequests; - // slot 67: watcherProofs + + // slot 57: watcherProofs /// @notice Mapping to store watcher proofs /// @dev payloadId => proof bytes mapping(bytes32 => bytes) public watcherProofs; - // slot 68: appGatewayCalled + // slot 58: appGatewayCalled /// @notice Mapping to store if appGateway has been called with trigger from on-chain Inbox /// @dev callId => bool mapping(bytes32 => bool) public appGatewayCalled; - // slots 69-118: gap for future storage variables + // slot 59: nextRequestCount + uint40 public nextRequestCount; + + // slot 60: nextBatchCount + uint40 public nextBatchCount; + + // slot 61: requestParams + mapping(uint40 => RequestParams) public requestParams; + // slot 62: batchPayloadIds + mapping(uint40 => bytes32[]) public batchPayloadIds; + // slot 63: requestBatchIds + mapping(uint40 => uint40[]) public requestBatchIds; + // slot 64: payloads + mapping(bytes32 => PayloadParams) public payloads; + // slot 65: isPromiseExecuted + mapping(bytes32 => bool) public isPromiseExecuted; + + // slot 66: watcherPrecompileLimits__ + IWatcherPrecompileLimits public watcherPrecompileLimits__; + // slot 67: watcherPrecompileConfig__ + IWatcherPrecompileConfig public watcherPrecompileConfig__; + + // slots [68-117]: gap for future storage variables uint256[50] _gap_after; } diff --git a/deployments/dev_addresses.json b/deployments/dev_addresses.json index 242369d1..a5ecf711 100644 --- a/deployments/dev_addresses.json +++ b/deployments/dev_addresses.json @@ -1,32 +1,52 @@ { + "84532": { + "ContractFactoryPlug": "0xFEFdbD9CB5bdC58Aa8B6B455923454275392838c", + "FastSwitchboard": "0xCc9f995DAE2D3Cf3C0763e353986E97ab78801b4", + "FeesPlug": "0xBBff19fBEAd971f39F1B298De985D7ADfb57b784", + "Socket": "0x89e66357C5F101C56b4F9F97cf378Cc32A21438a", + "SocketBatcher": "0x3bABE35428D9E2B87d678289f837F805dAB0db3A", + "startBlock": 23827713 + }, "421614": { - "ContractFactoryPlug": "0xCE9aF7Fb0Ee31276Ea64Cd7414d54eC57dA9b675", - "FastSwitchboard": "0x772088727d003f5A6Cf816E745ba6B8F8dEBbCe9", - "FeesPlug": "0xcc38176545fa5f6c2aB970F6d2D62b2D90bBA3Ba", - "Socket": "0xdE177c392Ad47377BA944215A944f530F79E1d87", - "SocketBatcher": "0x6BF08F11bDA6CD571Bc942F23ec38b8652FFfB2D", - "startBlock": 127798344 + "ContractFactoryPlug": "0x10BFD064258ac890957Ca65A85E7997a923Fb551", + "FastSwitchboard": "0xB0feE9136102B99A5722C693C8eb538C8c8d013B", + "FeesPlug": "0x0Ae8458F80a50a4ad706680605c88e050AaC8A89", + "Socket": "0xA99E6020d973C5956dBD727eDB45cDA5F7C4ca99", + "SocketBatcher": "0x3F95273234164329aec7DE66A037a80eb5a8F393", + "startBlock": 136387501 }, "7625382": { - "AddressResolver": "0x403eCBcC4d4bB8Fad09034bf0d197dDC626C832f", - "AddressResolverImpl": "0xbAeF84edEae864Ff22Bd9c9912AdfF84aD490d82", - "AuctionManager": "0x7dc45C49650e2914e3fA6E194e2080775c58256E", - "AuctionManagerImpl": "0xa07e38cAB46eAA358C3653C63219f1009e8F7789", - "DeliveryHelper": "0x0861f0888125e5A243C7af2c3E0F80C357c4c0C0", - "DeliveryHelperImpl": "0x9F10A0c71178dbD4d049f2C04fD0e34966134b9e", - "ERC1967Factory": "0x945e9ab4c08c225C10F178a0bd600BcC2bA7Cc78", - "FeesManager": "0x777fAAf1c30Ce8E68262b1cbF0a752d4f1bA652C", - "FeesManagerImpl": "0xB423eE3bffc3604F96B59cF419C48AE05b8E9d0b", - "startBlock": 73062, - "WatcherPrecompile": "0xadA397123A6E80F67b1887895A62B2D9273E50b4", - "WatcherPrecompileImpl": "0x71956F006Ec5434581D3Fd5E7224BB3bae231907" + "AddressResolver": "0x491DE197D50aaa4F59090DBDa4b5Aa6C2E14A10D", + "AddressResolverImpl": "0x2736Fc0AA0fa5Ca595Ae5F27Ec807B912A5b1D0f", + "AuctionManager": "0x7187372e1fF5CB8E8B84Ee02F25033fc42B3D033", + "AuctionManagerImpl": "0xaE4624b006D7730f22De1F7df5b1C0b960262AE3", + "DeliveryHelper": "0x8b4a6cee33f18D757d7F3613476b135E3B889303", + "DeliveryHelperImpl": "0xE693bEc40e39223749AC351156E713b7256541B0", + "ERC1967Factory": "0x122beAFCfc2E99D825322a78EAFD8a11fa2d9E0b", + "FeesManager": "0x7c0922C2AfaBF9098F55710E8D8E3c8F81bCB8ee", + "FeesManagerImpl": "0x2c50B6e519e0705A396E5c8652E5D447F37f9796", + "startBlock": 2491495, + "WatcherPrecompile": "0x6E4c1afEcc1AbFF69dF3bC6bFf81eF7A34a343d5", + "WatcherPrecompileConfig": "0x95f86089D4015e6874031B3583dE8795C3b217Fd", + "WatcherPrecompileConfigImpl": "0xE4a2eBcE3Bdcaa1861c01ddc6465b90311B749e4", + "WatcherPrecompileImpl": "0x233539d6BBf231660652AF00B5d6E850E892946a", + "WatcherPrecompileLimits": "0x34212a2Cf92D2863F35877Ed835B7e28b8287764", + "WatcherPrecompileLimitsImpl": "0xdfeA8cb793b84b3f046d2426259e0eC237Ec9bF3" + }, + "11155111": { + "ContractFactoryPlug": "0xdd7b56968a3505D1A10181F2880cAA65a89E4750", + "FastSwitchboard": "0xb34DB19C7FAeECf14B3D0336C6E34f7dc1336968", + "FeesPlug": "0xfBa932AaE9Ae2777aEC77832FC0C2D9059C8E905", + "Socket": "0xF86B89B5c689c170BfD2734254228D6d2db5a672", + "SocketBatcher": "0x466b51bcc1799A4cb8F629C46640ab3aA2608F75", + "startBlock": 23827730 }, "11155420": { - "ContractFactoryPlug": "0x289A0413420f812a7b05F931FB0726168121ae5a", - "FastSwitchboard": "0x59D9c8C5515cF9C8A9c83458E3D78C2a246E3e7C", - "FeesPlug": "0x285d1b2e93c1c74E141dC37f759B8aFAcD479b2b", - "Socket": "0xa347A8475d4d218b22e8b0cc90FF76B3e6c8043c", - "SocketBatcher": "0x4a7Ccf2845222172A8B7Fc6E132eDb64cCB4E4a4", - "startBlock": 24425961 + "ContractFactoryPlug": "0xDd73B7C6Bc8Cb4FFB3F0b460FF0985A91622f7E1", + "FastSwitchboard": "0x0CdaCA0B9F9bFfF1D9B660173BB8BE46c4fB71Da", + "FeesPlug": "0x95D672aaF036887aABEe72a6496D583317e6e48B", + "Socket": "0xDad99e0D8bA0ffe4955523ea0BCbe8F3DE3446D1", + "SocketBatcher": "0xb8D652C7D1dfA7578c6F119712c7b4c812BB3b57", + "startBlock": 25810565 } } diff --git a/deployments/dev_verification.json b/deployments/dev_verification.json index 4c11da30..cc9bb657 100644 --- a/deployments/dev_verification.json +++ b/deployments/dev_verification.json @@ -1,228 +1,162 @@ { "84532": [ [ - "0xA557EBE094F939ae6eE8F18c8F88D06182168786", + "0xFEFdbD9CB5bdC58Aa8B6B455923454275392838c", "ContractFactoryPlug", "contracts/protocol/payload-delivery/ContractFactoryPlug.sol", [ - "0x6c40Fb39B03e32EC4D23e31DdE6D10283F2C7b4F", + "0x89e66357C5F101C56b4F9F97cf378Cc32A21438a", "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0xD78f99D62BeaF0918bB0601C68EB537b6703Ce63", + "0xBBff19fBEAd971f39F1B298De985D7ADfb57b784", "FeesPlug", "contracts/protocol/payload-delivery/FeesPlug.sol", [ - "0x6c40Fb39B03e32EC4D23e31DdE6D10283F2C7b4F", + "0x89e66357C5F101C56b4F9F97cf378Cc32A21438a", "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0x06234dB2D69Ac158793a3ce59c3764422028E964", + "0xCc9f995DAE2D3Cf3C0763e353986E97ab78801b4", "FastSwitchboard", "contracts/protocol/socket/switchboard/FastSwitchboard.sol", [ 84532, - "0x6c40Fb39B03e32EC4D23e31DdE6D10283F2C7b4F", + "0x89e66357C5F101C56b4F9F97cf378Cc32A21438a", "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", + "0x3bABE35428D9E2B87d678289f837F805dAB0db3A", "SocketBatcher", "contracts/protocol/socket/SocketBatcher.sol", [ "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0x6c40Fb39B03e32EC4D23e31DdE6D10283F2C7b4F" + "0x89e66357C5F101C56b4F9F97cf378Cc32A21438a" ] ], [ - "0x6c40Fb39B03e32EC4D23e31DdE6D10283F2C7b4F", + "0x89e66357C5F101C56b4F9F97cf378Cc32A21438a", "Socket", "contracts/protocol/socket/Socket.sol", [84532, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ] ], - "421614": [ - [ - "0x29E632aE79107A82C637016CA21030d922De5375", - "FastSwitchboard", - "contracts/protocol/socket/switchboard/FastSwitchboard.sol", - [ - 421614, - "0xa0E1738a9Fc0698789866e09d7A335d30128C5C5", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ] - ], + "421614": [], "7625382": [ [ - "0xa07e38cAB46eAA358C3653C63219f1009e8F7789", - "AuctionManager", - "contracts/protocol/payload-delivery/AuctionManager.sol", - [] - ], - [ - "0x9F10A0c71178dbD4d049f2C04fD0e34966134b9e", - "DeliveryHelper", - "contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol", - [] - ], - [ - "0xB423eE3bffc3604F96B59cF419C48AE05b8E9d0b", + "0x2c50B6e519e0705A396E5c8652E5D447F37f9796", "FeesManager", "contracts/protocol/payload-delivery/FeesManager.sol", [] ], [ - "0x71956F006Ec5434581D3Fd5E7224BB3bae231907", + "0x233539d6BBf231660652AF00B5d6E850E892946a", "WatcherPrecompile", "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", [] ], [ - "0xbAeF84edEae864Ff22Bd9c9912AdfF84aD490d82", - "AddressResolver", - "contracts/protocol/AddressResolver.sol", - [] - ], - [ - "0x945e9ab4c08c225C10F178a0bd600BcC2bA7Cc78", - "ERC1967Factory", - "lib/solady/src/utils/ERC1967Factory.sol", - [] - ], - [ - "0x09B503e744DCB2cA2827ce5AF08Fd49Ba06D17e4", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] - ], - [ - "0x6c73961Bfaa2c9c1d0D7F4C213aa85af15b7CB54", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] - ], - [ - "0xd151bD217704F72f717C2111207e6Bb33B609f61", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] - ], - [ - "0x8dcEE196AFECe27545687426914d2830ff2dbc35", - "FeesManager", - "contracts/protocol/payload-delivery/app-gateway/FeesManager.sol", - [] - ], - [ - "0xb1F4CbFCE786aA8B553796Fb06c04Dd461967A16", + "0x4D0FA91403b4902B56Ad650aF2BA9D4fcA46aB0B", "WatcherPrecompile", "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", [] ], [ - "0x23EF7Af3bC1009EA6f95c3389921d5cB19950182", + "0xaE4624b006D7730f22De1F7df5b1C0b960262AE3", "AuctionManager", - "contracts/protocol/payload-delivery/app-gateway/AuctionManager.sol", + "contracts/protocol/payload-delivery/AuctionManager.sol", [] ], [ - "0x4CCF8F511A364827E5e6749b196BB26Ea00bF512", + "0xE693bEc40e39223749AC351156E713b7256541B0", "DeliveryHelper", "contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol", [] ], [ - "0x39f9b492695375F703450c5653c9D80CFa38e6eD", + "0xc2Ca571f4d4C2008Da4Bd750BaD3d50A5705ffF8", "FeesManager", - "contracts/protocol/payload-delivery/app-gateway/FeesManager.sol", + "contracts/protocol/payload-delivery/FeesManager.sol", [] ], [ - "0x234cA13f5dC4a2467c81E515F57238BF9f53156E", + "0x4894D35BF607BB47099172d42133ffe411a1d4B8", "WatcherPrecompile", "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", [] ], [ - "0xbBfb525ADc6eC38Ef0D4b807d327c2Dd1C286de1", - "AddressResolver", - "contracts/protocol/AddressResolver.sol", - [] - ], - [ - "0x208dC31cd6042a09bbFDdB31614A337a51b870ba", - "ERC1967Factory", - "lib/solady/src/utils/ERC1967Factory.sol", + "0xE4a2eBcE3Bdcaa1861c01ddc6465b90311B749e4", + "WatcherPrecompileConfig", + "contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol", [] ], [ - "0x4C68058509d754Cc0dE474eBC20aE94e4787E704", - "AuctionManager", - "contracts/protocol/payload-delivery/app-gateway/AuctionManager.sol", + "0xdfeA8cb793b84b3f046d2426259e0eC237Ec9bF3", + "WatcherPrecompileLimits", + "contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol", [] ], [ - "0x3c9f5172feb0dDfC06176cE67B566EFbb01CCe98", - "DeliveryHelper", - "contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol", - [] - ], - [ - "0xF4D3BDe438416938217d4624c82AEbEb46CeD371", - "FeesManager", - "contracts/protocol/payload-delivery/app-gateway/FeesManager.sol", - [] - ], - [ - "0x8F18fC10a8b40b548C6F04Fb252481c783A9ace0", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] - ], - [ - "0x8662FC08dEC7c61Dd3432fAF45a5bC024BB60B00", + "0x2736Fc0AA0fa5Ca595Ae5F27Ec807B912A5b1D0f", "AddressResolver", "contracts/protocol/AddressResolver.sol", [] ], [ - "0x234cA13f5dC4a2467c81E515F57238BF9f53156E", + "0x122beAFCfc2E99D825322a78EAFD8a11fa2d9E0b", "ERC1967Factory", "lib/solady/src/utils/ERC1967Factory.sol", [] ] ], - "11155111": [], - "11155420": [ + "11155111": [ [ - "0x245C0DCF8eF6e52b4d03c96b563C83a5f78A1E14", - "FastSwitchboard", - "contracts/protocol/socket/switchboard/FastSwitchboard.sol", + "0xdd7b56968a3505D1A10181F2880cAA65a89E4750", + "ContractFactoryPlug", + "contracts/protocol/payload-delivery/ContractFactoryPlug.sol", + [ + "0xF86B89B5c689c170BfD2734254228D6d2db5a672", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xfBa932AaE9Ae2777aEC77832FC0C2D9059C8E905", + "FeesPlug", + "contracts/protocol/payload-delivery/FeesPlug.sol", [ - 11155420, - "0x79Ac996De9333956f4980397ED5Bd91f77f10b01", + "0xF86B89B5c689c170BfD2734254228D6d2db5a672", "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0xBf9Ec2b0441eeEA9bEb89C6638921c37c15A13E4", + "0xb34DB19C7FAeECf14B3D0336C6E34f7dc1336968", "FastSwitchboard", "contracts/protocol/socket/switchboard/FastSwitchboard.sol", [ - 11155420, - "0x79Ac996De9333956f4980397ED5Bd91f77f10b01", + 11155111, + "0xF86B89B5c689c170BfD2734254228D6d2db5a672", "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0x79Ac996De9333956f4980397ED5Bd91f77f10b01", + "0x466b51bcc1799A4cb8F629C46640ab3aA2608F75", + "SocketBatcher", + "contracts/protocol/socket/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xF86B89B5c689c170BfD2734254228D6d2db5a672" + ] + ], + [ + "0xF86B89B5c689c170BfD2734254228D6d2db5a672", "Socket", "contracts/protocol/socket/Socket.sol", - [11155420, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + [11155111, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ] - ] + ], + "11155420": [] } diff --git a/deployments/stage_addresses.json b/deployments/stage_addresses.json index 103ae35c..61a298c8 100644 --- a/deployments/stage_addresses.json +++ b/deployments/stage_addresses.json @@ -1,48 +1,52 @@ { "43": { - "AddressResolver": "0xf3046B22F98C25305E8040286fB1b33378BA10a1", - "AddressResolverImpl": "0x208dC31cd6042a09bbFDdB31614A337a51b870ba", - "AuctionManager": "0x5d6d4DCb0F719F01441377F633F3EdD186e19360", - "AuctionManagerImpl": "0xF4D3BDe438416938217d4624c82AEbEb46CeD371", - "DeliveryHelper": "0x39bC71cC9AfeeA50B0638532e45b0462A5e62111", - "DeliveryHelperImpl": "0x8F18fC10a8b40b548C6F04Fb252481c783A9ace0", - "ERC1967Factory": "0x47116C0E101C4c1b5f21f0A57A86c0aa3F14D994", - "FeesManager": "0x603723100172D30171B7Fd9870ba80F8baf6FaD4", - "FeesManagerImpl": "0x8662FC08dEC7c61Dd3432fAF45a5bC024BB60B00", - "startBlock": 157, - "WatcherPrecompile": "0x4b5BcB38014cBdf852Ae6429871E0b1Ac0a05Df8", - "WatcherPrecompileImpl": "0x3cf47Ad0F040dFF1208E649C8f8e23e6B5A08916" + "AddressResolver": "0x4846430BB142385e581C894AE92a4CF0722aEC21", + "AddressResolverImpl": "0x0F13F50f7dED1da9A4845366C2AB5120a1A17549", + "AuctionManager": "0x222574Dab9bb404Cb49a9445CD4d9555e8B52Cf5", + "AuctionManagerImpl": "0xbe1b573aa1B6ddD1A7a27aE0Aa6A38FA5d26fc67", + "DeliveryHelper": "0x436Ea32C3198500d113B006dBdc6fF1Bebd10769", + "DeliveryHelperImpl": "0x40f7fdE05bFa9F7c9B55a582B0783352856BCd03", + "ERC1967Factory": "0xF362fdCAbbd1f58AAd998d4c7Aef4020365092C8", + "FeesManager": "0x9745623Aaa299500F93d2B1B4Efb7b3EC5e60FFc", + "FeesManagerImpl": "0x71956F006Ec5434581D3Fd5E7224BB3bae231907", + "startBlock": 2368668, + "WatcherPrecompile": "0xEbdA834fAc9ca4B86AdD442083c1650f8497EdCb", + "WatcherPrecompileConfig": "0x4D38091442c78B4cb2bB22AFF61552bc72d4BF8e", + "WatcherPrecompileConfigImpl": "0xDf9d7b339Db52Fc58f2c72ffAd3a87201FB16b30", + "WatcherPrecompileImpl": "0xbAeF84edEae864Ff22Bd9c9912AdfF84aD490d82", + "WatcherPrecompileLimits": "0x0CF9B01E7d1ef769D160F53289244f74197B4149", + "WatcherPrecompileLimitsImpl": "0x0bA474851A0703eC69964FB8264304AF357cd16D" }, "84532": { - "ContractFactoryPlug": "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", - "FastSwitchboard": "0xf0f51Ba62284A98AbB5D447487d5E6B536DB9B72", - "FeesPlug": "0xe3332D21b49d9347913cca2316FcC1b34fa16914", - "Socket": "0x6D54668ba18B425a1DbFC0BD720145c0aeE97f65", - "SocketBatcher": "0xC559BABEbcD92278E91a545308190E4761efc347", - "startBlock": 22449147 + "ContractFactoryPlug": "0x5AF9cA0Ce2Bc991FcE955f8c993fb0A5464B289F", + "FastSwitchboard": "0x0594497C89ECF66bC67204EE89770C4e799De3f9", + "FeesPlug": "0x0EBC6E395503eF135b7a45FfC7d42C2A2bc56D54", + "Socket": "0x92562Ae6526aB8B4fFF9Fa8ECAb6db67f0753693", + "SocketBatcher": "0xE4036898F51842E7DdFD36Dc8eAa7D4B207c5DEe", + "startBlock": 23664081 }, "421614": { - "ContractFactoryPlug": "0x78E3A5d21d0dB60bf0A585Cc2105043F919A404b", - "FastSwitchboard": "0x1448E643AbA68a0F1E4C5a3996bA2a355ce3EA8B", - "FeesPlug": "0x89324F93d852cB4fcDC4Ee202456be466ce096bb", - "Socket": "0xaFBD45A4D8378Bd2893F46d2f42e912F653B8777", - "SocketBatcher": "0x5966fc2e475Ddd0a098c3eCF1A3A1EF5036eCF7e", - "startBlock": 127843398 + "ContractFactoryPlug": "0x5F710Ac554DD22819F9411fa554265EEf827247d", + "FastSwitchboard": "0xBD0158415Eb99B5e1dBA1e4E534f916ba82380f9", + "FeesPlug": "0x9E263f6c7C199d9c147E30764A8cae1175184CB8", + "Socket": "0x22c1275677E600e2b049B69D929E2ccAAf4B880E", + "SocketBatcher": "0x92f85fe2CbB2D9ab577E4D167E629095497325b9", + "startBlock": 136470235 }, "11155111": { - "ContractFactoryPlug": "0xfaf8a3f8f4221398F3eC765836e8BF4A3d975962", - "FastSwitchboard": "0x0d7994B4aAc7cbdFAFEAED0B9B51E7de0586ec6f", - "FeesPlug": "0x7E33B305e12aD0E73B3aedBE67A53B7818732d7d", - "Socket": "0xe3332D21b49d9347913cca2316FcC1b34fa16914", - "SocketBatcher": "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", - "startBlock": 7797136 + "ContractFactoryPlug": "0xd36C1Dcb65CB09b7fCFABf153D7cdd42312C782E", + "FastSwitchboard": "0x36AC527afA283c95EA7dD11c8E93225d9F139028", + "FeesPlug": "0xc4008CCB59413cC2745d33549e5BE16A2d1DD061", + "Socket": "0x899AE7770eFb9714aF717d03c0d577e41d78ed48", + "SocketBatcher": "0xE90649F3BA488D91c7e8E3025F639F435Fa85243", + "startBlock": 23664095 }, "11155420": { - "ContractFactoryPlug": "0xaD2b8b14DaF98555A0BFC43e70E3AFD6C0743701", - "FastSwitchboard": "0x19618cB6C20b2512dFC5E207301Af0514B9533FD", - "FeesPlug": "0x09FfC007E730fbfEA6e09dC19396CddB7d329FC1", - "Socket": "0x89366513CA2eAc43B9E7a825D69BE8Fee495Ece5", - "SocketBatcher": "0xC8db322fD39D5c6F30Ca925C32a7986c4eA0c421", - "startBlock": 24431972 + "ContractFactoryPlug": "0x6320Ff773a4E01Cb8EB849EA906F17Cf6c48Ff9c", + "FastSwitchboard": "0xd94741a4654953817faEe228739a6d10C0683839", + "FeesPlug": "0x89634ecFea933aFaD5d3D6557b13cb8D466313d2", + "Socket": "0x2420B85D7e126d1948a4602f0c78a685655292Bd", + "SocketBatcher": "0xBD6770182fB47DD77924aDf3F200246Ab851f9c2", + "startBlock": 25646940 } } diff --git a/deployments/stage_verification.json b/deployments/stage_verification.json index 030eaa6b..61c8987d 100644 --- a/deployments/stage_verification.json +++ b/deployments/stage_verification.json @@ -1,73 +1,67 @@ { "43": [ [ - "0xF4D3BDe438416938217d4624c82AEbEb46CeD371", - "AuctionManager", - "contracts/protocol/payload-delivery/AuctionManager.sol", - [] - ], - [ - "0x8F18fC10a8b40b548C6F04Fb252481c783A9ace0", - "DeliveryHelper", - "contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol", - [] - ], - [ - "0x8662FC08dEC7c61Dd3432fAF45a5bC024BB60B00", + "0x71956F006Ec5434581D3Fd5E7224BB3bae231907", "FeesManager", "contracts/protocol/payload-delivery/FeesManager.sol", [] ], [ - "0x3cf47Ad0F040dFF1208E649C8f8e23e6B5A08916", + "0xbAeF84edEae864Ff22Bd9c9912AdfF84aD490d82", "WatcherPrecompile", "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", [] ], [ - "0x208dC31cd6042a09bbFDdB31614A337a51b870ba", - "AddressResolver", - "contracts/protocol/AddressResolver.sol", - [] - ], - [ - "0x47116C0E101C4c1b5f21f0A57A86c0aa3F14D994", - "ERC1967Factory", - "lib/solady/src/utils/ERC1967Factory.sol", + "0x02Bd15aa48BAE9A92E23a3F30Be0c1bD253970Cf", + "WatcherPrecompile", + "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", [] ], [ - "0x12103e799d8887034d4560A960C2410ceE751004", + "0xbe1b573aa1B6ddD1A7a27aE0Aa6A38FA5d26fc67", "AuctionManager", "contracts/protocol/payload-delivery/AuctionManager.sol", [] ], [ - "0xB08306a7D8733CB027dD679AdbfdF64cD52670eb", + "0x40f7fdE05bFa9F7c9B55a582B0783352856BCd03", "DeliveryHelper", "contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol", [] ], [ - "0xE3A4c7Fb21196425C635B2b12e90F010BCD12Fec", + "0xd151bD217704F72f717C2111207e6Bb33B609f61", "FeesManager", "contracts/protocol/payload-delivery/FeesManager.sol", [] ], [ - "0x279284d399cFB4cF91f2ebe461f43C6DF020148f", + "0x2916aC09Be088427E1a25968DA332F1F1eFa62d2", "WatcherPrecompile", "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", [] ], [ - "0x82c52D85543029C618B1F0E2fA5f194D2c4DfA2A", + "0xDf9d7b339Db52Fc58f2c72ffAd3a87201FB16b30", + "WatcherPrecompileConfig", + "contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol", + [] + ], + [ + "0x0bA474851A0703eC69964FB8264304AF357cd16D", + "WatcherPrecompileLimits", + "contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol", + [] + ], + [ + "0x0F13F50f7dED1da9A4845366C2AB5120a1A17549", "AddressResolver", "contracts/protocol/AddressResolver.sol", [] ], [ - "0xC3a6C7Ae16831b86C084CeC8192A14b6c3b53649", + "0xF362fdCAbbd1f58AAd998d4c7Aef4020365092C8", "ERC1967Factory", "lib/solady/src/utils/ERC1967Factory.sol", [] @@ -75,92 +69,94 @@ ], "84532": [ [ - "0x693bcDb114a57302Cd687b8Af1bD7583ee56748C", + "0x5AF9cA0Ce2Bc991FcE955f8c993fb0A5464B289F", "ContractFactoryPlug", "contracts/protocol/payload-delivery/ContractFactoryPlug.sol", [ - "0x6D54668ba18B425a1DbFC0BD720145c0aeE97f65", + "0x92562Ae6526aB8B4fFF9Fa8ECAb6db67f0753693", "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0xe3332D21b49d9347913cca2316FcC1b34fa16914", + "0x0EBC6E395503eF135b7a45FfC7d42C2A2bc56D54", "FeesPlug", "contracts/protocol/payload-delivery/FeesPlug.sol", [ - "0x6D54668ba18B425a1DbFC0BD720145c0aeE97f65", + "0x92562Ae6526aB8B4fFF9Fa8ECAb6db67f0753693", "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0xf0f51Ba62284A98AbB5D447487d5E6B536DB9B72", + "0x0594497C89ECF66bC67204EE89770C4e799De3f9", "FastSwitchboard", "contracts/protocol/socket/switchboard/FastSwitchboard.sol", [ 84532, - "0x6D54668ba18B425a1DbFC0BD720145c0aeE97f65", + "0x92562Ae6526aB8B4fFF9Fa8ECAb6db67f0753693", "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0xC559BABEbcD92278E91a545308190E4761efc347", + "0xE4036898F51842E7DdFD36Dc8eAa7D4B207c5DEe", "SocketBatcher", "contracts/protocol/socket/SocketBatcher.sol", [ "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0x6D54668ba18B425a1DbFC0BD720145c0aeE97f65" + "0x92562Ae6526aB8B4fFF9Fa8ECAb6db67f0753693" ] ], [ - "0x6D54668ba18B425a1DbFC0BD720145c0aeE97f65", + "0x92562Ae6526aB8B4fFF9Fa8ECAb6db67f0753693", "Socket", "contracts/protocol/socket/Socket.sol", - [ - 84532, - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "EVMX" - ] + [84532, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ] ], "421614": [], - "7625382": [ + "11155111": [ [ - "0xF4D3BDe438416938217d4624c82AEbEb46CeD371", - "AuctionManager", - "contracts/protocol/payload-delivery/AuctionManager.sol", - [] - ], - [ - "0x8F18fC10a8b40b548C6F04Fb252481c783A9ace0", - "DeliveryHelper", - "contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol", - [] + "0xd36C1Dcb65CB09b7fCFABf153D7cdd42312C782E", + "ContractFactoryPlug", + "contracts/protocol/payload-delivery/ContractFactoryPlug.sol", + [ + "0x899AE7770eFb9714aF717d03c0d577e41d78ed48", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x8662FC08dEC7c61Dd3432fAF45a5bC024BB60B00", - "FeesManager", - "contracts/protocol/payload-delivery/FeesManager.sol", - [] + "0xc4008CCB59413cC2745d33549e5BE16A2d1DD061", + "FeesPlug", + "contracts/protocol/payload-delivery/FeesPlug.sol", + [ + "0x899AE7770eFb9714aF717d03c0d577e41d78ed48", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x3cf47Ad0F040dFF1208E649C8f8e23e6B5A08916", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] + "0x36AC527afA283c95EA7dD11c8E93225d9F139028", + "FastSwitchboard", + "contracts/protocol/socket/switchboard/FastSwitchboard.sol", + [ + 11155111, + "0x899AE7770eFb9714aF717d03c0d577e41d78ed48", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] ], [ - "0x208dC31cd6042a09bbFDdB31614A337a51b870ba", - "AddressResolver", - "contracts/protocol/AddressResolver.sol", - [] + "0xE90649F3BA488D91c7e8E3025F639F435Fa85243", + "SocketBatcher", + "contracts/protocol/socket/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x899AE7770eFb9714aF717d03c0d577e41d78ed48" + ] ], [ - "0x47116C0E101C4c1b5f21f0A57A86c0aa3F14D994", - "ERC1967Factory", - "lib/solady/src/utils/ERC1967Factory.sol", - [] + "0x899AE7770eFb9714aF717d03c0d577e41d78ed48", + "Socket", + "contracts/protocol/socket/Socket.sol", + [11155111, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ] ], - "11155111": [], "11155420": [] } diff --git a/foundry.toml b/foundry.toml index 6af74ab3..6c926318 100644 --- a/foundry.toml +++ b/foundry.toml @@ -2,8 +2,9 @@ solc_version = "0.8.22" src = "contracts" out = "out" -libs = ["node_modules", "lib"] +libs = ["lib"] ffi = true optimizer = true optimizer_runs = 200 -evm_version = 'paris' \ No newline at end of file +evm_version = 'paris' +via_ir = false diff --git a/hardhat-scripts/addChain/index.ts b/hardhat-scripts/addChain/index.ts new file mode 100644 index 00000000..0e771571 --- /dev/null +++ b/hardhat-scripts/addChain/index.ts @@ -0,0 +1,41 @@ +import prompts from "prompts"; + +import { addChainToSDK } from "./writeConfigs"; + +async function main() { + const response = await prompts([ + { + name: "option", + type: "select", + message: "What would you like to do?", + choices: [ + { + title: "Add chain configs", + value: "add", + }, + { + title: "Exit", + value: "exit", + }, + ], + }, + ]); + + switch (response.option) { + case "add": + await addChainToSDK(); + break; + case "exit": + process.exit(0); + } +} + +async function start() { + while (true) { + await main(); + } +} + +(async () => { + start(); +})(); diff --git a/hardhat-scripts/addChain/utils.ts b/hardhat-scripts/addChain/utils.ts new file mode 100644 index 00000000..0a7d2c3d --- /dev/null +++ b/hardhat-scripts/addChain/utils.ts @@ -0,0 +1,151 @@ +import fs from "fs"; +import path from "path"; + +import { ChainId, ChainType, NativeTokens } from "../../src"; + +const enumFolderPath = path.join( + __dirname, + `/../../src/constants/chain-enums/` +); + +export const updateSDK = async ( + chainName: string, + chainId: number, + nativeToken: string, + chainType: number, + isMainnet: boolean, + isNewNative: boolean +) => { + if (!fs.existsSync(enumFolderPath)) { + throw new Error(`Folder not found! ${enumFolderPath}`); + } + + const filteredChain = Object.values(ChainId).filter((c) => c == chainId); + if (filteredChain.length > 0) { + console.log("Chain already added!"); + return; + } + + await updateFile( + "hardhatChainName.ts", + `,\n ${chainName.toUpperCase()} = "${chainName.toLowerCase()}",\n}\n`, + ",\n}" + ); + await updateFile( + "chainId.ts", + `,\n ${chainName.toUpperCase()} = ${chainId},\n}\n`, + ",\n}" + ); + await updateFile( + "chainSlug.ts", + `,\n ${chainName.toUpperCase()} = ChainId.${chainName.toUpperCase()},\n}\n`, + ",\n}" + ); + await updateFile( + "chainSlugToKey.ts", + `,\n [ChainSlug.${chainName.toUpperCase()}]: HardhatChainName.${chainName.toUpperCase()},\n};\n`, + ",\n};" + ); + await updateFile( + "chainSlugToId.ts", + `,\n [ChainSlug.${chainName.toUpperCase()}]: ChainId.${chainName.toUpperCase()},\n};\n`, + ",\n};" + ); + await updateFile( + "hardhatChainNameToSlug.ts", + `,\n [HardhatChainName.${chainName.toUpperCase()}]: ChainSlug.${chainName.toUpperCase()},\n};\n`, + ",\n};" + ); + await updateFile( + "chainSlugToHardhatChainName.ts", + `,\n [ChainSlug.${chainName.toUpperCase()}]: HardhatChainName.${chainName.toUpperCase()},\n};\n`, + ",\n};" + ); + + if (isNewNative) { + await updateFile( + "native-tokens.ts", + `,\n "${nativeToken.toLowerCase()}" = "${nativeToken.toLowerCase()}",\n}\n`, + ",\n}" + ); + } + + if (nativeToken !== NativeTokens.ethereum) { + await updateFile( + "currency.ts", + `,\n [ChainSlug.${chainName.toUpperCase()}]: NativeTokens["${nativeToken}"],\n};\n`, + ",\n};" + ); + } + + const chainTypeInString = Object.keys(ChainType)[chainType]; + if (chainTypeInString === ChainType.arbChain) { + await updateFile( + "arbChains.ts", + `,\n ChainSlug.${chainName.toUpperCase()},\n];`, + ",\n];" + ); + } else if (chainTypeInString === ChainType.arbL3Chain) { + await updateFile( + "arbL3Chains.ts", + `,\n ChainSlug.${chainName.toUpperCase()},\n];`, + ",\n];" + ); + } else if (chainTypeInString === ChainType.opStackL2Chain) { + await updateFile( + "opStackChains.ts", + `,\n ChainSlug.${chainName.toUpperCase()},\n];`, + ",\n];" + ); + } else if (chainTypeInString === ChainType.polygonCDKChain) { + await updateFile( + "polygonCDKChains.ts", + `,\n ChainSlug.${chainName.toUpperCase()},\n];`, + ",\n];" + ); + } else if (chainTypeInString === ChainType.zkStackChain) { + await updateFile( + "zkStackChain.ts", + `,\n ChainSlug.${chainName.toUpperCase()},\n];`, + ",\n];" + ); + } else { + await updateFile( + "ethLikeChains.ts", + `,\n ChainSlug.${chainName.toUpperCase()},\n];`, + ",\n];" + ); + } + + if (isMainnet) { + await updateFile( + "mainnetIds.ts", + `,\n ChainSlug.${chainName.toUpperCase()},\n];\n`, + ",\n];" + ); + } else + await updateFile( + "testnetIds.ts", + `,\n ChainSlug.${chainName.toUpperCase()},\n];\n`, + ",\n];" + ); +}; + +const updateFile = async ( + fileName: string, + newChainDetails: string, + replaceWith: string +) => { + const filePath = enumFolderPath + fileName; + const outputExists = fs.existsSync(filePath); + if (!outputExists) throw new Error(`${fileName} enum not found! ${filePath}`); + + const verificationDetailsString = fs.readFileSync(filePath, "utf-8"); + + // replace last bracket with new line + const verificationDetails = verificationDetailsString + .trimEnd() + .replace(replaceWith, newChainDetails); + + fs.writeFileSync(filePath, verificationDetails); +}; diff --git a/hardhat-scripts/addChain/writeConfigs.ts b/hardhat-scripts/addChain/writeConfigs.ts new file mode 100644 index 00000000..bb9f6549 --- /dev/null +++ b/hardhat-scripts/addChain/writeConfigs.ts @@ -0,0 +1,118 @@ +import { StaticJsonRpcProvider } from "@ethersproject/providers"; +import { utils } from "ethers"; +import prompts from "prompts"; + +import { ChainId, ChainType, NativeTokens } from "../../src"; +import { updateSDK } from "./utils"; + +export async function addChainToSDK() { + const currencyChoices = [...Object.keys(NativeTokens), "other"]; + + const rpcResponse = await prompts([ + { + name: "rpc", + type: "text", + message: "Enter rpc url", + validate: validateRpc, + }, + { + name: "chainName", + type: "text", + message: + "Enter chain name (without spaces, use underscore instead of spaces)", + }, + ]); + + const chainId = await getChainId(rpcResponse.rpc); + + const filteredChain = Object.values(ChainId).filter((c) => c == chainId); + if (filteredChain.length > 0) { + console.log("Chain already added!"); + return { + response: { rpc: rpcResponse.rpc, chainName: rpcResponse.chainName }, + chainId, + isAlreadyAdded: true, + }; + } + + const response = await prompts([ + { + name: "isMainnet", + type: "toggle", + message: "Is it a mainnet?", + }, + { + name: "chainType", + type: "select", + message: "Select the rollup type (select default if not)", + choices: [...Object.keys(ChainType)].map((type) => ({ + title: type, + value: type, + })), + }, + { + name: "currency", + type: "select", + message: "Select the native token", + choices: currencyChoices.map((choice) => ({ + title: choice, + value: choice, + })), + }, + ]); + + let isNewNative = false; + let currency = currencyChoices[response.currency]; + if (response.currency == currencyChoices.length - 1) { + const currencyPromptResponse = await prompts([ + { + name: "coingeckoId", + type: "text", + message: "Enter coingecko id of your token", + validate: validateCoingeckoId, + }, + ]); + + isNewNative = true; + currency = currencyPromptResponse.coingeckoId; + } + + // update types and enums + await updateSDK( + rpcResponse.chainName, + chainId, + currency, + response.chainType, + response.isMainnet, + isNewNative + ); + + return { response, chainId, isAlreadyAdded: false }; +} + +const validateCoingeckoId = async (coingeckoId: string) => { + if (!coingeckoId) { + return "Invalid coingecko Id"; + } + return true; +}; + +const validateRpc = async (rpcUrl: string) => { + if (!rpcUrl) { + return "Invalid RPC"; + } + return getChainId(rpcUrl) + .then((a) => true) + .catch((e) => `Invalid RPC: ${e}`); +}; + +const validateAddress = (address: string) => { + if (!address || address.length === 0) return true; + return utils.isAddress(address); +}; + +const getChainId = async (rpcUrl: string) => { + const provider = new StaticJsonRpcProvider(rpcUrl); + const network = await provider.getNetwork(); + return network.chainId; +}; diff --git a/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index 6cea0d30..d7236e79 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -1,7 +1,7 @@ import { config as dotenvConfig } from "dotenv"; dotenvConfig(); import { ethers } from "ethers"; -import { ChainSlug, DeploymentMode } from "@socket.tech/socket-protocol-common"; +import { ChainSlug, DeploymentMode } from "../../src"; export const mode = process.env.DEPLOYMENT_MODE as | DeploymentMode @@ -26,20 +26,22 @@ export const logConfig = () => { export const chains: Array = [ ChainSlug.ARBITRUM_SEPOLIA, ChainSlug.OPTIMISM_SEPOLIA, - // ChainSlug.SEPOLIA, ChainSlug.BASE_SEPOLIA, + ChainSlug.SEPOLIA, ]; export const EVM_CHAIN_ID_MAP: Record = { [DeploymentMode.LOCAL]: 7625382, [DeploymentMode.DEV]: 7625382, [DeploymentMode.STAGE]: 43, [DeploymentMode.PROD]: 3605, -} +}; export const auctionEndDelaySeconds = 0; export const watcher = "0xb62505feacC486e809392c65614Ce4d7b051923b"; +export const transmitter = "0x138e9840861C983DC0BB9b3e941FB7C0e9Ade320"; export const MAX_FEES = ethers.utils.parseEther("0.001"); export const EVMX_CHAIN_ID = EVM_CHAIN_ID_MAP[mode]; -export const MAX_LIMIT = 100; +export const DEFAULT_MAX_LIMIT = 100; export const BID_TIMEOUT = 600; export const EXPIRY_TIME = 300; export const UPGRADE_VERSION = 1; +export const MAX_RE_AUCTION_COUNT = 5; diff --git a/hardhat-scripts/constants/constants.ts b/hardhat-scripts/constants/constants.ts index 1ae8e8f5..bd93d8d3 100644 --- a/hardhat-scripts/constants/constants.ts +++ b/hardhat-scripts/constants/constants.ts @@ -1 +1,8 @@ +import { keccak256, id } from "ethers/lib/utils"; + export const ETH_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; + +export const IMPLEMENTATION_SLOT = + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; + +export const FAST_SWITCHBOARD_TYPE = id("FAST"); diff --git a/hardhat-scripts/constants/enums.ts b/hardhat-scripts/constants/enums.ts index 371023e1..d7707602 100644 --- a/hardhat-scripts/constants/enums.ts +++ b/hardhat-scripts/constants/enums.ts @@ -8,6 +8,8 @@ export enum CORE_CONTRACTS { export enum EVMxCoreContracts { WatcherPrecompile = "WatcherPrecompile", + WatcherPrecompileLimits = "WatcherPrecompileLimits", + WatcherPrecompileConfig = "WatcherPrecompileConfig", AuctionManager = "AuctionManager", FeesManager = "FeesManager", DeliveryHelper = "DeliveryHelper", diff --git a/hardhat-scripts/constants/relayers.ts b/hardhat-scripts/constants/relayers.ts deleted file mode 100644 index 589291d9..00000000 --- a/hardhat-scripts/constants/relayers.ts +++ /dev/null @@ -1,22 +0,0 @@ -export const relayerAddressList = [ - "0x59D24CD3A0b2b646F980A62DCb0aA4115506FFc9", - "0x762783712FD12231601d6d8591F3a5718812D534", - "0x9f5C9941306E7B57583E99033BedB7eA7889EEA4", - "0xd35F262d6f2D3F6D610bAf6635dE57c349ca83A1", - "0xce6b9c352f864515d7E8BBEA67d80d18245937F2", - "0xE651eDb3F16D9e6b1145ae5eee388f0e48D2d44b", - "0xc176E88dE45747743699fAeA58814Ce98a2faC2D", - "0x88220692264EEc280Bd5AaF9278CdE0737Feb2D6", - "0x2d68551354226c7321130f122055F049F8F67791", - "0xA7C89619ceaC009a23c6C3bC5F74d41BBaC68fD1", - "0x7893D79718860DF30e5Fd21AAA6Be05edD22465D", - "0x6386c83e994331c6a41A4420294D130930AEDF9e", - "0xfF33A0afc88CbF48C9DB31Fc2D2EC2F36D598184", - "0xB756B6D986eE448433542A60A1f590EE3B0DFCda", - "0x76943F947D5622624444aeFF135a5121d6732299", - "0x049B750045fdE15F347aF9E86FB80dD879C848ea", - "0x9c653569C32473F40210495128BB5A40ef10c65B", - "0x0291a40beF28E3606b8208a665F900d141E9A8B3", - "0x2e498dFB44CC79D2ef80Afd7C4439BEC8822E216", - "0x049E701A690E885467E54A1B0595f90BDc8324B0", -]; diff --git a/hardhat-scripts/constants/roles.ts b/hardhat-scripts/constants/roles.ts index 5faeb8c1..99ff3d91 100644 --- a/hardhat-scripts/constants/roles.ts +++ b/hardhat-scripts/constants/roles.ts @@ -3,4 +3,5 @@ export enum ROLES { WITHDRAW_ROLE = "WITHDRAW_ROLE", GOVERNANCE_ROLE = "GOVERNANCE_ROLE", WATCHER_ROLE = "WATCHER_ROLE", + TRANSMITTER_ROLE = "TRANSMITTER_ROLE", } diff --git a/hardhat-scripts/constants/types.ts b/hardhat-scripts/constants/types.ts index 97603b2c..0cd19bef 100644 --- a/hardhat-scripts/constants/types.ts +++ b/hardhat-scripts/constants/types.ts @@ -1,7 +1,4 @@ -import { - ChainAddressesObj, - ChainSlug, -} from "@socket.tech/socket-protocol-common"; +import { ChainAddressesObj, ChainSlug } from "../../src"; export type DeploymentAddresses = { [chainSlug in ChainSlug]?: ChainAddressesObj; diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index 645e82f7..bc3c6715 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -1,31 +1,33 @@ -import { - ChainAddressesObj, - ChainSlug -} from "@socket.tech/socket-protocol-common"; +import { ChainAddressesObj, ChainSlug } from "../../src"; import { config } from "dotenv"; -import { Contract, Signer, Wallet, providers } from "ethers"; +import { Contract, Signer, utils, Wallet } from "ethers"; import { formatEther } from "ethers/lib/utils"; import { ethers } from "hardhat"; -import { BID_TIMEOUT, EVMX_CHAIN_ID, EXPIRY_TIME, MAX_LIMIT } from "../config"; -import { - auctionEndDelaySeconds, - chains, - logConfig, - mode, -} from "../config/config"; import { CORE_CONTRACTS, DeploymentAddresses, EVMxCoreContracts, + FAST_SWITCHBOARD_TYPE, + IMPLEMENTATION_SLOT, } from "../constants"; -import { getImplementationAddress } from "../migration/migrate-proxies"; import { DeployParams, getAddresses, getOrDeploy, - getProviderFromChainSlug, storeAddresses, } from "../utils"; +import { getSocketSigner, getWatcherSigner } from "../utils/sign"; +import { + auctionEndDelaySeconds, + BID_TIMEOUT, + chains, + EVMX_CHAIN_ID, + EXPIRY_TIME, + logConfig, + DEFAULT_MAX_LIMIT, + MAX_RE_AUCTION_COUNT, + mode, +} from "../config/config"; config(); let EVMxOwner: string; @@ -38,27 +40,35 @@ const main = async () => { }; const logBalances = async () => { - const evmxDeployer = new ethers.Wallet(process.env.WATCHER_PRIVATE_KEY as string); - const socketDeployer = new ethers.Wallet(process.env.SOCKET_SIGNER_KEY as string); - let provider = getProviderFromChainSlug(EVMX_CHAIN_ID as ChainSlug); - const evmxBalance = await provider.getBalance(evmxDeployer.address); - console.log(`EVMx Deployer ${evmxDeployer.address} balance on ${EVMX_CHAIN_ID}:`, formatEther(evmxBalance)); - await Promise.all(chains.map(async (chain) => { - const provider = getProviderFromChainSlug(chain); - const socketBalance = await provider.getBalance(socketDeployer.address); - console.log(`Socket Deployer ${socketDeployer.address} balance on ${chain}:`, formatEther(socketBalance)); - })); + 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( + chains.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 deployEVMxContracts = async () => { try { let addresses: DeploymentAddresses; let deployUtils: DeployParams = { addresses: {} as ChainAddressesObj, mode, - signer: new ethers.Wallet(process.env.WATCHER_PRIVATE_KEY as string), + signer: await getWatcherSigner(), currentChainSlug: EVMX_CHAIN_ID as ChainSlug, }; const chain = EVMX_CHAIN_ID; @@ -69,13 +79,7 @@ const deployEVMxContracts = async () => { ? (addresses[chain] as ChainAddressesObj) : ({} as ChainAddressesObj); - const providerInstance = new providers.StaticJsonRpcProvider( - process.env.EVMX_RPC as string - ); - const signer: Wallet = new ethers.Wallet( - process.env.WATCHER_PRIVATE_KEY as string, - providerInstance - ); + const signer: Wallet = getWatcherSigner(); EVMxOwner = signer.address; deployUtils = { @@ -109,15 +113,32 @@ const deployEVMxContracts = async () => { deployUtils.addresses[EVMxCoreContracts.AddressResolver] ); + deployUtils = await deployContractWithProxy( + EVMxCoreContracts.WatcherPrecompileLimits, + `contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol`, + [EVMxOwner, addressResolver.address, DEFAULT_MAX_LIMIT], + proxyFactory, + deployUtils + ); + + deployUtils = await deployContractWithProxy( + EVMxCoreContracts.WatcherPrecompileConfig, + `contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol`, + [EVMxOwner, addressResolver.address, EVMX_CHAIN_ID], + proxyFactory, + deployUtils + ); + deployUtils = await deployContractWithProxy( EVMxCoreContracts.WatcherPrecompile, `contracts/protocol/watcherPrecompile/WatcherPrecompile.sol`, [ EVMxOwner, addressResolver.address, - MAX_LIMIT, EXPIRY_TIME, EVMX_CHAIN_ID, + deployUtils.addresses[EVMxCoreContracts.WatcherPrecompileLimits], + deployUtils.addresses[EVMxCoreContracts.WatcherPrecompileConfig], ], proxyFactory, deployUtils @@ -126,7 +147,12 @@ const deployEVMxContracts = async () => { deployUtils = await deployContractWithProxy( EVMxCoreContracts.FeesManager, `contracts/protocol/payload-delivery/FeesManager.sol`, - [addressResolver.address, EVMxOwner, EVMX_CHAIN_ID], + [ + addressResolver.address, + EVMxOwner, + EVMX_CHAIN_ID, + FAST_SWITCHBOARD_TYPE, + ], proxyFactory, deployUtils ); @@ -151,6 +177,7 @@ const deployEVMxContracts = async () => { auctionEndDelaySeconds, addressResolver.address, EVMxOwner, + MAX_RE_AUCTION_COUNT, ], proxyFactory, deployUtils @@ -209,7 +236,7 @@ const deploySocketContracts = async () => { let deployUtils: DeployParams = { addresses: {} as ChainAddressesObj, mode, - signer: new ethers.Wallet(process.env.SOCKET_SIGNER_KEY as string), + signer: getSocketSigner(EVMX_CHAIN_ID as ChainSlug), currentChainSlug: EVMX_CHAIN_ID as ChainSlug, }; console.log("Deploying Socket contracts"); @@ -221,11 +248,7 @@ const deploySocketContracts = async () => { ? (addresses[chain] as ChainAddressesObj) : ({} as ChainAddressesObj); - const providerInstance = getProviderFromChainSlug(chain); - const signer: Wallet = new ethers.Wallet( - process.env.SOCKET_SIGNER_KEY as string, - providerInstance - ); + const signer: Wallet = getSocketSigner(chain as ChainSlug); const socketOwner = signer.address; deployUtils = { @@ -418,6 +441,22 @@ const deployContractWithProxy = async ( return deployUtils; }; +export async function getImplementationAddress( + proxyAddress: string +): Promise { + const customProvider = new ethers.providers.JsonRpcProvider( + process.env.EVMX_RPC as string + ); + + // Fallback to standard storage slot for other proxy types + const implHex = await customProvider.getStorageAt( + proxyAddress, + IMPLEMENTATION_SLOT + ); + + return utils.getAddress("0x" + implHex.slice(-40)); +} + main() .then(() => process.exit(0)) .catch((error: Error) => { diff --git a/hardhat-scripts/deploy/2.roles.ts b/hardhat-scripts/deploy/2.roles.ts index 8aa12732..ae578b73 100644 --- a/hardhat-scripts/deploy/2.roles.ts +++ b/hardhat-scripts/deploy/2.roles.ts @@ -2,8 +2,7 @@ import { config as dotenvConfig } from "dotenv"; dotenvConfig(); import { Wallet } from "ethers"; -import { ethers } from "hardhat"; -import { chains, EVMX_CHAIN_ID, mode, watcher } from "../config"; +import { chains, EVMX_CHAIN_ID, mode, watcher, transmitter } from "../config"; import { CORE_CONTRACTS, DeploymentAddresses, @@ -16,10 +15,9 @@ import { getRoleHash, overrides, } from "../utils"; -import { relayerAddressList } from "../constants/relayers"; -import { ChainAddressesObj } from "@socket.tech/socket-protocol-common"; +import { ChainAddressesObj, ChainSlug } from "../../src"; import { ROLES } from "../constants/roles"; - +import { getWatcherSigner, getSocketSigner } from "../utils/sign"; export const REQUIRED_ROLES = { FastSwitchboard: [ROLES.WATCHER_ROLE, ROLES.RESCUE_ROLE], Socket: [ROLES.GOVERNANCE_ROLE, ROLES.RESCUE_ROLE], @@ -63,13 +61,9 @@ async function setRoleForContract( } async function getSigner(chain: number, isWatcher: boolean = false) { - const providerInstance = getProviderFromChainSlug(chain); - const signer: Wallet = new ethers.Wallet( - isWatcher - ? (process.env.WATCHER_PRIVATE_KEY as string) - : (process.env.SOCKET_SIGNER_KEY as string), - providerInstance - ); + const signer: Wallet = isWatcher + ? getWatcherSigner() + : getSocketSigner(chain as ChainSlug); return signer; } @@ -113,17 +107,14 @@ async function setRolesForEVMx(addresses: DeploymentAddresses) { const contractAddress = chainAddresses[EVMxCoreContracts.WatcherPrecompile]; if (!contractAddress) return; - for (const relayerAddress of [...relayerAddressList, signer.address]) { - console.log(`setting WATCHER_ROLE for ${relayerAddress} on EVMX`); - await setRoleForContract( - EVMxCoreContracts.WatcherPrecompile, - contractAddress, - relayerAddress, - ROLES.WATCHER_ROLE, - signer, - EVMX_CHAIN_ID - ); - } + await setRoleForContract( + EVMxCoreContracts.AuctionManager, + chainAddresses[EVMxCoreContracts.AuctionManager], + transmitter, + ROLES.TRANSMITTER_ROLE, + signer, + EVMX_CHAIN_ID + ); } export const main = async () => { @@ -134,6 +125,7 @@ export const main = async () => { for (const chain of chains) { await setRolesForOnChain(chain, addresses); } + await setRolesForEVMx(addresses); } catch (error) { console.log("Error:", error); } diff --git a/hardhat-scripts/deploy/3.upgradeManagers.ts b/hardhat-scripts/deploy/3.upgradeManagers.ts index eaf3592f..2c3a261c 100644 --- a/hardhat-scripts/deploy/3.upgradeManagers.ts +++ b/hardhat-scripts/deploy/3.upgradeManagers.ts @@ -1,24 +1,21 @@ -import { - ChainSlug, - ChainAddressesObj, - DeploymentMode, -} from "@socket.tech/socket-protocol-common"; +import { ChainAddressesObj, ChainSlug, EVMxAddressesObj } from "../../src"; import { config as dotenvConfig } from "dotenv"; dotenvConfig(); import { Wallet } from "ethers"; -import { ethers } from "hardhat"; import { chains, EVMX_CHAIN_ID, mode } from "../config"; import { CORE_CONTRACTS, DeploymentAddresses, EVMxCoreContracts, + FAST_SWITCHBOARD_TYPE, } from "../constants"; import { getAddresses, getInstance, - getProviderFromChainSlug, + getSocketSigner, + getWatcherSigner, storeAddresses, } from "../utils"; @@ -33,11 +30,7 @@ export const main = async () => { ? (addresses[chain] as ChainAddressesObj) : ({} as ChainAddressesObj); - const providerInstance = getProviderFromChainSlug(chain); - const signer: Wallet = new ethers.Wallet( - process.env.SOCKET_SIGNER_KEY as string, - providerInstance - ); + const signer: Wallet = getSocketSigner(chain as ChainSlug); const socketContract = ( await getInstance( @@ -61,49 +54,43 @@ export const main = async () => { } }; -async function setOnchainContracts(chain, addresses) { - const providerInstance = getProviderFromChainSlug(EVMX_CHAIN_ID as ChainSlug); - const signer: Wallet = new ethers.Wallet( - process.env.WATCHER_PRIVATE_KEY as string, - providerInstance - ); - const EVMxAddresses = addresses[EVMX_CHAIN_ID]!; - const watcherPrecompile = ( +async function setOnchainContracts(chain: number, addresses) { + const signer: Wallet = getWatcherSigner(); + const EVMxAddresses = addresses[EVMX_CHAIN_ID] as EVMxAddressesObj; + const chainAddresses = addresses[chain] as ChainAddressesObj; + const watcherPrecompileConfig = ( await getInstance( - EVMxCoreContracts.WatcherPrecompile, - EVMxAddresses[EVMxCoreContracts.WatcherPrecompile] + EVMxCoreContracts.WatcherPrecompileConfig, + EVMxAddresses[EVMxCoreContracts.WatcherPrecompileConfig] ) ).connect(signer); - const fastSBtype = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("FAST")); - const sbAddress = addresses[chain][CORE_CONTRACTS.FastSwitchboard]; - const socketAddress = addresses[chain][CORE_CONTRACTS.Socket]; + const sbAddress = chainAddresses[CORE_CONTRACTS.FastSwitchboard]; + const socketAddress = chainAddresses[CORE_CONTRACTS.Socket]; const contractFactoryPlugAddress = - addresses[chain][CORE_CONTRACTS.ContractFactoryPlug]; - const feesPlugAddress = addresses[chain][CORE_CONTRACTS.FeesPlug]; + chainAddresses[CORE_CONTRACTS.ContractFactoryPlug]; + const feesPlugAddress = chainAddresses[CORE_CONTRACTS.FeesPlug]; - const currentSbAddress = await watcherPrecompile.switchboards( + const currentSbAddress = await watcherPrecompileConfig.switchboards( chain, - fastSBtype + FAST_SWITCHBOARD_TYPE ); - const currentSocket = await watcherPrecompile.sockets(chain); + const currentSocket = await watcherPrecompileConfig.sockets(chain); const currentContractFactoryPlug = - await watcherPrecompile.contractFactoryPlug(chain); - const currentFeesPlug = await watcherPrecompile.feesPlug(chain); + await watcherPrecompileConfig.contractFactoryPlug(chain); + const currentFeesPlug = await watcherPrecompileConfig.feesPlug(chain); + console.log("Setting onchain contracts for", chain); if ( - currentSbAddress.toLowerCase() !== sbAddress.toLowerCase() || currentSocket.toLowerCase() !== socketAddress.toLowerCase() || currentContractFactoryPlug.toLowerCase() !== contractFactoryPlugAddress.toLowerCase() || currentFeesPlug.toLowerCase() !== feesPlugAddress.toLowerCase() ) { - const tx = await watcherPrecompile + const tx = await watcherPrecompileConfig .connect(signer) .setOnChainContracts( chain, - fastSBtype, - sbAddress, socketAddress, contractFactoryPlugAddress, feesPlugAddress @@ -112,6 +99,16 @@ async function setOnchainContracts(chain, addresses) { console.log(`Setting onchain contracts for ${chain}, txHash: `, tx.hash); await tx.wait(); } + + console.log("Setting switchboard for", chain); + if (currentSbAddress.toLowerCase() !== sbAddress.toLowerCase()) { + const tx = await watcherPrecompileConfig + .connect(signer) + .setSwitchboard(chain, FAST_SWITCHBOARD_TYPE, sbAddress); + + console.log(`Setting switchboard for ${chain}, txHash: `, tx.hash); + await tx.wait(); + } } const registerSb = async (sbAddress, signer, socket) => { diff --git a/hardhat-scripts/deploy/4.connect.ts b/hardhat-scripts/deploy/4.connect.ts index 0de5a503..1b0bfd84 100644 --- a/hardhat-scripts/deploy/4.connect.ts +++ b/hardhat-scripts/deploy/4.connect.ts @@ -1,5 +1,5 @@ -import { ChainAddressesObj } from "@socket.tech/socket-protocol-common"; -import { Contract, ethers, providers, Wallet } from "ethers"; +import { Contract, ethers, Wallet } from "ethers"; +import { ChainAddressesObj, ChainSlug } from "../../src"; import { chains, EVMX_CHAIN_ID, mode } from "../config"; import { CORE_CONTRACTS, @@ -9,10 +9,10 @@ import { import { getAddresses, getInstance, - getProviderFromChainSlug, + getSocketSigner, overrides, } from "../utils"; -import { signWatcherMessage } from "../utils/sign"; +import { getWatcherSigner, signWatcherMessage } from "../utils/sign"; const plugs = [CORE_CONTRACTS.ContractFactoryPlug, CORE_CONTRACTS.FeesPlug]; export type AppGatewayConfig = { plug: string; @@ -58,9 +58,8 @@ export const isConfigSetOnSocket = async ( const plugConfigRegistered = await socket.getPlugConfig(plug.address); return ( plugConfigRegistered.appGateway.toLowerCase() === - appGateway?.toLowerCase() && - plugConfigRegistered.switchboard__.toLowerCase() === - switchboard.toLowerCase() + appGateway.toLowerCase() && + plugConfigRegistered.switchboard.toLowerCase() === switchboard.toLowerCase() ); }; @@ -113,11 +112,7 @@ export const connectPlugsOnSocket = async () => { chains.map(async (chain) => { if (!addresses[chain]) return; - const providerInstance = getProviderFromChainSlug(chain); - const socketSigner = new Wallet( - process.env.SOCKET_SIGNER_KEY as string, - providerInstance - ); + const socketSigner = getSocketSigner(chain as ChainSlug); const addr = addresses[chain]!; // Connect each plug contract for (const plugContract of plugs) { @@ -149,18 +144,12 @@ export const updateConfigEVMx = async () => { const appConfigs: AppGatewayConfig[] = []; // Set up Watcher contract - const providerInstance = new providers.StaticJsonRpcProvider( - process.env.EVMX_RPC as string - ); - const signer = new ethers.Wallet( - process.env.WATCHER_PRIVATE_KEY as string, - providerInstance - ); + const signer = getWatcherSigner(); const EVMxAddresses = addresses[EVMX_CHAIN_ID]!; - const watcher = ( + const watcherPrecompileConfig = ( await getInstance( - EVMxCoreContracts.WatcherPrecompile, - EVMxAddresses[EVMxCoreContracts.WatcherPrecompile] + EVMxCoreContracts.WatcherPrecompileConfig, + EVMxAddresses[EVMxCoreContracts.WatcherPrecompileConfig] ) ).connect(signer); @@ -178,7 +167,7 @@ export const updateConfigEVMx = async () => { if ( await isConfigSetOnEVMx( - watcher, + watcherPrecompileConfig, chain, addr[plugContract], appGateway, @@ -206,12 +195,21 @@ export const updateConfigEVMx = async () => { "bytes4", "tuple(address plug,address appGateway,address switchboard,uint32 chainSlug)[]", ], - [watcher.interface.getSighash("setAppGateways"), appConfigs] + [ + watcherPrecompileConfig.interface.getSighash("setAppGateways"), + appConfigs, + ] + ); + const { nonce, signature } = await signWatcherMessage( + encodedMessage, + watcherPrecompileConfig.address + ); + const tx = await watcherPrecompileConfig.setAppGateways( + appConfigs, + nonce, + signature, + { ...overrides(EVMX_CHAIN_ID) } ); - const { nonce, signature } = await signWatcherMessage(encodedMessage); - const tx = await watcher.setAppGateways(appConfigs, nonce, signature, { - ...overrides(EVMX_CHAIN_ID), - }); console.log(`Updating EVMx Config tx hash: ${tx.hash}`); await tx.wait(); } diff --git a/hardhat-scripts/deploy/5.upload.ts b/hardhat-scripts/deploy/5.upload.ts index b6d5aebb..4eaccb8f 100644 --- a/hardhat-scripts/deploy/5.upload.ts +++ b/hardhat-scripts/deploy/5.upload.ts @@ -1,20 +1,15 @@ import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; -import { - ChainAddressesObj, - DeploymentMode, - EVMxAddressesObj, - chainSlugToHardhatChainName, - ChainSlug -} from "@socket.tech/socket-protocol-common"; +import { DeploymentMode } from "../../src"; import { config as dotenvConfig } from "dotenv"; -import fs from "fs"; -import path from "path"; -import { EVMX_CHAIN_ID, mode, chains } from "../config/config"; +import { mode } from "../config/config"; +import { getS3Config } from "../s3Config/buildConfig"; dotenvConfig(); const getBucketName = () => { switch (mode) { + case DeploymentMode.LOCAL: + return "socketpoc"; case DeploymentMode.DEV: return "socketpoc"; case DeploymentMode.STAGE: @@ -28,6 +23,8 @@ const getBucketName = () => { const getFileName = () => { switch (mode) { + case DeploymentMode.LOCAL: + return "pocConfig.json"; case DeploymentMode.DEV: return "devConfig.json"; case DeploymentMode.STAGE: @@ -38,75 +35,17 @@ const getFileName = () => { throw new Error(`Invalid deployment mode: ${mode}`); } }; - -const getAddressesPath = () => { - switch (mode) { - case DeploymentMode.DEV: - return "../../deployments/dev_addresses.json"; - case DeploymentMode.STAGE: - return "../../deployments/stage_addresses.json"; - case DeploymentMode.PROD: - return "../../deployments/prod_addresses.json"; - default: - throw new Error(`Invalid deployment mode: ${mode}`); - } -}; -type ConfigEntry = { - eventBlockRangePerCron: number; - rpc: string | undefined; - wssRpc: string | undefined; - confirmations: number; - eventBlockRange: number; - addresses?: ChainAddressesObj | EVMxAddressesObj; -}; -type S3Config = { - [chainId: string]: ConfigEntry; -}; - -const supportedChainSlugs = [EVMX_CHAIN_ID as ChainSlug, ...chains]; - -export let config: S3Config = { - //@ts-ignore - supportedChainSlugs, -}; - -// Add config for each supported chain -supportedChainSlugs.forEach(chainSlug => { - let chainName = - chainSlug === EVMX_CHAIN_ID ? "EVMX" : chainSlugToHardhatChainName[chainSlug].toString().replace("-", "_"); - let rpcKey = `${chainName.toUpperCase()}_RPC`; - let wssRpcKey = `${chainName.toUpperCase()}_WSS_RPC`; - if (!process.env[rpcKey] || !process.env[wssRpcKey]) { - console.log(`Missing RPC or WSS RPC for chain ${chainName}`); - return; - } - config[chainSlug] = { - eventBlockRangePerCron: 5000, - rpc: process.env[rpcKey], - wssRpc: process.env[wssRpcKey], - confirmations: 0, - eventBlockRange: 5000, - }; -}); -// Read the addresses.json file -const addressesPath = path.join(__dirname, getAddressesPath()); -const addresses = JSON.parse(fs.readFileSync(addressesPath, "utf8")); - -// Update config with addresses -for (const chainId in config) { - if (addresses[chainId]) { - console.log(`Updating addresses for chainId ${chainId}`); - config[chainId].addresses = addresses[chainId]; - } -} -console.log(JSON.stringify(config, null, 2)); // Initialize S3 client const s3Client = new S3Client({ region: "us-east-1" }); // Replace with your preferred region // Function to upload to S3 -async function uploadToS3(data: any, fileName: string = getFileName()) { +async function uploadToS3() { + const fileName = getFileName(); + const bucketName = getBucketName(); + const data = getS3Config(); + console.log(JSON.stringify(data, null, 2)); const params = { - Bucket: getBucketName(), + Bucket: bucketName, Key: fileName, Body: JSON.stringify(data, null, 2), ContentType: "application/json", @@ -115,12 +54,10 @@ async function uploadToS3(data: any, fileName: string = getFileName()) { try { const command = new PutObjectCommand(params); await s3Client.send(command); - console.log(`Successfully uploaded ${fileName} to S3`); + console.log(`Successfully uploaded ${fileName} to S3 bucket ${bucketName}`); } catch (error) { console.error(`Error uploading ${fileName} to S3:`, error); } } -// Upload config to S3 -// uploadToS3(config, "pocConfig.json"); -uploadToS3(config); +uploadToS3(); diff --git a/hardhat-scripts/deploy/6.setupEnv.ts b/hardhat-scripts/deploy/6.setupEnv.ts index 17707fed..6f9a7f83 100644 --- a/hardhat-scripts/deploy/6.setupEnv.ts +++ b/hardhat-scripts/deploy/6.setupEnv.ts @@ -1,4 +1,4 @@ -import { ChainSlug } from "@socket.tech/socket-protocol-common"; +import { ChainSlug } from "../../src"; import fs from "fs"; import path from "path"; import { EVMX_CHAIN_ID, mode } from "../config/config"; diff --git a/hardhat-scripts/migration/migrate-proxies.ts b/hardhat-scripts/migration/migrate-proxies.ts deleted file mode 100644 index ca8068c1..00000000 --- a/hardhat-scripts/migration/migrate-proxies.ts +++ /dev/null @@ -1,220 +0,0 @@ -import { ethers } from "hardhat"; -import { Contract, utils, Wallet } from "ethers"; -import { EVMX_CHAIN_ID, UPGRADE_VERSION } from "../config/config"; -import { getProviderFromChainSlug } from "../utils"; -import { ChainSlug } from "@socket.tech/socket-protocol-common"; -import { getAddresses } from "../utils"; -import { mode } from "../config/config"; -// Implementation slot from ERC1967 -const IMPLEMENTATION_SLOT = - "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; - -const upgradeableContracts = [ - "AddressResolver", - "WatcherPrecompile", - "FeesManager", - "DeliveryHelper", - "AuctionManager", -]; - -export async function getImplementationAddress( - proxyAddress: string -): Promise { - const customProvider = new ethers.providers.JsonRpcProvider( - process.env.EVMX_RPC as string - ); - - // Fallback to standard storage slot for other proxy types - const implHex = await customProvider.getStorageAt( - proxyAddress, - IMPLEMENTATION_SLOT - ); - - return utils.getAddress("0x" + implHex.slice(-40)); -} - -async function setupSigner() { - const providerInstance = getProviderFromChainSlug(EVMX_CHAIN_ID as ChainSlug); - return new ethers.Wallet( - process.env.WATCHER_PRIVATE_KEY as string, - providerInstance - ); -} - -async function setupProxyFactory(addresses: any, signer: Wallet) { - let proxyFactory = await ethers.getContractAt( - "ERC1967Factory", - addresses[EVMX_CHAIN_ID].ERC1967Factory - ); - return proxyFactory.connect(signer); -} - -async function upgradeContract( - contractName: string, - addresses: any, - proxyFactory: Contract, - signer: Wallet -) { - console.log(`\nProcessing ${contractName}...`); - - const PROXY_ADDRESS = addresses[EVMX_CHAIN_ID][contractName]; - if (!PROXY_ADDRESS) { - console.log(`Contract address not found for ${contractName}`); - return; - } - - try { - const currentImplAddress = await getImplementationAddress(PROXY_ADDRESS); - console.log( - `Current implementation for ${contractName}: ${currentImplAddress}` - ); - - const newImplementation = addresses[EVMX_CHAIN_ID][`${contractName}Impl`]; - if (!newImplementation) { - console.log(`No implementation address found for ${contractName}`); - return; - } - - let contract = await ethers.getContractAt(contractName, PROXY_ADDRESS); - contract = contract.connect(signer); - - await verifyAndUpgradeContract( - contract, - contractName, - currentImplAddress, - newImplementation, - proxyFactory, - signer - ); - } catch (error) { - console.error(`Error upgrading ${contractName}:`, error); - process.exit(1); - } -} - -async function verifyAndUpgradeContract( - contract: Contract, - contractName: string, - currentImplAddress: string, - newImplementation: string, - proxyFactory: Contract, - signer: Wallet -) { - let version; - try { - version = await contract.version(); - console.log("Version on contract before upgrade:", version); - } catch (error) { - console.log("version variable not found"); - } - - if (contractName === "AddressResolver") - await verifyBeaconImplementation(contract, signer); - - if (currentImplAddress.toLowerCase() === newImplementation.toLowerCase()) { - console.log("Implementation is already up to date"); - return; - } - - await performUpgrade(contract, proxyFactory, newImplementation); - await verifyUpgrade(contract, newImplementation, contractName, signer); -} - -async function performUpgrade( - contract: Contract, - proxyFactory: Contract, - newImplementation: string -) { - console.log("Upgrading proxy..."); - const initializeFn = contract.interface.getFunction("initialize"); - const initData = contract.interface.encodeFunctionData(initializeFn, [ - UPGRADE_VERSION, - ]); - - const tx = await proxyFactory.upgradeAndCall( - contract.address, - newImplementation, - initData - ); - console.log("tx", tx.hash); - await tx.wait(); -} - -async function verifyUpgrade( - contract: Contract, - newImplementation: string, - contractName: string, - signer: Wallet -) { - const updatedImplAddress = await getImplementationAddress(contract.address); - console.log("New implementation:", updatedImplAddress); - - if (updatedImplAddress.toLowerCase() !== newImplementation.toLowerCase()) { - throw new Error("Upgrade verification failed - implementation mismatch"); - } - - const version = await contract.version(); - console.log("Version on contract after upgrade:", version); - - if (contractName === "AddressResolver") { - await verifyBeaconImplementation(contract, signer); - } - - console.log("Upgrade successful and verified"); -} - -async function verifyBeaconImplementation(contract: Contract, signer: Wallet) { - console.log("Verifying beacon implementations..."); - const forwarderBeaconAddress = await contract.forwarderBeacon(); - const forwarderImplementationAddress = - await contract.forwarderImplementation(); - const asyncPromiseBeaconAddress = await contract.asyncPromiseBeacon(); - const asyncPromiseImplementationAddress = - await contract.asyncPromiseImplementation(); - - const upgradeableBeaconAbi = [ - "function implementation() view returns (address)", - ]; - - const forwarderBeacon = new ethers.Contract( - forwarderBeaconAddress, - upgradeableBeaconAbi - ); - const asyncPromiseBeacon = new ethers.Contract( - asyncPromiseBeaconAddress, - upgradeableBeaconAbi - ); - - // Verify forwarder beacon implementation - const forwarderBeaconImplementation = await forwarderBeacon - .connect(signer) - .implementation(); - if ( - forwarderBeaconImplementation.toLowerCase() !== - forwarderImplementationAddress.toLowerCase() - ) { - throw new Error("Forwarder beacon implementation mismatch"); - } - - // Verify async promise beacon implementation - const asyncPromiseBeaconImplementation = await asyncPromiseBeacon - .connect(signer) - .implementation(); - if ( - asyncPromiseBeaconImplementation.toLowerCase() !== - asyncPromiseImplementationAddress.toLowerCase() - ) { - throw new Error("Async promise beacon implementation mismatch"); - } -} - -async function main() { - // @ts-ignore - Hardhat Runtime Environment will be injected by hardhat - const addresses = getAddresses(mode); - const signer = await setupSigner(); - const proxyFactory = await setupProxyFactory(addresses, signer); - - for (const contractName of upgradeableContracts) { - await upgradeContract(contractName, addresses, proxyFactory, signer); - } -} diff --git a/hardhat-scripts/misc-scripts/getErrorCodes.ts b/hardhat-scripts/misc-scripts/errorCodes.ts similarity index 100% rename from hardhat-scripts/misc-scripts/getErrorCodes.ts rename to hardhat-scripts/misc-scripts/errorCodes.ts diff --git a/hardhat-scripts/misc-scripts/eventTopics.ts b/hardhat-scripts/misc-scripts/eventTopics.ts new file mode 100644 index 00000000..1b86fa95 --- /dev/null +++ b/hardhat-scripts/misc-scripts/eventTopics.ts @@ -0,0 +1,80 @@ +import { ethers } from "ethers"; +import fs from "fs"; +import { artifacts } from "hardhat"; +import path from "path"; + +async function main() { + console.log("Event Topics:\n"); + + // Get all contract artifacts + const contractFiles = fs + .readdirSync(path.join(__dirname, "../../contracts"), { recursive: true }) + .filter((file) => file.toString().endsWith(".sol")); + + const contracts: string[] = []; + + for (const file of contractFiles) { + console.log(file); + const content = fs.readFileSync( + path.join(__dirname, "../../contracts", file.toString()), + "utf8" + ); + + // Get all contracts and interfaces in file + const matches = content.matchAll( + /(?:abstract\s+)?(?:contract|interface)\s+(\w+)(?:\s+is\s+[\w,\s]+)?{/g + ); + const contractsInFile = Array.from(matches).map((match) => ({ + name: match[1], + isAbstract: match[0].startsWith("abstract"), + })); + + // Skip if all contracts in file are abstract + if (contractsInFile.every((c) => c.isAbstract)) { + console.log("Skipping file with only abstract contracts:", file); + continue; + } + + // Add non-abstract contracts and interfaces + const validContracts = contractsInFile.filter((c) => !c.isAbstract); + contracts.push(...validContracts.map((c) => c.name)); + } + + let mdContent = "# Event Topics\n\n"; + + for (const contractName of contracts) { + console.log(`\n${contractName}:`); + console.log("-".repeat(contractName.length + 1)); + + mdContent += `## ${contractName}\n\n`; + mdContent += "| Event | Arguments | Topic |\n"; + mdContent += "| ----- | --------- | ----- |\n"; + + const artifact = await artifacts.readArtifact(contractName); + const iface = new ethers.utils.Interface(artifact.abi); + + const events = iface.events; + Object.values(events).forEach((event) => { + const topic = iface.getEventTopic(event.name); + const args = event.inputs + .map((input) => `${input.name}: ${input.type}`) + .join(", "); + console.log(`${event.name}(${args}): ${topic}`); + mdContent += `| \`${event.name}\` | \`(${args})\` | \`${topic}\` |\n`; + }); + + mdContent += "\n"; + } + + // Write to file + const outputPath = path.join(__dirname, "../../EventTopics.md"); + fs.writeFileSync(outputPath, mdContent); + console.log("\nEvent topics written to EventTopics.md"); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/hardhat-scripts/misc-scripts/functionSigs.ts b/hardhat-scripts/misc-scripts/functionSigs.ts new file mode 100644 index 00000000..fb44cafd --- /dev/null +++ b/hardhat-scripts/misc-scripts/functionSigs.ts @@ -0,0 +1,83 @@ +import { ethers } from "ethers"; +import fs from "fs"; +import { artifacts } from "hardhat"; +import path from "path"; + +async function main() { + console.log("Function Signatures:\n"); + + // Get all contract artifacts + const contractFiles = fs + .readdirSync(path.join(__dirname, "../../contracts"), { recursive: true }) + .filter((file) => file.toString().endsWith(".sol")); + + const contracts: string[] = []; + + for (const file of contractFiles) { + console.log(file); + const content = fs.readFileSync( + path.join(__dirname, "../../contracts", file.toString()), + "utf8" + ); + + // Skip interfaces + if (content.includes("interface ")) { + console.log("Skipping interface:", file); + continue; + } + + // Get all contracts in file + const contractMatches = content.matchAll( + /(?:abstract\s+)?contract\s+(\w+)(?:\s+is\s+[\w,\s]+)?{/g + ); + const contractsInFile = Array.from(contractMatches).map((match) => ({ + name: match[1], + isAbstract: match[0].startsWith("abstract"), + })); + + // Skip if all contracts in file are abstract + if (contractsInFile.every((c) => c.isAbstract)) { + console.log("Skipping file with only abstract contracts:", file); + continue; + } + + // Only add non-abstract contracts + const nonAbstractContracts = contractsInFile.filter((c) => !c.isAbstract); + contracts.push(...nonAbstractContracts.map((c) => c.name)); + } + + let mdContent = "# Function Signatures\n\n"; + + for (const contractName of contracts) { + console.log(`\n${contractName}:`); + console.log("-".repeat(contractName.length + 1)); + + mdContent += `## ${contractName}\n\n`; + mdContent += "| Function | Signature |\n"; + mdContent += "| -------- | --------- |\n"; + + const artifact = await artifacts.readArtifact(contractName); + const iface = new ethers.utils.Interface(artifact.abi); + + const functions = iface.functions; + Object.values(functions).forEach((func) => { + const sig = iface.getSighash(func.name); + console.log(`${func.name}: ${sig}`); + mdContent += `| \`${func.name}\` | \`${sig}\` |\n`; + }); + + mdContent += "\n"; + } + + // Write to file + const outputPath = path.join(__dirname, "../../FunctionSignatures.md"); + fs.writeFileSync(outputPath, mdContent); + console.log("\nFunction signatures written to FunctionSignatures.md"); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/hardhat-scripts/misc-scripts/getEventTopics.ts b/hardhat-scripts/misc-scripts/getEventTopics.ts deleted file mode 100644 index 09339479..00000000 --- a/hardhat-scripts/misc-scripts/getEventTopics.ts +++ /dev/null @@ -1,78 +0,0 @@ -import fs from "fs"; -import path from "path"; -import { ethers } from "ethers"; - -// Function to recursively get all .sol files -function getSolFiles(dir: string, fileList: string[] = []): string[] { - const files = fs.readdirSync(dir); - - files.forEach((file) => { - const filePath = path.join(dir, file); - if (fs.statSync(filePath).isDirectory()) { - fileList = getSolFiles(filePath, fileList); - } else if (path.extname(file) === ".sol") { - fileList.push(filePath); - } - }); - - return fileList; -} - -// Function to extract event topics from contract file -function extractEventTopics(filePath: string): string[] { - const content = fs.readFileSync(filePath, "utf8"); - const eventRegex = /event\s+(\w+)\s*\(([\s\S]*?)\);/g; - const topics: string[] = []; - - let match; - while ((match = eventRegex.exec(content)) !== null) { - const eventName = match[1]; - const params = match[2] - .split(",") - .map((param) => param.trim().split(" ")[0]) // Extract only the type - .join(","); - const topic = ethers.utils.id(`${eventName}(${params})`); - topics.push(`${eventName} -> ${topic}`); - } - - return topics; -} - -// Main function -async function main() { - const contractsDir = path.join(__dirname, "../../contracts"); - const topicsDir = path.join(__dirname, "../../EventTopics.md"); - const solFiles = getSolFiles(contractsDir); - - console.log("Event Topics Found:"); - console.log("-------------------"); - - let mdContent = "# Event Topics\n\n"; - - for (const file of solFiles) { - const topics = extractEventTopics(file); - if (topics.length > 0) { - console.log(`\nIn ${path.relative(contractsDir, file)}:`); - mdContent += `\n## ${path.relative(contractsDir, file)}\n\n`; - mdContent += "| Event | Topic |\n|-------|-------|"; - - for (const topic of topics) { - console.log(topic); - const [eventName, topicHash] = topic.split(" -> "); - mdContent += `\n| \`${eventName}\` | \`${topicHash}\` |`; - } - mdContent += "\n"; - } - } - - // Write to EventTopics.md file - fs.writeFileSync(topicsDir, mdContent); - console.log("\nEvent topics have been written to EventTopics.md"); -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); diff --git a/hardhat-scripts/s3Config/buildConfig.ts b/hardhat-scripts/s3Config/buildConfig.ts new file mode 100644 index 00000000..7d51681b --- /dev/null +++ b/hardhat-scripts/s3Config/buildConfig.ts @@ -0,0 +1,44 @@ +import { config as dotenvConfig } from "dotenv"; +import { ChainConfig, ChainSlug, S3Config, getFinalityBlocks } from "../../src"; +import { EVMX_CHAIN_ID, chains, mode } from "../config/config"; +import { getAddresses } from "../utils/address"; +import { getChainName, rpcKeys, wssRpcKeys } from "../utils/networks"; +import { getChainType } from "./utils"; +import { version } from "./version"; + +dotenvConfig(); +const addresses = getAddresses(mode); + +export const getS3Config = () => { + const supportedChainSlugs = [EVMX_CHAIN_ID as ChainSlug, ...chains]; + const config: S3Config = { + supportedChainSlugs, + version: version[mode], + chains: {}, + }; + supportedChainSlugs.forEach((chainSlug) => { + config.chains[chainSlug] = getChainConfig(chainSlug); + }); + return config; +}; + +export const getChainConfig = (chainSlug: ChainSlug) => { + let rpcKey = rpcKeys(chainSlug); + let wssRpcKey = wssRpcKeys(chainSlug); + if (!process.env[rpcKey] || !process.env[wssRpcKey]) { + throw new Error( + `Missing RPC or WSS RPC for chain ${getChainName(chainSlug)}` + ); + } + const chainConfig: ChainConfig = { + eventBlockRangePerCron: 5000, + rpc: process.env[rpcKey], + wssRpc: process.env[wssRpcKey], + confirmations: 0, + eventBlockRange: 5000, + addresses: addresses[chainSlug], + chainType: getChainType(chainSlug), + finalityBlocks: getFinalityBlocks(chainSlug), + }; + return chainConfig; +}; diff --git a/hardhat-scripts/s3Config/utils.ts b/hardhat-scripts/s3Config/utils.ts new file mode 100644 index 00000000..f5fe6412 --- /dev/null +++ b/hardhat-scripts/s3Config/utils.ts @@ -0,0 +1,23 @@ +import { + arbChains, + arbL3Chains, + ChainSlug, + ChainType, + opStackL2Chain, + polygonCDKChains, + zkStackChain, +} from "../../src"; + +export const getChainType = (chainSlug: ChainSlug) => { + if (opStackL2Chain.includes(chainSlug)) { + return ChainType.opStackL2Chain; + } else if (arbChains.includes(chainSlug)) { + return ChainType.arbChain; + } else if (arbL3Chains.includes(chainSlug)) { + return ChainType.arbL3Chain; + } else if (polygonCDKChains.includes(chainSlug)) { + return ChainType.zkStackChain; + } else if (zkStackChain.includes(chainSlug)) { + return ChainType.polygonCDKChain; + } else return ChainType.default; +}; diff --git a/hardhat-scripts/s3Config/version.ts b/hardhat-scripts/s3Config/version.ts new file mode 100644 index 00000000..ad7863dd --- /dev/null +++ b/hardhat-scripts/s3Config/version.ts @@ -0,0 +1,8 @@ +import { DeploymentMode } from "../../src"; + +export const version = { + [DeploymentMode.LOCAL]: "1.0.17", + [DeploymentMode.DEV]: "1.0.17", + [DeploymentMode.STAGE]: "1.0.17", + [DeploymentMode.PROD]: "1.0.17", +}; diff --git a/hardhat-scripts/utils/address.ts b/hardhat-scripts/utils/address.ts index d74f1313..6caf8c3f 100644 --- a/hardhat-scripts/utils/address.ts +++ b/hardhat-scripts/utils/address.ts @@ -1,16 +1,21 @@ import dev_addresses from "../../deployments/dev_addresses.json"; import stage_addresses from "../../deployments/stage_addresses.json"; -import prod_addresses from "../../deployments/prod_addresses.json"; -import { DeploymentMode } from "@socket.tech/socket-protocol-common"; +import local_addresses from "../../deployments/local_addresses.json"; +import { ChainAddressesObj, DeploymentMode, EVMxAddressesObj } from "../../src"; -export const getAddresses = (mode: DeploymentMode) => { +export const getAddresses = ( + mode: DeploymentMode +): { [chainSlug: string | number]: ChainAddressesObj | EVMxAddressesObj } => { switch (mode) { + case DeploymentMode.LOCAL: + // @ts-ignore + return local_addresses; case DeploymentMode.DEV: + // @ts-ignore return dev_addresses; case DeploymentMode.STAGE: + // @ts-ignore return stage_addresses; - case DeploymentMode.PROD: - return prod_addresses; default: throw new Error(`Invalid deployment mode: ${mode}`); } diff --git a/hardhat-scripts/utils/deployUtils.ts b/hardhat-scripts/utils/deployUtils.ts index a3accdf2..62824dcf 100644 --- a/hardhat-scripts/utils/deployUtils.ts +++ b/hardhat-scripts/utils/deployUtils.ts @@ -5,11 +5,7 @@ import { ContractFactory, Contract } from "ethers"; import { Address } from "hardhat-deploy/dist/types"; import path from "path"; import fs from "fs"; -import { - ChainAddressesObj, - ChainSlug, - DeploymentMode, -} from "@socket.tech/socket-protocol-common"; +import { ChainAddressesObj, ChainSlug, DeploymentMode } from "../../src"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { overrides } from "../utils"; import { VerifyArgs } from "../verify"; @@ -67,7 +63,10 @@ export const getOrDeploy = async ( deployUtils.mode ); } else { - contract = await getInstance(contractName, deployUtils.addresses[keyName]); + contract = await getInstance( + path + `:${contractName}`, + deployUtils.addresses[keyName] + ); console.log( `${contractName} found on ${deployUtils.currentChainSlug} for ${deployUtils.mode} at address ${contract.address}` ); @@ -83,6 +82,7 @@ export async function deployContractWithArgs( chainSlug: ChainSlug ) { try { + console.log("deploying", contractName, args); const Contract: ContractFactory = await ethers.getContractFactory( contractName ); diff --git a/hardhat-scripts/utils/index.ts b/hardhat-scripts/utils/index.ts index b0ec6153..e11a036e 100644 --- a/hardhat-scripts/utils/index.ts +++ b/hardhat-scripts/utils/index.ts @@ -3,3 +3,4 @@ export * from "./networks"; export * from "./overrides"; export * from "./accounts"; export * from "./deployUtils"; +export * from "./sign"; diff --git a/hardhat-scripts/utils/networks.ts b/hardhat-scripts/utils/networks.ts index b2f55ebe..a8cc205c 100644 --- a/hardhat-scripts/utils/networks.ts +++ b/hardhat-scripts/utils/networks.ts @@ -6,7 +6,7 @@ import { hardhatChainNameToSlug, HardhatChainName, chainSlugToHardhatChainName, -} from "@socket.tech/socket-protocol-common"; +} from "../../src"; import { EVMX_CHAIN_ID } from "../config/config"; const dotenvConfigPath: string = process.env.DOTENV_CONFIG_PATH || "./.env"; @@ -21,15 +21,23 @@ function createReverseEnumMap(enumObj: any) { return reverseMap; } -export const rpcKeys = (chainSlug: ChainSlug) => { - if (chainSlug == (EVMX_CHAIN_ID as ChainSlug)) { - return "EVMX_RPC"; +export const getChainName = (chainSlug: ChainSlug) => { + if (chainSlug === EVMX_CHAIN_ID) { + return "EVMX"; } - let chainName = chainSlugToHardhatChainName[chainSlug].toString(); - chainName = chainName.replace("-", "_"); + return chainSlugToHardhatChainName[chainSlug].toString().replace("-", "_"); +}; + +export const rpcKeys = (chainSlug: ChainSlug) => { + const chainName = getChainName(chainSlug); return `${chainName.toUpperCase()}_RPC`; }; +export const wssRpcKeys = (chainSlug: ChainSlug) => { + const chainName = getChainName(chainSlug); + return `${chainName.toUpperCase()}_WSS_RPC`; +}; + export function getJsonRpcUrl(chain: ChainSlug): string { let chainRpcKey = rpcKeys(chain); if (!chainRpcKey) throw Error(`Chain ${chain} not found in rpcKey`); diff --git a/hardhat-scripts/utils/overrides.ts b/hardhat-scripts/utils/overrides.ts index 7d9ccc96..d4cfdafc 100644 --- a/hardhat-scripts/utils/overrides.ts +++ b/hardhat-scripts/utils/overrides.ts @@ -1,4 +1,4 @@ -import { ChainSlug } from "@socket.tech/socket-protocol-common"; +import { ChainSlug } from "../../src"; import { BigNumber, BigNumberish, providers } from "ethers"; import { EVMX_CHAIN_ID } from "../config/config"; import { getProviderFromChainSlug } from "./networks"; diff --git a/hardhat-scripts/utils/sign.ts b/hardhat-scripts/utils/sign.ts index 2bd67a08..5f7ed311 100644 --- a/hardhat-scripts/utils/sign.ts +++ b/hardhat-scripts/utils/sign.ts @@ -1,19 +1,30 @@ -import { ethers, Wallet } from "ethers"; -import { EVMX_CHAIN_ID, mode } from "../config/config"; -import { EVMxCoreContracts } from "../constants"; -import { getAddresses } from "./address"; +import { ethers } from "ethers"; +import { ChainSlug } from "../../src"; +import { EVMX_CHAIN_ID } from "../config/config"; +import { getProviderFromChainSlug } from "./networks"; -export const signWatcherMessage = async (encodedMessage: string) => { +export const signWatcherMessage = async ( + encodedMessage: string, + watcherContractAddress: string +) => { const signatureNonce = Date.now(); - const signer = new Wallet(process.env.WATCHER_PRIVATE_KEY!); - const watcherPrecompileAddress = - getAddresses(mode)[EVMX_CHAIN_ID][EVMxCoreContracts.WatcherPrecompile]; + const signer = getWatcherSigner(); const digest = ethers.utils.keccak256( ethers.utils.defaultAbiCoder.encode( ["address", "uint32", "uint256", "bytes"], - [watcherPrecompileAddress, EVMX_CHAIN_ID, signatureNonce, encodedMessage] + [watcherContractAddress, EVMX_CHAIN_ID, signatureNonce, encodedMessage] ) ); const signature = await signer.signMessage(ethers.utils.arrayify(digest)); return { nonce: signatureNonce, signature }; }; + +export const getWatcherSigner = () => { + const provider = getProviderFromChainSlug(EVMX_CHAIN_ID as ChainSlug); + return new ethers.Wallet(process.env.WATCHER_PRIVATE_KEY as string, provider); +}; + +export const getSocketSigner = (chainSlug: ChainSlug) => { + const provider = getProviderFromChainSlug(chainSlug); + return new ethers.Wallet(process.env.SOCKET_SIGNER_KEY as string, provider); +}; diff --git a/hardhat-scripts/verify/verify.ts b/hardhat-scripts/verify/verify.ts index 4afabe63..2835a150 100644 --- a/hardhat-scripts/verify/verify.ts +++ b/hardhat-scripts/verify/verify.ts @@ -1,25 +1,26 @@ import { ChainSlug, - ChainSlugToKey, - DeploymentMode, HardhatChainName, -} from "@socket.tech/socket-protocol-common"; + DeploymentMode, + ChainSlugToKey, +} from "../../src"; import hre from "hardhat"; import { EVMX_CHAIN_ID, mode } from "../config/config"; import { storeUnVerifiedParams, verify } from "../utils"; +import local_addresses from "../../deployments/local_addresses.json"; import dev_verification from "../../deployments/dev_verification.json"; -import prod_verification from "../../deployments/prod_verification.json"; import stage_verification from "../../deployments/stage_verification.json"; const getVerificationParams = (mode: DeploymentMode) => { switch (mode) { + case DeploymentMode.LOCAL: + //@ts-ignore + return local_addresses; case DeploymentMode.DEV: return dev_verification; case DeploymentMode.STAGE: return stage_verification; - case DeploymentMode.PROD: - return prod_verification; default: throw new Error(`Invalid deployment mode: ${mode}`); } diff --git a/hardhat.config.ts b/hardhat.config.ts index 72ce85e8..ada0e153 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -5,6 +5,8 @@ import "hardhat-preprocessor"; import "hardhat-deploy"; import "hardhat-abi-exporter"; import "hardhat-change-network"; +import "hardhat-contract-sizer"; + import { config as dotenvConfig } from "dotenv"; import type { HardhatUserConfig } from "hardhat/config"; import type { @@ -22,9 +24,8 @@ import { ChainSlugToId, HardhatChainName, hardhatChainNameToSlug, -} from "@socket.tech/socket-protocol-common"; +} from "./src"; import { EVMX_CHAIN_ID } from "./hardhat-scripts/config/config"; -import { BASE_SEPOLIA_CHAIN_ID } from "./hardhat-scripts/constants"; const dotenvConfigPath: string = process.env.DOTENV_CONFIG_PATH || "./.env"; dotenvConfig({ path: resolve(__dirname, dotenvConfigPath) }); @@ -59,16 +60,12 @@ let liveNetworks = { ChainSlug.OPTIMISM_SEPOLIA ), [HardhatChainName.SEPOLIA]: getChainConfig(ChainSlug.SEPOLIA), + [HardhatChainName.BASE_SEPOLIA]: getChainConfig(ChainSlug.BASE_SEPOLIA), EVMX: { accounts: [`0x${privateKey}`], chainId: EVMX_CHAIN_ID, url: process.env.EVMX_RPC, }, - ["base_sepolia"]: { - accounts: [`0x${privateKey}`], - chainId: BASE_SEPOLIA_CHAIN_ID, - url: process.env.BASE_SEPOLIA_RPC, - }, }; const config: HardhatUserConfig = { @@ -121,7 +118,7 @@ const config: HardhatUserConfig = { }, { network: "baseTestnet", - chainId: BASE_SEPOLIA_CHAIN_ID, + chainId: ChainId.BASE_SEPOLIA, urls: { apiURL: "https://api-sepolia.basescan.org/api", browserURL: "https://sepolia.basescan.org/", @@ -131,8 +128,8 @@ const config: HardhatUserConfig = { network: "evmx", chainId: EVMX_CHAIN_ID, urls: { - apiURL: "", - browserURL: "", + apiURL: "https://evmx.cloud.blockscout.com/api", + browserURL: "https://evmx.cloud.blockscout.com/", }, }, ], @@ -163,7 +160,7 @@ const config: HardhatUserConfig = { evmVersion: "paris", optimizer: { enabled: true, - runs: 999, + runs: 1, details: { yul: true, yulDetails: { @@ -171,7 +168,7 @@ const config: HardhatUserConfig = { }, }, }, - viaIR: true, + viaIR: false, }, }, }; diff --git a/lib/solmate b/lib/solmate deleted file mode 160000 index c93f7716..00000000 --- a/lib/solmate +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c93f7716c9909175d45f6ef80a34a650e2d24e56 diff --git a/package.json b/package.json index aee7ad7e..80d12f1f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@socket.tech/socket-protocol", - "main": "./dist/src/index.js", - "types": "./dist/src/index.d.ts", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "files": [ "dist", "artifacts/abi" @@ -9,16 +9,17 @@ "publishConfig": { "access": "public" }, - "version": "1.0.15", + "version": "1.1.9", "description": "socket protocol", "scripts": { - "build": "hardhat export-abi && tsc --project lib.tsconfig.json", + "build": "yarn abi && tsc --project lib.tsconfig.json", "tsc": "tsc --project lib.tsconfig.json", "abi": "hardhat export-abi", "lint": "prettier \"./**\" --write", "lintContracts": "prettier \"./**\" --write --plugin=prettier-plugin-solidity", "compile": "forge build", - "deploy": "bash setupInfraContracts.sh" + "deploy": "bash setupInfraContracts.sh", + "publish-core": "yarn build && yarn publish --patch --no-git-tag-version" }, "pre-commit": [], "author": "", @@ -27,24 +28,29 @@ "@aws-sdk/client-s3": "^3.670.0", "@nomicfoundation/hardhat-verify": "^2.0.12", "@nomiclabs/hardhat-ethers": "2.2.3", - "@socket.tech/socket-protocol-common": "1.1.31", + "@socket.tech/socket-protocol-common": "1.1.44", "@typechain/ethers-v5": "^10.0.0", "@typechain/hardhat": "6.0.0", + "@types/node": "^22.13.9", + "@types/prompts": "^2.4.9", "dotenv": "^16.0.3", "ethers": "5.6.6", - "forge-std": "^1.1.2", "hardhat": "2.12.2", "hardhat-abi-exporter": "2.10.1", "hardhat-change-network": "^0.0.7", "hardhat-deploy": "0.11.20", "hardhat-preprocessor": "0.1.4", "http-server": "^14.1.1", + "path": "^0.12.7", "pre-commit": "^1.2.2", "prettier": "^2.3.1", "prettier-plugin-solidity": "^1.4.1", + "prompts": "^2.4.2", "ts-node": "^10.7.0", "typechain": "^8.0.0", "typescript": "^4.6.4" }, - "dependencies": {} + "dependencies": { + "hardhat-contract-sizer": "^2.10.0" + } } diff --git a/publish.sh b/publish.sh new file mode 100755 index 00000000..6d4331ee --- /dev/null +++ b/publish.sh @@ -0,0 +1,2 @@ +yarn build +yarn publish \ No newline at end of file diff --git a/remappings.txt b/remappings.txt index 1cf3bb7d..7b75fc8f 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,4 +1,3 @@ -ds-test/=lib/forge-std/lib/ds-test/src/ -forge-std/=lib/forge-std/src/ -solmate/=lib/solmate/src/ -solady/=lib/solady/src/ \ No newline at end of file +hardhat-deploy/=node_modules/hardhat-deploy/ +hardhat/=node_modules/hardhat/ +solady/=lib/solady/src/ diff --git a/script/admin/UpdateAppEVMxLimits.s.sol b/script/admin/UpdateAppEVMxLimits.s.sol index 94b52c09..4389c1be 100644 --- a/script/admin/UpdateAppEVMxLimits.s.sol +++ b/script/admin/UpdateAppEVMxLimits.s.sol @@ -46,7 +46,7 @@ contract UpdateLimitsScript is Script { ratePerSecond: 10000000000 // Rate per second }); // // Update the limits - watcherContract.updateLimitParams(updates); + watcherContract.watcherPrecompileLimits__().updateLimitParams(updates); vm.stopBroadcast(); } diff --git a/script/counter/DeployEVMxCounterApp.s.sol b/script/counter/DeployEVMxCounterApp.s.sol index 05d9af02..a62b7e81 100644 --- a/script/counter/DeployEVMxCounterApp.s.sol +++ b/script/counter/DeployEVMxCounterApp.s.sol @@ -7,6 +7,7 @@ import {CounterAppGateway} from "../../test/apps/app-gateways/counter/CounterApp import {Fees} from "../../contracts/protocol/utils/common/Structs.sol"; import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; +// source .env && forge script script/counter/deployEVMxCounterApp.s.sol --broadcast --skip-simulation --legacy --gas-price 0 contract CounterDeploy is Script { function run() external { address addressResolver = vm.envAddress("ADDRESS_RESOLVER"); @@ -20,13 +21,10 @@ contract CounterDeploy is Script { Fees memory fees = Fees({ feePoolChain: 421614, feePoolToken: ETH_ADDRESS, - amount: 0.001 ether + amount: 0.00001 ether }); - CounterAppGateway gateway = new CounterAppGateway( - addressResolver, - fees - ); + CounterAppGateway gateway = new CounterAppGateway(addressResolver, fees); console.log("Contracts deployed:"); console.log("CounterAppGateway:", address(gateway)); diff --git a/script/counter/DeployOnchainCounters.s.sol b/script/counter/DeployOnchainCounters.s.sol index 65b00d4c..d786e76b 100644 --- a/script/counter/DeployOnchainCounters.s.sol +++ b/script/counter/DeployOnchainCounters.s.sol @@ -6,6 +6,7 @@ import {console} from "forge-std/console.sol"; import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; import {CounterAppGateway} from "../../test/apps/app-gateways/counter/CounterAppGateway.sol"; +// source .env && forge script script/counter/DeployCounterOnchain.s.sol --broadcast --skip-simulation --legacy --gas-price 0 contract CounterDeployOnchain is Script { function run() external { string memory rpc = vm.envString("EVMX_RPC"); diff --git a/script/counter/IncrementCountersFromApp.s.sol b/script/counter/IncrementCountersFromApp.s.sol index 60a90fd2..c048237b 100644 --- a/script/counter/IncrementCountersFromApp.s.sol +++ b/script/counter/IncrementCountersFromApp.s.sol @@ -5,6 +5,8 @@ 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/IncrementCountersFromApp.s.sol --broadcast --skip-simulation --legacy --gas-price 0 +// source .env && cast send $APP_GATEWAY "incrementCounters(address[])" '[0xdA908E7491499d64944Ea5Dc967135a0F22d2057]' --private-key $PRIVATE_KEY --legacy --gas-price 0 contract IncrementCounters is Script { function run() external { string memory socketRPC = vm.envString("EVMX_RPC"); diff --git a/script/counter/SetFees.s.sol b/script/counter/SetFees.s.sol new file mode 100644 index 00000000..3d089235 --- /dev/null +++ b/script/counter/SetFees.s.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; +import {CounterAppGateway} from "../../test/apps/app-gateways/counter/CounterAppGateway.sol"; +import {Fees} from "../../contracts/protocol/utils/common/Structs.sol"; +// source .env && forge script script/counter/DeployCounterOnchain.s.sol --broadcast --skip-simulation --legacy --gas-price 0 +contract CounterSetFees is Script { + function run() external { + string memory rpc = vm.envString("EVMX_RPC"); + console.log(rpc); + vm.createSelectFork(rpc); + + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + vm.startBroadcast(deployerPrivateKey); + + CounterAppGateway appGateway = CounterAppGateway(vm.envAddress("APP_GATEWAY")); + console.log("Counter Gateway:", address(appGateway)); + + console.log("Setting fees..."); + // Setting fee payment on Arbitrum Sepolia + Fees memory fees = Fees({ + feePoolChain: 421614, + feePoolToken: ETH_ADDRESS, + amount: 0.00001 ether + }); + appGateway.setFees(fees); + } +} diff --git a/script/helpers/AppGatewayFeeBalance.s.sol b/script/helpers/AppGatewayFeeBalance.s.sol index 6637a83b..0743a7d0 100644 --- a/script/helpers/AppGatewayFeeBalance.s.sol +++ b/script/helpers/AppGatewayFeeBalance.s.sol @@ -12,17 +12,21 @@ contract CheckDepositedFees is Script { vm.createSelectFork(vm.envString("EVMX_RPC")); FeesManager feesManager = FeesManager(payable(vm.envAddress("FEES_MANAGER"))); address appGateway = vm.envAddress("APP_GATEWAY"); - + uint32 chain = 421614; + address token = ETH_ADDRESS; (uint256 deposited, uint256 blocked) = feesManager.appGatewayFeeBalances( appGateway, - 421614, - ETH_ADDRESS + chain, + token ); console.log("App Gateway:", appGateway); + console.log("Fees Manager:", address(feesManager)); + console.logUint(chain); + console.log("Token:", token); console.log("Deposited fees:", deposited); console.log("Blocked fees:", blocked); - uint256 availableFees = feesManager.getAvailableFees(421614, appGateway, ETH_ADDRESS); + uint256 availableFees = feesManager.getAvailableFees(chain, appGateway, token); console.log("Available fees:", availableFees); } } diff --git a/script/helpers/CheckAppEVMxLimits.s.sol b/script/helpers/CheckAppEVMxLimits.s.sol index c61f0719..7c1f16a0 100644 --- a/script/helpers/CheckAppEVMxLimits.s.sol +++ b/script/helpers/CheckAppEVMxLimits.s.sol @@ -18,13 +18,29 @@ contract CheckLimitsScript is Script { console.log("AppGateway address:", appGateway); WatcherPrecompile watcherContract = WatcherPrecompile(watcherPrecompile); - LimitParams memory scheduleLimit = watcherContract.getLimitParams(SCHEDULE, appGateway); - LimitParams memory queryLimit = watcherContract.getLimitParams(QUERY, appGateway); - LimitParams memory finalizeLimit = watcherContract.getLimitParams(FINALIZE, appGateway); + LimitParams memory scheduleLimit = watcherContract + .watcherPrecompileLimits__() + .getLimitParams(SCHEDULE, appGateway); + LimitParams memory queryLimit = watcherContract.watcherPrecompileLimits__().getLimitParams( + QUERY, + appGateway + ); + LimitParams memory finalizeLimit = watcherContract + .watcherPrecompileLimits__() + .getLimitParams(FINALIZE, appGateway); - uint256 scheduleCurrentLimit = watcherContract.getCurrentLimit(SCHEDULE, appGateway); - uint256 queryCurrentLimit = watcherContract.getCurrentLimit(QUERY, appGateway); - uint256 finalizeCurrentLimit = watcherContract.getCurrentLimit(FINALIZE, appGateway); + uint256 scheduleCurrentLimit = watcherContract.watcherPrecompileLimits__().getCurrentLimit( + SCHEDULE, + appGateway + ); + uint256 queryCurrentLimit = watcherContract.watcherPrecompileLimits__().getCurrentLimit( + QUERY, + appGateway + ); + uint256 finalizeCurrentLimit = watcherContract.watcherPrecompileLimits__().getCurrentLimit( + FINALIZE, + appGateway + ); console.log("Schedule max limit:"); console.log(scheduleLimit.maxLimit); diff --git a/script/helpers/PayFeesInArbitrumETH.s.sol b/script/helpers/PayFeesInArbitrumETH.s.sol index 50da4fc1..ebe4f0e2 100644 --- a/script/helpers/PayFeesInArbitrumETH.s.sol +++ b/script/helpers/PayFeesInArbitrumETH.s.sol @@ -7,6 +7,7 @@ import {FeesPlug} from "../../contracts/protocol/payload-delivery/FeesPlug.sol"; import {Fees} from "../../contracts/protocol/utils/common/Structs.sol"; import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; +// source .env && forge script script/helpers/PayFeesInArbitrumETH.s.sol --broadcast --skip-simulation contract DepositFees is Script { function run() external { vm.createSelectFork(vm.envString("ARBITRUM_SEPOLIA_RPC")); @@ -20,7 +21,8 @@ contract DepositFees is Script { console.log("Sender address:", sender); uint256 balance = sender.balance; console.log("Sender balance in wei:", balance); - + console.log("App Gateway:", appGateway); + console.log("Fees Plug:", address(feesPlug)); uint feesAmount = 0.001 ether; feesPlug.deposit{value: feesAmount}(ETH_ADDRESS, appGateway, feesAmount); } diff --git a/setupInfraContracts.sh b/setupInfraContracts.sh index 19d7adb8..dee0dde8 100644 --- a/setupInfraContracts.sh +++ b/setupInfraContracts.sh @@ -1,11 +1,14 @@ -if [ "$1" = "compile" ]; then - time npx hardhat run hardhat-scripts/deploy/1.deploy.ts -else +if [ "$1" = "skip-compile" ]; then time npx hardhat run hardhat-scripts/deploy/1.deploy.ts --no-compile +else + time npx hardhat run hardhat-scripts/deploy/1.deploy.ts fi time npx hardhat run hardhat-scripts/deploy/2.roles.ts --no-compile time npx hardhat run hardhat-scripts/deploy/3.upgradeManagers.ts --no-compile time npx hardhat run hardhat-scripts/deploy/4.connect.ts --no-compile time npx ts-node hardhat-scripts/deploy/5.upload.ts --resolveJsonModule time npx hardhat run hardhat-scripts/deploy/6.setupEnv.ts --no-compile -time npx hardhat run hardhat-scripts/verify/verify.ts --no-compile & disown +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 hardhat run hardhat-scripts/verify/verify.ts --no-compile diff --git a/src/chain-enums/arbChains.ts b/src/chain-enums/arbChains.ts new file mode 100644 index 00000000..5a7a9e81 --- /dev/null +++ b/src/chain-enums/arbChains.ts @@ -0,0 +1,11 @@ +import { ChainSlug } from "./chainSlug"; + +export const arbChains = [ + ChainSlug.ARBITRUM, + ChainSlug.ARBITRUM_GOERLI, + ChainSlug.ARBITRUM_SEPOLIA, + ChainSlug.PARALLEL, + ChainSlug.REYA_CRONOS, + ChainSlug.REYA, + ChainSlug.GEIST, +]; diff --git a/src/chain-enums/arbL3Chains.ts b/src/chain-enums/arbL3Chains.ts new file mode 100644 index 00000000..a400f5da --- /dev/null +++ b/src/chain-enums/arbL3Chains.ts @@ -0,0 +1,9 @@ +import { ChainSlug } from "./chainSlug"; + +export const arbL3Chains = [ + ChainSlug.SYNDR_SEPOLIA_L3, + ChainSlug.KINTO, + ChainSlug.KINTO_DEVNET, + ChainSlug.WINR, + ChainSlug.SYNDR, +]; diff --git a/src/chain-enums/chainId.ts b/src/chain-enums/chainId.ts new file mode 100644 index 00000000..4c7cf31c --- /dev/null +++ b/src/chain-enums/chainId.ts @@ -0,0 +1,60 @@ +export enum ChainId { + ARBITRUM = 42161, + ARBITRUM_GOERLI = 421613, + ARBITRUM_SEPOLIA = 421614, + OPTIMISM = 10, + OPTIMISM_GOERLI = 420, + OPTIMISM_SEPOLIA = 11155420, + BSC = 56, + MAINNET = 1, + GOERLI = 5, + SEPOLIA = 11155111, + POLYGON_MAINNET = 137, + AEVO_TESTNET = 11155112, + AEVO = 2999, + HARDHAT = 31337, + LYRA_TESTNET = 901, + LYRA = 957, + XAI_TESTNET = 47279324479, + CDK_TESTNET = 686669576, + SX_NETWORK_TESTNET = 647, + SX_NETWORK = 416, + MODE_TESTNET = 919, + VICTION_TESTNET = 89, + BASE = 8453, + BASE_SEPOLIA = 84532, + MODE = 34443, + ANCIENT8_TESTNET = 2863311531, + ANCIENT8_TESTNET2 = 28122024, + PARALLEL = 1024, + MANTLE = 5000, + REYA_CRONOS = 89346162, + REYA = 1729, + SYNDR_SEPOLIA_L3 = 444444, + POLYNOMIAL_TESTNET = 80008, + BOB = 60808, + KINTO = 7887, + KINTO_DEVNET = 412346, + SIPHER_FUNKI_TESTNET = 3397901, + WINR = 777777, + BLAST = 81457, + BSC_TESTNET = 97, + POLYNOMIAL = 8008, + SYNDR = 404, + NEOX_TESTNET = 12227331, + NEOX_T4_TESTNET = 12227332, + NEOX = 47763, + GNOSIS = 100, + LINEA = 59144, + ZKEVM = 1101, + AVALANCHE = 43114, + XLAYER = 196, + MANTA_PACIFIC = 169, + POLTER_TESTNET = 631571, + POLYGON_AMOY = 80002, + OPBNB = 204, + GEIST = 63157, + ZERO_SEPOLIA = 4457845, + INTEROP_ALPHA_0 = 420120000, + INTEROP_ALPHA_1 = 420120001, +} diff --git a/src/chain-enums/chainSlug.ts b/src/chain-enums/chainSlug.ts new file mode 100644 index 00000000..6dd18494 --- /dev/null +++ b/src/chain-enums/chainSlug.ts @@ -0,0 +1,62 @@ +import { ChainId } from "./chainId"; + +export enum ChainSlug { + ARBITRUM = ChainId.ARBITRUM, + ARBITRUM_GOERLI = ChainId.ARBITRUM_GOERLI, + ARBITRUM_SEPOLIA = ChainId.ARBITRUM_SEPOLIA, + OPTIMISM = ChainId.OPTIMISM, + OPTIMISM_GOERLI = ChainId.OPTIMISM_GOERLI, + OPTIMISM_SEPOLIA = ChainId.OPTIMISM_SEPOLIA, + BSC = ChainId.BSC, + MAINNET = ChainId.MAINNET, + GOERLI = ChainId.GOERLI, + SEPOLIA = ChainId.SEPOLIA, + POLYGON_MAINNET = ChainId.POLYGON_MAINNET, + AEVO_TESTNET = ChainId.AEVO_TESTNET, + AEVO = ChainId.AEVO, + HARDHAT = ChainId.HARDHAT, + LYRA_TESTNET = ChainId.LYRA_TESTNET, + LYRA = ChainId.LYRA, + XAI_TESTNET = 1399904803, + SX_NETWORK_TESTNET = ChainId.SX_NETWORK_TESTNET, + SX_NETWORK = ChainId.SX_NETWORK, + MODE_TESTNET = ChainId.MODE_TESTNET, + VICTION_TESTNET = ChainId.VICTION_TESTNET, + CDK_TESTNET = ChainId.CDK_TESTNET, + BASE = ChainId.BASE, + BASE_SEPOLIA = ChainId.BASE_SEPOLIA, + MODE = ChainId.MODE, + ANCIENT8_TESTNET = ChainId.ANCIENT8_TESTNET, + ANCIENT8_TESTNET2 = ChainId.ANCIENT8_TESTNET2, + PARALLEL = ChainId.PARALLEL, + MANTLE = ChainId.MANTLE, + REYA_CRONOS = ChainId.REYA_CRONOS, + REYA = 1324967486, + SYNDR_SEPOLIA_L3 = ChainId.SYNDR_SEPOLIA_L3, + POLYNOMIAL_TESTNET = ChainId.POLYNOMIAL_TESTNET, + BOB = ChainId.BOB, + KINTO = ChainId.KINTO, + KINTO_DEVNET = ChainId.KINTO_DEVNET, + SIPHER_FUNKI_TESTNET = ChainId.SIPHER_FUNKI_TESTNET, + WINR = ChainId.WINR, + BLAST = ChainId.BLAST, + BSC_TESTNET = ChainId.BSC_TESTNET, + POLYNOMIAL = ChainId.POLYNOMIAL, + SYNDR = ChainId.SYNDR, + NEOX_TESTNET = ChainId.NEOX_TESTNET, + NEOX_T4_TESTNET = ChainId.NEOX_T4_TESTNET, + NEOX = ChainId.NEOX, + GNOSIS = ChainId.GNOSIS, + LINEA = ChainId.LINEA, + ZKEVM = ChainId.ZKEVM, + AVALANCHE = ChainId.AVALANCHE, + XLAYER = ChainId.XLAYER, + MANTA_PACIFIC = ChainId.MANTA_PACIFIC, + POLTER_TESTNET = ChainId.POLTER_TESTNET, + POLYGON_AMOY = ChainId.POLYGON_AMOY, + OPBNB = ChainId.OPBNB, + GEIST = ChainId.GEIST, + ZERO_SEPOLIA = ChainId.ZERO_SEPOLIA, + INTEROP_ALPHA_0 = ChainId.INTEROP_ALPHA_0, + INTEROP_ALPHA_1 = ChainId.INTEROP_ALPHA_1, +} diff --git a/src/chain-enums/chainSlugToHardhatChainName.ts b/src/chain-enums/chainSlugToHardhatChainName.ts new file mode 100644 index 00000000..02b6b0ae --- /dev/null +++ b/src/chain-enums/chainSlugToHardhatChainName.ts @@ -0,0 +1,63 @@ +import { ChainSlug } from "./chainSlug"; +import { HardhatChainName } from "./hardhatChainName"; + +export const chainSlugToHardhatChainName = { + [ChainSlug.ARBITRUM]: HardhatChainName.ARBITRUM, + [ChainSlug.ARBITRUM_GOERLI]: HardhatChainName.ARBITRUM_GOERLI, + [ChainSlug.ARBITRUM_SEPOLIA]: HardhatChainName.ARBITRUM_SEPOLIA, + [ChainSlug.OPTIMISM]: HardhatChainName.OPTIMISM, + [ChainSlug.OPTIMISM_GOERLI]: HardhatChainName.OPTIMISM_GOERLI, + [ChainSlug.OPTIMISM_SEPOLIA]: HardhatChainName.OPTIMISM_SEPOLIA, + [ChainSlug.BSC]: HardhatChainName.BSC, + [ChainSlug.MAINNET]: HardhatChainName.MAINNET, + [ChainSlug.GOERLI]: HardhatChainName.GOERLI, + [ChainSlug.SEPOLIA]: HardhatChainName.SEPOLIA, + [ChainSlug.POLYGON_MAINNET]: HardhatChainName.POLYGON_MAINNET, + [ChainSlug.AEVO_TESTNET]: HardhatChainName.AEVO_TESTNET, + [ChainSlug.AEVO]: HardhatChainName.AEVO, + [ChainSlug.HARDHAT]: HardhatChainName.HARDHAT, + [ChainSlug.LYRA_TESTNET]: HardhatChainName.LYRA_TESTNET, + [ChainSlug.LYRA]: HardhatChainName.LYRA, + [ChainSlug.XAI_TESTNET]: HardhatChainName.XAI_TESTNET, + [ChainSlug.SX_NETWORK_TESTNET]: HardhatChainName.SX_NETWORK_TESTNET, + [ChainSlug.SX_NETWORK]: HardhatChainName.SX_NETWORK, + [ChainSlug.MODE_TESTNET]: HardhatChainName.MODE_TESTNET, + [ChainSlug.VICTION_TESTNET]: HardhatChainName.VICTION_TESTNET, + [ChainSlug.CDK_TESTNET]: HardhatChainName.CDK_TESTNET, + [ChainSlug.BASE]: HardhatChainName.BASE, + [ChainSlug.BASE_SEPOLIA]: HardhatChainName.BASE_SEPOLIA, + [ChainSlug.MODE]: HardhatChainName.MODE, + [ChainSlug.ANCIENT8_TESTNET]: HardhatChainName.ANCIENT8_TESTNET, + [ChainSlug.ANCIENT8_TESTNET2]: HardhatChainName.ANCIENT8_TESTNET2, + [ChainSlug.PARALLEL]: HardhatChainName.PARALLEL, + [ChainSlug.MANTLE]: HardhatChainName.MANTLE, + [ChainSlug.REYA_CRONOS]: HardhatChainName.REYA_CRONOS, + [ChainSlug.REYA]: HardhatChainName.REYA, + [ChainSlug.SYNDR_SEPOLIA_L3]: HardhatChainName.SYNDR_SEPOLIA_L3, + [ChainSlug.POLYNOMIAL_TESTNET]: HardhatChainName.POLYNOMIAL_TESTNET, + [ChainSlug.BOB]: HardhatChainName.BOB, + [ChainSlug.KINTO]: HardhatChainName.KINTO, + [ChainSlug.KINTO_DEVNET]: HardhatChainName.KINTO_DEVNET, + [ChainSlug.SIPHER_FUNKI_TESTNET]: HardhatChainName.SIPHER_FUNKI_TESTNET, + [ChainSlug.WINR]: HardhatChainName.WINR, + [ChainSlug.BLAST]: HardhatChainName.BLAST, + [ChainSlug.BSC_TESTNET]: HardhatChainName.BSC_TESTNET, + [ChainSlug.POLYNOMIAL]: HardhatChainName.POLYNOMIAL, + [ChainSlug.SYNDR]: HardhatChainName.SYNDR, + [ChainSlug.NEOX_TESTNET]: HardhatChainName.NEOX_TESTNET, + [ChainSlug.NEOX_T4_TESTNET]: HardhatChainName.NEOX_T4_TESTNET, + [ChainSlug.NEOX]: HardhatChainName.NEOX, + [ChainSlug.GNOSIS]: HardhatChainName.GNOSIS, + [ChainSlug.LINEA]: HardhatChainName.LINEA, + [ChainSlug.ZKEVM]: HardhatChainName.ZKEVM, + [ChainSlug.AVALANCHE]: HardhatChainName.AVALANCHE, + [ChainSlug.XLAYER]: HardhatChainName.XLAYER, + [ChainSlug.MANTA_PACIFIC]: HardhatChainName.MANTA_PACIFIC, + [ChainSlug.POLTER_TESTNET]: HardhatChainName.POLTER_TESTNET, + [ChainSlug.POLYGON_AMOY]: HardhatChainName.POLYGON_AMOY, + [ChainSlug.OPBNB]: HardhatChainName.OPBNB, + [ChainSlug.GEIST]: HardhatChainName.GEIST, + [ChainSlug.ZERO_SEPOLIA]: HardhatChainName.ZERO_SEPOLIA, + [ChainSlug.INTEROP_ALPHA_0]: HardhatChainName.INTEROP_ALPHA_0, + [ChainSlug.INTEROP_ALPHA_1]: HardhatChainName.INTEROP_ALPHA_1, +}; diff --git a/src/chain-enums/chainSlugToId.ts b/src/chain-enums/chainSlugToId.ts new file mode 100644 index 00000000..07b27268 --- /dev/null +++ b/src/chain-enums/chainSlugToId.ts @@ -0,0 +1,63 @@ +import { ChainId } from "./chainId"; +import { ChainSlug } from "./chainSlug"; + +export const ChainSlugToId = { + [ChainSlug.ARBITRUM]: ChainId.ARBITRUM, + [ChainSlug.ARBITRUM_GOERLI]: ChainId.ARBITRUM_GOERLI, + [ChainSlug.ARBITRUM_SEPOLIA]: ChainId.ARBITRUM_SEPOLIA, + [ChainSlug.OPTIMISM]: ChainId.OPTIMISM, + [ChainSlug.OPTIMISM_GOERLI]: ChainId.OPTIMISM_GOERLI, + [ChainSlug.OPTIMISM_SEPOLIA]: ChainId.OPTIMISM_SEPOLIA, + [ChainSlug.BSC]: ChainId.BSC, + [ChainSlug.MAINNET]: ChainId.MAINNET, + [ChainSlug.GOERLI]: ChainId.GOERLI, + [ChainSlug.SEPOLIA]: ChainId.SEPOLIA, + [ChainSlug.POLYGON_MAINNET]: ChainId.POLYGON_MAINNET, + [ChainSlug.AEVO_TESTNET]: ChainId.AEVO_TESTNET, + [ChainSlug.AEVO]: ChainId.AEVO, + [ChainSlug.HARDHAT]: ChainId.HARDHAT, + [ChainSlug.LYRA_TESTNET]: ChainId.LYRA_TESTNET, + [ChainSlug.LYRA]: ChainId.LYRA, + [ChainSlug.XAI_TESTNET]: ChainId.XAI_TESTNET, + [ChainSlug.SX_NETWORK_TESTNET]: ChainId.SX_NETWORK_TESTNET, + [ChainSlug.SX_NETWORK]: ChainId.SX_NETWORK, + [ChainSlug.MODE_TESTNET]: ChainId.MODE_TESTNET, + [ChainSlug.VICTION_TESTNET]: ChainId.VICTION_TESTNET, + [ChainSlug.CDK_TESTNET]: ChainId.CDK_TESTNET, + [ChainSlug.BASE]: ChainId.BASE, + [ChainSlug.BASE_SEPOLIA]: ChainId.BASE_SEPOLIA, + [ChainSlug.MODE]: ChainId.MODE, + [ChainSlug.ANCIENT8_TESTNET]: ChainId.ANCIENT8_TESTNET, + [ChainSlug.ANCIENT8_TESTNET2]: ChainId.ANCIENT8_TESTNET2, + [ChainSlug.PARALLEL]: ChainId.PARALLEL, + [ChainSlug.MANTLE]: ChainId.MANTLE, + [ChainSlug.REYA_CRONOS]: ChainId.REYA_CRONOS, + [ChainSlug.REYA]: ChainId.REYA, + [ChainSlug.SYNDR_SEPOLIA_L3]: ChainId.SYNDR_SEPOLIA_L3, + [ChainSlug.POLYNOMIAL_TESTNET]: ChainId.POLYNOMIAL_TESTNET, + [ChainSlug.BOB]: ChainId.BOB, + [ChainSlug.KINTO]: ChainId.KINTO, + [ChainSlug.KINTO_DEVNET]: ChainId.KINTO_DEVNET, + [ChainSlug.SIPHER_FUNKI_TESTNET]: ChainId.SIPHER_FUNKI_TESTNET, + [ChainSlug.WINR]: ChainId.WINR, + [ChainSlug.BLAST]: ChainId.BLAST, + [ChainSlug.BSC_TESTNET]: ChainId.BSC_TESTNET, + [ChainSlug.POLYNOMIAL]: ChainId.POLYNOMIAL, + [ChainSlug.SYNDR]: ChainId.SYNDR, + [ChainSlug.NEOX_TESTNET]: ChainId.NEOX_TESTNET, + [ChainSlug.NEOX_T4_TESTNET]: ChainId.NEOX_T4_TESTNET, + [ChainSlug.NEOX]: ChainId.NEOX, + [ChainSlug.GNOSIS]: ChainId.GNOSIS, + [ChainSlug.LINEA]: ChainId.LINEA, + [ChainSlug.ZKEVM]: ChainId.ZKEVM, + [ChainSlug.AVALANCHE]: ChainId.AVALANCHE, + [ChainSlug.XLAYER]: ChainId.XLAYER, + [ChainSlug.MANTA_PACIFIC]: ChainId.MANTA_PACIFIC, + [ChainSlug.POLTER_TESTNET]: ChainId.POLTER_TESTNET, + [ChainSlug.POLYGON_AMOY]: ChainId.POLYGON_AMOY, + [ChainSlug.OPBNB]: ChainId.OPBNB, + [ChainSlug.GEIST]: ChainId.GEIST, + [ChainSlug.ZERO_SEPOLIA]: ChainId.ZERO_SEPOLIA, + [ChainSlug.INTEROP_ALPHA_0]: ChainId.INTEROP_ALPHA_0, + [ChainSlug.INTEROP_ALPHA_1]: ChainId.INTEROP_ALPHA_1, +}; diff --git a/src/chain-enums/chainSlugToKey.ts b/src/chain-enums/chainSlugToKey.ts new file mode 100644 index 00000000..43c601a4 --- /dev/null +++ b/src/chain-enums/chainSlugToKey.ts @@ -0,0 +1,63 @@ +import { ChainSlug } from "./chainSlug"; +import { HardhatChainName } from "./hardhatChainName"; + +export const ChainSlugToKey = { + [ChainSlug.ARBITRUM]: HardhatChainName.ARBITRUM, + [ChainSlug.ARBITRUM_GOERLI]: HardhatChainName.ARBITRUM_GOERLI, + [ChainSlug.ARBITRUM_SEPOLIA]: HardhatChainName.ARBITRUM_SEPOLIA, + [ChainSlug.OPTIMISM]: HardhatChainName.OPTIMISM, + [ChainSlug.OPTIMISM_GOERLI]: HardhatChainName.OPTIMISM_GOERLI, + [ChainSlug.OPTIMISM_SEPOLIA]: HardhatChainName.OPTIMISM_SEPOLIA, + [ChainSlug.BSC]: HardhatChainName.BSC, + [ChainSlug.MAINNET]: HardhatChainName.MAINNET, + [ChainSlug.GOERLI]: HardhatChainName.GOERLI, + [ChainSlug.SEPOLIA]: HardhatChainName.SEPOLIA, + [ChainSlug.POLYGON_MAINNET]: HardhatChainName.POLYGON_MAINNET, + [ChainSlug.AEVO_TESTNET]: HardhatChainName.AEVO_TESTNET, + [ChainSlug.AEVO]: HardhatChainName.AEVO, + [ChainSlug.HARDHAT]: HardhatChainName.HARDHAT, + [ChainSlug.LYRA_TESTNET]: HardhatChainName.LYRA_TESTNET, + [ChainSlug.LYRA]: HardhatChainName.LYRA, + [ChainSlug.XAI_TESTNET]: HardhatChainName.XAI_TESTNET, + [ChainSlug.SX_NETWORK_TESTNET]: HardhatChainName.SX_NETWORK_TESTNET, + [ChainSlug.SX_NETWORK]: HardhatChainName.SX_NETWORK, + [ChainSlug.MODE_TESTNET]: HardhatChainName.MODE_TESTNET, + [ChainSlug.VICTION_TESTNET]: HardhatChainName.VICTION_TESTNET, + [ChainSlug.CDK_TESTNET]: HardhatChainName.CDK_TESTNET, + [ChainSlug.BASE]: HardhatChainName.BASE, + [ChainSlug.BASE_SEPOLIA]: HardhatChainName.BASE_SEPOLIA, + [ChainSlug.MODE]: HardhatChainName.MODE, + [ChainSlug.ANCIENT8_TESTNET]: HardhatChainName.ANCIENT8_TESTNET, + [ChainSlug.ANCIENT8_TESTNET2]: HardhatChainName.ANCIENT8_TESTNET2, + [ChainSlug.PARALLEL]: HardhatChainName.PARALLEL, + [ChainSlug.MANTLE]: HardhatChainName.MANTLE, + [ChainSlug.REYA_CRONOS]: HardhatChainName.REYA_CRONOS, + [ChainSlug.REYA]: HardhatChainName.REYA, + [ChainSlug.SYNDR_SEPOLIA_L3]: HardhatChainName.SYNDR_SEPOLIA_L3, + [ChainSlug.POLYNOMIAL_TESTNET]: HardhatChainName.POLYNOMIAL_TESTNET, + [ChainSlug.BOB]: HardhatChainName.BOB, + [ChainSlug.KINTO]: HardhatChainName.KINTO, + [ChainSlug.KINTO_DEVNET]: HardhatChainName.KINTO_DEVNET, + [ChainSlug.SIPHER_FUNKI_TESTNET]: HardhatChainName.SIPHER_FUNKI_TESTNET, + [ChainSlug.WINR]: HardhatChainName.WINR, + [ChainSlug.BLAST]: HardhatChainName.BLAST, + [ChainSlug.BSC_TESTNET]: HardhatChainName.BSC_TESTNET, + [ChainSlug.POLYNOMIAL]: HardhatChainName.POLYNOMIAL, + [ChainSlug.SYNDR]: HardhatChainName.SYNDR, + [ChainSlug.NEOX_TESTNET]: HardhatChainName.NEOX_TESTNET, + [ChainSlug.NEOX_T4_TESTNET]: HardhatChainName.NEOX_T4_TESTNET, + [ChainSlug.NEOX]: HardhatChainName.NEOX, + [ChainSlug.GNOSIS]: HardhatChainName.GNOSIS, + [ChainSlug.LINEA]: HardhatChainName.LINEA, + [ChainSlug.ZKEVM]: HardhatChainName.ZKEVM, + [ChainSlug.AVALANCHE]: HardhatChainName.AVALANCHE, + [ChainSlug.XLAYER]: HardhatChainName.XLAYER, + [ChainSlug.MANTA_PACIFIC]: HardhatChainName.MANTA_PACIFIC, + [ChainSlug.POLTER_TESTNET]: HardhatChainName.POLTER_TESTNET, + [ChainSlug.POLYGON_AMOY]: HardhatChainName.POLYGON_AMOY, + [ChainSlug.OPBNB]: HardhatChainName.OPBNB, + [ChainSlug.GEIST]: HardhatChainName.GEIST, + [ChainSlug.ZERO_SEPOLIA]: HardhatChainName.ZERO_SEPOLIA, + [ChainSlug.INTEROP_ALPHA_0]: HardhatChainName.INTEROP_ALPHA_0, + [ChainSlug.INTEROP_ALPHA_1]: HardhatChainName.INTEROP_ALPHA_1, +}; diff --git a/src/chain-enums/currency.ts b/src/chain-enums/currency.ts new file mode 100644 index 00000000..1f9448db --- /dev/null +++ b/src/chain-enums/currency.ts @@ -0,0 +1,22 @@ +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"], +}; diff --git a/src/chain-enums/ethLikeChains.ts b/src/chain-enums/ethLikeChains.ts new file mode 100644 index 00000000..dde62f66 --- /dev/null +++ b/src/chain-enums/ethLikeChains.ts @@ -0,0 +1,29 @@ +import { ChainSlug } from "./chainSlug"; + +// chains having constant gas limits +export const ethLikeChains = [ + ChainSlug.MAINNET, + ChainSlug.BSC, + ChainSlug.POLYGON_MAINNET, + ChainSlug.SEPOLIA, + ChainSlug.SX_NETWORK, + ChainSlug.SX_NETWORK_TESTNET, + ChainSlug.ANCIENT8_TESTNET, + ChainSlug.ANCIENT8_TESTNET2, + ChainSlug.REYA_CRONOS, + ChainSlug.REYA, + ChainSlug.GOERLI, + ChainSlug.VICTION_TESTNET, + ChainSlug.SYNDR_SEPOLIA_L3, + ChainSlug.BSC_TESTNET, + ChainSlug.NEOX_TESTNET, + ChainSlug.NEOX_T4_TESTNET, + ChainSlug.NEOX, + ChainSlug.GNOSIS, + ChainSlug.LINEA, + ChainSlug.ZKEVM, + ChainSlug.AVALANCHE, + ChainSlug.POLYGON_AMOY, + ChainSlug.INTEROP_ALPHA_0, + ChainSlug.INTEROP_ALPHA_1, +]; diff --git a/src/chain-enums/hardhatChainName.ts b/src/chain-enums/hardhatChainName.ts new file mode 100644 index 00000000..c74be92e --- /dev/null +++ b/src/chain-enums/hardhatChainName.ts @@ -0,0 +1,60 @@ +export enum HardhatChainName { + ARBITRUM = "arbitrum", + ARBITRUM_GOERLI = "arbitrum_goerli", + ARBITRUM_SEPOLIA = "arbitrum_sepolia", + OPTIMISM = "optimism", + OPTIMISM_GOERLI = "optimism_goerli", + OPTIMISM_SEPOLIA = "optimism_sepolia", + BSC = "bsc", + MAINNET = "mainnet", + GOERLI = "goerli", + SEPOLIA = "sepolia", + POLYGON_MAINNET = "polygon_mainnet", + AEVO_TESTNET = "aevo_testnet", + AEVO = "aevo", + LYRA_TESTNET = "lyra_testnet", + LYRA = "lyra", + XAI_TESTNET = "xai_testnet", + SX_NETWORK_TESTNET = "sxn_testnet", + SX_NETWORK = "sxn", + MODE_TESTNET = "mode_testnet", + VICTION_TESTNET = "viction_testnet", + CDK_TESTNET = "cdk_testnet", + HARDHAT = "hardhat", + BASE = "base", + BASE_SEPOLIA = "base_sepolia", + MODE = "mode", + ANCIENT8_TESTNET = "ancient8_testnet", + ANCIENT8_TESTNET2 = "ancient8_testnet2", + PARALLEL = "parallel", + MANTLE = "mantle", + REYA_CRONOS = "reya_cronos", + REYA = "reya", + SYNDR_SEPOLIA_L3 = "syndr_sepolia_l3", + POLYNOMIAL_TESTNET = "polynomial_testnet", + BOB = "bob", + KINTO = "kinto", + KINTO_DEVNET = "kinto_devnet", + SIPHER_FUNKI_TESTNET = "sipher_funki_testnet", + WINR = "winr", + BLAST = "blast", + BSC_TESTNET = "bsc_testnet", + POLYNOMIAL = "polynomial", + SYNDR = "syndr", + NEOX_TESTNET = "neox_testnet", + NEOX_T4_TESTNET = "neox_t4_testnet", + NEOX = "neox", + GNOSIS = "gnosis", + LINEA = "linea", + ZKEVM = "zkevm", + AVALANCHE = "avalanche", + XLAYER = "xlayer", + MANTA_PACIFIC = "manta_pacific", + POLTER_TESTNET = "polter_testnet", + POLYGON_AMOY = "polygon_amoy", + OPBNB = "opbnb", + GEIST = "geist", + ZERO_SEPOLIA = "zero_sepolia", + INTEROP_ALPHA_0 = "interop_alpha_0", + INTEROP_ALPHA_1 = "interop_alpha_1", +} diff --git a/src/chain-enums/hardhatChainNameToSlug.ts b/src/chain-enums/hardhatChainNameToSlug.ts new file mode 100644 index 00000000..110b45c9 --- /dev/null +++ b/src/chain-enums/hardhatChainNameToSlug.ts @@ -0,0 +1,63 @@ +import { ChainSlug } from "./chainSlug"; +import { HardhatChainName } from "./hardhatChainName"; + +export const hardhatChainNameToSlug = { + [HardhatChainName.ARBITRUM]: ChainSlug.ARBITRUM, + [HardhatChainName.ARBITRUM_GOERLI]: ChainSlug.ARBITRUM_GOERLI, + [HardhatChainName.ARBITRUM_SEPOLIA]: ChainSlug.ARBITRUM_SEPOLIA, + [HardhatChainName.OPTIMISM]: ChainSlug.OPTIMISM, + [HardhatChainName.OPTIMISM_GOERLI]: ChainSlug.OPTIMISM_GOERLI, + [HardhatChainName.OPTIMISM_SEPOLIA]: ChainSlug.OPTIMISM_SEPOLIA, + [HardhatChainName.BSC]: ChainSlug.BSC, + [HardhatChainName.MAINNET]: ChainSlug.MAINNET, + [HardhatChainName.GOERLI]: ChainSlug.GOERLI, + [HardhatChainName.SEPOLIA]: ChainSlug.SEPOLIA, + [HardhatChainName.POLYGON_MAINNET]: ChainSlug.POLYGON_MAINNET, + [HardhatChainName.AEVO_TESTNET]: ChainSlug.AEVO_TESTNET, + [HardhatChainName.AEVO]: ChainSlug.AEVO, + [HardhatChainName.HARDHAT]: ChainSlug.HARDHAT, + [HardhatChainName.LYRA_TESTNET]: ChainSlug.LYRA_TESTNET, + [HardhatChainName.LYRA]: ChainSlug.LYRA, + [HardhatChainName.XAI_TESTNET]: ChainSlug.XAI_TESTNET, + [HardhatChainName.SX_NETWORK_TESTNET]: ChainSlug.SX_NETWORK_TESTNET, + [HardhatChainName.SX_NETWORK]: ChainSlug.SX_NETWORK, + [HardhatChainName.MODE_TESTNET]: ChainSlug.MODE_TESTNET, + [HardhatChainName.VICTION_TESTNET]: ChainSlug.VICTION_TESTNET, + [HardhatChainName.CDK_TESTNET]: ChainSlug.CDK_TESTNET, + [HardhatChainName.BASE]: ChainSlug.BASE, + [HardhatChainName.BASE_SEPOLIA]: ChainSlug.BASE_SEPOLIA, + [HardhatChainName.MODE]: ChainSlug.MODE, + [HardhatChainName.ANCIENT8_TESTNET]: ChainSlug.ANCIENT8_TESTNET, + [HardhatChainName.ANCIENT8_TESTNET2]: ChainSlug.ANCIENT8_TESTNET2, + [HardhatChainName.PARALLEL]: ChainSlug.PARALLEL, + [HardhatChainName.MANTLE]: ChainSlug.MANTLE, + [HardhatChainName.REYA_CRONOS]: ChainSlug.REYA_CRONOS, + [HardhatChainName.REYA]: ChainSlug.REYA, + [HardhatChainName.SYNDR_SEPOLIA_L3]: ChainSlug.SYNDR_SEPOLIA_L3, + [HardhatChainName.POLYNOMIAL_TESTNET]: ChainSlug.POLYNOMIAL_TESTNET, + [HardhatChainName.BOB]: ChainSlug.BOB, + [HardhatChainName.KINTO]: ChainSlug.KINTO, + [HardhatChainName.KINTO_DEVNET]: ChainSlug.KINTO_DEVNET, + [HardhatChainName.SIPHER_FUNKI_TESTNET]: ChainSlug.SIPHER_FUNKI_TESTNET, + [HardhatChainName.WINR]: ChainSlug.WINR, + [HardhatChainName.BLAST]: ChainSlug.BLAST, + [HardhatChainName.BSC_TESTNET]: ChainSlug.BSC_TESTNET, + [HardhatChainName.POLYNOMIAL]: ChainSlug.POLYNOMIAL, + [HardhatChainName.SYNDR]: ChainSlug.SYNDR, + [HardhatChainName.NEOX_TESTNET]: ChainSlug.NEOX_TESTNET, + [HardhatChainName.NEOX_T4_TESTNET]: ChainSlug.NEOX_T4_TESTNET, + [HardhatChainName.NEOX]: ChainSlug.NEOX, + [HardhatChainName.GNOSIS]: ChainSlug.GNOSIS, + [HardhatChainName.LINEA]: ChainSlug.LINEA, + [HardhatChainName.ZKEVM]: ChainSlug.ZKEVM, + [HardhatChainName.AVALANCHE]: ChainSlug.AVALANCHE, + [HardhatChainName.XLAYER]: ChainSlug.XLAYER, + [HardhatChainName.MANTA_PACIFIC]: ChainSlug.MANTA_PACIFIC, + [HardhatChainName.POLTER_TESTNET]: ChainSlug.POLTER_TESTNET, + [HardhatChainName.POLYGON_AMOY]: ChainSlug.POLYGON_AMOY, + [HardhatChainName.OPBNB]: ChainSlug.OPBNB, + [HardhatChainName.GEIST]: ChainSlug.GEIST, + [HardhatChainName.ZERO_SEPOLIA]: ChainSlug.ZERO_SEPOLIA, + [HardhatChainName.INTEROP_ALPHA_0]: ChainSlug.INTEROP_ALPHA_0, + [HardhatChainName.INTEROP_ALPHA_1]: ChainSlug.INTEROP_ALPHA_1, +}; diff --git a/src/chain-enums/index.ts b/src/chain-enums/index.ts new file mode 100644 index 00000000..417392a0 --- /dev/null +++ b/src/chain-enums/index.ts @@ -0,0 +1,17 @@ +export * from "./arbChains"; +export * from "./arbL3Chains"; +export * from "./chainId"; +export * from "./chainSlug"; +export * from "./chainSlugToHardhatChainName"; +export * from "./chainSlugToId"; +export * from "./chainSlugToKey"; +export * from "./currency"; +export * from "./ethLikeChains"; +export * from "./hardhatChainName"; +export * from "./hardhatChainNameToSlug"; +export * from "./mainnetIds"; +export * from "./native-tokens"; +export * from "./opStackChains"; +export * from "./polygonCDKChains"; +export * from "./testnetIds"; +export * from "./zkStackChain"; diff --git a/src/chain-enums/mainnetIds.ts b/src/chain-enums/mainnetIds.ts new file mode 100644 index 00000000..eaaeced7 --- /dev/null +++ b/src/chain-enums/mainnetIds.ts @@ -0,0 +1,32 @@ +import { ChainSlug } from "./chainSlug"; + +export const MainnetIds: ChainSlug[] = [ + ChainSlug.MAINNET, + ChainSlug.POLYGON_MAINNET, + ChainSlug.ARBITRUM, + ChainSlug.OPTIMISM, + ChainSlug.BSC, + ChainSlug.AEVO, + ChainSlug.LYRA, + ChainSlug.BASE, + ChainSlug.MODE, + ChainSlug.PARALLEL, + ChainSlug.MANTLE, + ChainSlug.REYA, + ChainSlug.SX_NETWORK, + ChainSlug.BOB, + ChainSlug.KINTO, + ChainSlug.WINR, + ChainSlug.BLAST, + ChainSlug.POLYNOMIAL, + ChainSlug.SYNDR, + ChainSlug.NEOX, + ChainSlug.GNOSIS, + ChainSlug.LINEA, + ChainSlug.ZKEVM, + ChainSlug.AVALANCHE, + ChainSlug.XLAYER, + ChainSlug.MANTA_PACIFIC, + ChainSlug.OPBNB, + ChainSlug.GEIST, +]; diff --git a/src/chain-enums/native-tokens.ts b/src/chain-enums/native-tokens.ts new file mode 100644 index 00000000..1e70d1bf --- /dev/null +++ b/src/chain-enums/native-tokens.ts @@ -0,0 +1,15 @@ +// 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", +} diff --git a/src/chain-enums/opStackChains.ts b/src/chain-enums/opStackChains.ts new file mode 100644 index 00000000..d1e6aa3e --- /dev/null +++ b/src/chain-enums/opStackChains.ts @@ -0,0 +1,24 @@ +import { ChainSlug } from "./chainSlug"; + +export const opStackL2Chain = [ + ChainSlug.AEVO, + ChainSlug.AEVO_TESTNET, + ChainSlug.LYRA, + ChainSlug.MODE_TESTNET, + ChainSlug.LYRA_TESTNET, + ChainSlug.MODE, + ChainSlug.OPTIMISM, + ChainSlug.OPTIMISM_SEPOLIA, + ChainSlug.OPTIMISM_GOERLI, + ChainSlug.BASE, + ChainSlug.BASE_SEPOLIA, + ChainSlug.MANTLE, + ChainSlug.POLYNOMIAL_TESTNET, + ChainSlug.BOB, + ChainSlug.SIPHER_FUNKI_TESTNET, + ChainSlug.BLAST, + ChainSlug.POLYNOMIAL, + ChainSlug.MANTA_PACIFIC, + ChainSlug.POLTER_TESTNET, + ChainSlug.OPBNB, +]; diff --git a/src/chain-enums/polygonCDKChains.ts b/src/chain-enums/polygonCDKChains.ts new file mode 100644 index 00000000..4a29a7ab --- /dev/null +++ b/src/chain-enums/polygonCDKChains.ts @@ -0,0 +1,10 @@ +import { ChainSlug } from "./chainSlug"; + +export const polygonCDKChains = [ + ChainSlug.CDK_TESTNET, + ChainSlug.ANCIENT8_TESTNET2, + ChainSlug.SX_NETWORK_TESTNET, + ChainSlug.SX_NETWORK, + ChainSlug.XAI_TESTNET, + ChainSlug.XLAYER, +]; diff --git a/src/chain-enums/testnetIds.ts b/src/chain-enums/testnetIds.ts new file mode 100644 index 00000000..efe3e6d4 --- /dev/null +++ b/src/chain-enums/testnetIds.ts @@ -0,0 +1,33 @@ +import { ChainSlug } from "./chainSlug"; + +export const TestnetIds: ChainSlug[] = [ + ChainSlug.GOERLI, + ChainSlug.SEPOLIA, + ChainSlug.ARBITRUM_GOERLI, + ChainSlug.ARBITRUM_SEPOLIA, + ChainSlug.OPTIMISM_GOERLI, + ChainSlug.OPTIMISM_SEPOLIA, + ChainSlug.AEVO_TESTNET, + ChainSlug.LYRA_TESTNET, + ChainSlug.XAI_TESTNET, + ChainSlug.SX_NETWORK_TESTNET, + ChainSlug.MODE_TESTNET, + ChainSlug.VICTION_TESTNET, + ChainSlug.CDK_TESTNET, + ChainSlug.ANCIENT8_TESTNET, + ChainSlug.ANCIENT8_TESTNET2, + ChainSlug.REYA_CRONOS, + ChainSlug.SYNDR_SEPOLIA_L3, + ChainSlug.POLYNOMIAL_TESTNET, + ChainSlug.KINTO_DEVNET, + ChainSlug.SIPHER_FUNKI_TESTNET, + ChainSlug.BSC_TESTNET, + ChainSlug.NEOX_TESTNET, + ChainSlug.NEOX_T4_TESTNET, + ChainSlug.POLTER_TESTNET, + ChainSlug.POLYGON_AMOY, + ChainSlug.ZERO_SEPOLIA, + ChainSlug.BASE_SEPOLIA, + ChainSlug.INTEROP_ALPHA_0, + ChainSlug.INTEROP_ALPHA_1, +]; diff --git a/src/chain-enums/zkStackChain.ts b/src/chain-enums/zkStackChain.ts new file mode 100644 index 00000000..70ad4151 --- /dev/null +++ b/src/chain-enums/zkStackChain.ts @@ -0,0 +1,3 @@ +import { ChainSlug } from "./chainSlug"; + +export const zkStackChain = [ChainSlug.ZERO_SEPOLIA]; diff --git a/src/enums.ts b/src/enums.ts new file mode 100644 index 00000000..87a79cd5 --- /dev/null +++ b/src/enums.ts @@ -0,0 +1,74 @@ +export enum DeploymentMode { + LOCAL = "local", + DEV = "dev", + PROD = "prod", + STAGE = "stage", +} + +export enum Events { + // Socket + ExecutionSuccess = "ExecutionSuccess", + ExecutionFailed = "ExecutionFailed", + PlugConnected = "PlugConnected", + AppGatewayCallRequested = "AppGatewayCallRequested", + + // FeesPlug + FeesDeposited = "FeesDeposited", + + // WatcherPrecompile + CalledAppGateway = "CalledAppGateway", + QueryRequested = "QueryRequested", + FinalizeRequested = "FinalizeRequested", + PromiseResolved = "PromiseResolved", + PromiseNotResolved = "PromiseNotResolved", + TimeoutRequested = "TimeoutRequested", + TimeoutResolved = "TimeoutResolved", + RequestSubmitted = "RequestSubmitted", + Finalized = "Finalized", + MarkedRevert = "MarkedRevert", + // AuctionManager + AuctionEnded = "AuctionEnded", + AuctionRestarted = "AuctionRestarted", + + // DeliveryHelper + PayloadSubmitted = "PayloadSubmitted", + PayloadAsyncRequested = "PayloadAsyncRequested", + FeesIncreased = "FeesIncreased", + RequestCancelled = "RequestCancelled", +} + +export enum Contracts { + Socket = "Socket", + FeesPlug = "FeesPlug", + WatcherPrecompile = "WatcherPrecompile", + WatcherPrecompileLimits = "WatcherPrecompileLimits", + WatcherPrecompileConfig = "WatcherPrecompileConfig", + AuctionManager = "AuctionManager", + DeliveryHelper = "DeliveryHelper", +} + +export enum CallType { + READ, + WRITE, + DEPLOY, + WITHDRAW, +} + +export enum CallTypeNames { + READ = "READ", + WRITE = "WRITE", + DEPLOY = "DEPLOY", + WITHDRAW = "WITHDRAW", +} + +export enum FinalityBucket { + LOW, // low confirmations / latest + MEDIUM, // medium confirmations / data posted + HIGH, // high confirmations / data posted and finalized +} + +export enum FinalityBucketNames { + LOW = "LOW", + MEDIUM = "MEDIUM", + HIGH = "HIGH", +} diff --git a/src/events.ts b/src/events.ts new file mode 100644 index 00000000..1893f5b0 --- /dev/null +++ b/src/events.ts @@ -0,0 +1,34 @@ +import { Events } from "./enums"; + +export const socketEvents = [ + Events.ExecutionSuccess, + Events.ExecutionFailed, + Events.PlugConnected, + Events.AppGatewayCallRequested, +]; + +export const feesPlugEvents = [Events.FeesDeposited]; + +export const watcherPrecompileEvents = [ + Events.CalledAppGateway, + Events.RequestSubmitted, + Events.QueryRequested, + Events.FinalizeRequested, + Events.Finalized, + Events.PromiseResolved, + Events.PromiseNotResolved, + Events.TimeoutRequested, + Events.TimeoutResolved, + Events.MarkedRevert, +]; + +export const deliveryHelperEvents = [ + Events.PayloadSubmitted, + Events.FeesIncreased, + Events.RequestCancelled, +]; + +export const auctionManagerEvents = [ + Events.AuctionEnded, + Events.AuctionRestarted, +]; diff --git a/src/finality.ts b/src/finality.ts new file mode 100644 index 00000000..e9693f7b --- /dev/null +++ b/src/finality.ts @@ -0,0 +1,52 @@ +import { ChainSlug } from "./chain-enums"; +import { ChainFinalityBlocks, FinalityBucket } from "./types"; + +export const DEFAULT_FINALITY_BUCKET = FinalityBucket.LOW; + +export const defaultFinalityBlocks: ChainFinalityBlocks = { + [FinalityBucket.LOW]: 1, + [FinalityBucket.MEDIUM]: "safe", + [FinalityBucket.HIGH]: "finalized", +}; + +export const getFinalityBlocks = ( + chainSlug: ChainSlug +): ChainFinalityBlocks => { + return finalityBlockOverrides[chainSlug] ?? defaultFinalityBlocks; +}; + +export const finalityBlockOverrides: { + [chainSlug in ChainSlug]?: ChainFinalityBlocks; +} = { + [ChainSlug.MAINNET]: { + [FinalityBucket.LOW]: 6, + [FinalityBucket.MEDIUM]: "safe", + [FinalityBucket.HIGH]: "finalized", + }, + + [ChainSlug.POLYGON_MAINNET]: { + [FinalityBucket.LOW]: 256, + [FinalityBucket.MEDIUM]: 512, + [FinalityBucket.HIGH]: 1000, + }, + [ChainSlug.NEOX_TESTNET]: { + [FinalityBucket.LOW]: 1, + [FinalityBucket.MEDIUM]: 10, + [FinalityBucket.HIGH]: 100, + }, + [ChainSlug.NEOX_T4_TESTNET]: { + [FinalityBucket.LOW]: 1, + [FinalityBucket.MEDIUM]: 10, + [FinalityBucket.HIGH]: 100, + }, + [ChainSlug.NEOX]: { + [FinalityBucket.LOW]: 1, + [FinalityBucket.MEDIUM]: 10, + [FinalityBucket.HIGH]: 100, + }, + [ChainSlug.LINEA]: { + [FinalityBucket.LOW]: 1, + [FinalityBucket.MEDIUM]: 10, + [FinalityBucket.HIGH]: 100, + }, +}; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..24e89c47 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,5 @@ +export * from "./chain-enums"; +export * from "./enums"; +export * from "./events"; +export * from "./finality"; +export * from "./types"; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 00000000..8a738fbd --- /dev/null +++ b/src/types.ts @@ -0,0 +1,55 @@ +import { FinalityBucket } from "./enums"; + +export enum ChainType { + opStackL2Chain = "opStackL2Chain", + arbL3Chain = "arbL3Chain", + arbChain = "arbChain", + polygonCDKChain = "polygonCDKChain", + zkStackChain = "zkStackChain", + default = "default", +} + +export type ChainFinalityBlocks = { + [FinalityBucket.LOW]: number | "safe" | "finalized"; + [FinalityBucket.MEDIUM]: number | "safe" | "finalized"; + [FinalityBucket.HIGH]: number | "safe" | "finalized"; +}; + +export type ChainAddressesObj = { + Socket: string; + SocketBatcher: string; + FastSwitchboard: string; + FeesPlug: string; + ContractFactoryPlug: string; + startBlock: number; +}; + +export type EVMxAddressesObj = { + AddressResolver: string; + WatcherPrecompile: string; + WatcherPrecompileLimits: string; + WatcherPrecompileConfig: string; + AuctionManager: string; + FeesManager: string; + DeliveryHelper: string; + startBlock: number; +}; + +export type S3Config = { + version: string; + chains: { [chainSlug: number]: ChainConfig }; + supportedChainSlugs: number[]; +}; + +export type ChainConfig = { + eventBlockRangePerCron: number; + rpc: string | undefined; + wssRpc: string | undefined; + confirmations: number; + eventBlockRange: number; + addresses: ChainAddressesObj | EVMxAddressesObj; + finalityBlocks: ChainFinalityBlocks; + chainType: ChainType; +}; + +export { FinalityBucket }; diff --git a/test/DeliveryHelper.t.sol b/test/DeliveryHelper.t.sol index 597c113f..09ecc39d 100644 --- a/test/DeliveryHelper.t.sol +++ b/test/DeliveryHelper.t.sol @@ -24,18 +24,19 @@ contract DeliveryHelperTest is SetupTest { AuctionManager auctionManager; event PayloadSubmitted( - bytes32 indexed asyncId, + uint40 indexed requestCount, address indexed appGateway, - PayloadDetails[] payloads, + PayloadSubmitParams[] payloadSubmitParams, Fees fees, - uint256 auctionEndDelay + address auctionManager, + bool onlyReadRequests ); - event BidPlaced(bytes32 indexed asyncId, Bid bid); - event AuctionEnded(bytes32 indexed asyncId, Bid winningBid); - event BatchCancelled(bytes32 indexed asyncId); - event FinalizeRequested(bytes32 indexed payloadId, AsyncRequest asyncRequest); + event BidPlaced(uint40 requestCount, Bid bid); + event AuctionEnded(uint40 indexed requestCount, Bid winningBid); + event RequestCancelled(uint40 indexed requestCount); event QueryRequested(uint32 chainSlug, address targetAddress, bytes32 payloadId, bytes payload); + //////////////////////////////////// Setup //////////////////////////////////// function setUpDeliveryHelper() internal { // core deployEVMxCore(); @@ -49,7 +50,8 @@ contract DeliveryHelperTest is SetupTest { FeesManager.initialize.selector, address(addressResolver), watcherEOA, - evmxSlug + evmxSlug, + FAST ); vm.expectEmit(true, true, true, false); @@ -66,7 +68,7 @@ contract DeliveryHelperTest is SetupTest { auctionEndDelaySeconds, address(addressResolver), owner, - version + maxReAuctionCount ); vm.expectEmit(true, true, true, false); emit Initialized(version); @@ -102,10 +104,12 @@ contract DeliveryHelperTest is SetupTest { addressResolver.setFeesManager(address(feesManager)); vm.stopPrank(); + hoax(owner); + auctionManager.grantRole(TRANSMITTER_ROLE, transmitterEOA); + // chain core contracts arbConfig = deploySocket(arbChainSlug); optConfig = deploySocket(optChainSlug); - connectDeliveryHelper(); } @@ -161,38 +165,13 @@ contract DeliveryHelperTest is SetupTest { }); bytes memory watcherSignature = _createWatcherSignature( - abi.encode(IWatcherPrecompile.setAppGateways.selector, gateways) + address(watcherPrecompileConfig), + abi.encode(IWatcherPrecompileConfig.setAppGateways.selector, gateways) ); - - watcherPrecompile.setAppGateways(gateways, signatureNonce++, watcherSignature); + watcherPrecompileConfig.setAppGateways(gateways, signatureNonce++, watcherSignature); } - function setLimit(address appGateway_) internal { - UpdateLimitParams[] memory params = new UpdateLimitParams[](3); - params[0] = UpdateLimitParams({ - limitType: QUERY, - appGateway: appGateway_, - maxLimit: 10000000000000000000000, - ratePerSecond: 10000000000000000000000 - }); - params[1] = UpdateLimitParams({ - limitType: SCHEDULE, - appGateway: appGateway_, - maxLimit: 10000000000000000000000, - ratePerSecond: 10000000000000000000000 - }); - params[2] = UpdateLimitParams({ - limitType: FINALIZE, - appGateway: appGateway_, - maxLimit: 10000000000000000000000, - ratePerSecond: 10000000000000000000000 - }); - - hoax(watcherEOA); - watcherPrecompile.updateLimitParams(params); - - skip(100); - } + //////////////////////////////////// Fees //////////////////////////////////// function depositFees(address appGateway_, Fees memory fees_) internal { SocketContracts memory socketConfig = getSocketConfig(fees_.feePoolChain); @@ -208,20 +187,11 @@ contract DeliveryHelperTest is SetupTest { fees_.feePoolToken, fees_.amount ); + bytes32 digest = keccak256( abi.encode(address(feesManager), evmxSlug, signatureNonce, bytesInput) ); - - digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest)); - (uint8 sigV, bytes32 sigR, bytes32 sigS) = vm.sign(watcherPrivateKey, digest); - bytes memory sig = new bytes(65); - bytes1 v32 = bytes1(sigV); - - assembly { - mstore(add(sig, 96), v32) - mstore(add(sig, 32), sigR) - mstore(add(sig, 64), sigS) - } + bytes memory sig = _createSignature(digest, watcherPrivateKey); feesManager.incrementFeesDeposited( fees_.feePoolChain, appGateway_, @@ -232,110 +202,50 @@ contract DeliveryHelperTest is SetupTest { ); } - //// BATCH DEPLOY AND EXECUTE HELPERS //// - function getContractFactoryPlug(uint32 chainSlug_) internal view returns (address) { - return address(getSocketConfig(chainSlug_).contractFactoryPlug); - } - - function checkPayloadBatchAndDetails( - PayloadDetails[] memory payloadDetails, - bytes32 asyncId, - address appGateway_ - ) internal view { - for (uint i = 0; i < payloadDetails.length; i++) { - PayloadDetails memory payloadDetail = deliveryHelper.getPayloadIndexDetails(asyncId, i); - - assertEq(payloadDetail.chainSlug, payloadDetails[i].chainSlug, "ChainSlug mismatch"); - // todo - // assertEq( - // payloadDetail.target, - // payloadDetails[i].target, - // "Target mismatch" - // ); - // assertEq( - // keccak256(payloadDetail.payload), - // keccak256(payloadDetails[i].payload), - // "Payload mismatch" - // ); - assertEq( - uint(payloadDetail.callType), - uint(payloadDetails[i].callType), - "CallType mismatch" - ); - // assertEq( - // payloadDetail.executionGasLimit, - // payloadDetails[i].executionGasLimit, - // "ExecutionGasLimit mismatch" - // ); - } - - PayloadBatch memory payloadBatch = deliveryHelper.getAsyncBatchDetails(asyncId); + ////////////////////////////////// Deployment helpers //////////////////////////////////// + function _deploy( + uint32 chainSlug_, + IAppGateway appGateway_, + bytes32[] memory contractIds_ + ) internal returns (uint40 requestCount) { + requestCount = watcherPrecompile.nextRequestCount(); + appGateway_.deployContracts(chainSlug_); - assertEq(payloadBatch.appGateway, appGateway_, "AppGateway mismatch"); - assertEq(payloadBatch.auctionManager, address(auctionManager), "AuctionManager mismatch"); - assertEq(payloadBatch.winningBid.fee, bidAmount, "WinningBid mismatch"); - assertEq( - payloadBatch.winningBid.transmitter, - transmitterEOA, - "WinningBid transmitter mismatch" - ); - assertEq(payloadBatch.isBatchCancelled, false, "IsBatchCancelled mismatch"); + finalizeRequest(requestCount, new bytes[](0)); + setupGatewayAndPlugs(chainSlug_, appGateway_, contractIds_); } - function bidAndEndAuction(bytes32 asyncId) internal { - placeBid(asyncId); - endAuction(); - } + function finalizeRequest(uint40 requestCount_, bytes[] memory readReturnData_) internal { + uint40[] memory batches = watcherPrecompile.getBatches(requestCount_); - function bidAndExecute(bytes32[] memory payloadIds, bytes32 asyncId_) internal { - bidAndEndAuction(asyncId_); - for (uint i = 0; i < payloadIds.length; i++) { - finalizeAndExecute(payloadIds[i]); + bool onlyReads = _checkIfOnlyReads(batches[0]); + if (!(onlyReads && batches.length == 1)) { + bidAndEndAuction(requestCount_); } - } - - function bidAndExecuteParallel(bytes32[] memory payloadIds, bytes32 asyncId_) internal { - bidAndEndAuction(asyncId_); - bytes[] memory returnData = new bytes[](payloadIds.length); - for (uint i = 0; i < payloadIds.length; i++) { - PayloadDetails memory payloadDetails = deliveryHelper.getPayloadDetails(payloadIds[i]); - returnData[i] = finalizeAndRelay(payloadIds[i], payloadDetails); + uint256 readCount = 0; + for (uint i = 0; i < batches.length; i++) { + bool hasMoreBatches = i < batches.length - 1; + readCount = _finalizeBatch(batches[i], readReturnData_, readCount, hasMoreBatches); } - - resolvePromises(payloadIds, returnData); } - function _deploy( - bytes32[] memory contractIds, - uint32 chainSlug_, - uint256 totalPayloads, - IAppGateway appGateway_ - ) internal returns (bytes32 asyncId) { - SocketContracts memory socketConfig = getSocketConfig(chainSlug_); - - asyncId = getNextAsyncId(); - bytes32[] memory payloadIds = getWritePayloadIds( - chainSlug_, - address(socketConfig.switchboard), - totalPayloads - ); - - appGateway_.deployContracts(chainSlug_); - bidAndExecute(payloadIds, asyncId); - setupGatewayAndPlugs(chainSlug_, appGateway_, contractIds); + function executeRequest(bytes[] memory readReturnData_) internal { + uint40 requestCount = watcherPrecompile.nextRequestCount(); + requestCount = requestCount == 0 ? 0 : requestCount - 1; + finalizeRequest(requestCount, readReturnData_); } function setupGatewayAndPlugs( uint32 chainSlug_, IAppGateway appGateway_, - bytes32[] memory contractIds + bytes32[] memory contractIds_ ) internal { - AppGatewayConfig[] memory gateways = new AppGatewayConfig[](contractIds.length); + AppGatewayConfig[] memory gateways = new AppGatewayConfig[](contractIds_.length); SocketContracts memory socketConfig = getSocketConfig(chainSlug_); - for (uint i = 0; i < contractIds.length; i++) { - address plug = appGateway_.getOnChainAddress(contractIds[i], chainSlug_); + for (uint i = 0; i < contractIds_.length; i++) { + address plug = appGateway_.getOnChainAddress(contractIds_[i], chainSlug_); gateways[i] = AppGatewayConfig({ plug: plug, @@ -346,278 +256,76 @@ contract DeliveryHelperTest is SetupTest { } bytes memory watcherSignature = _createWatcherSignature( - abi.encode(IWatcherPrecompile.setAppGateways.selector, gateways) + address(watcherPrecompileConfig), + abi.encode(IWatcherPrecompileConfig.setAppGateways.selector, gateways) ); - watcherPrecompile.setAppGateways(gateways, signatureNonce++, watcherSignature); - } - - function _executeReadBatchSingleChain() internal returns (bytes32 asyncId) { - asyncId = getNextAsyncId(); - } - - function _executeReadBatchMultiChain() internal returns (bytes32 asyncId) { - asyncId = getNextAsyncId(); - } - - function _executeWriteBatchSingleChain( - uint32 chainSlug_, - uint256 totalPayloads - ) internal returns (bytes32 asyncId) { - asyncId = getNextAsyncId(); - - bytes32[] memory payloadIds = getWritePayloadIds( - chainSlug_, - address(getSocketConfig(chainSlug_).switchboard), - totalPayloads - ); - bidAndExecute(payloadIds, asyncId); - } - - function _executeWriteBatchMultiChain( - uint32[] memory chainSlugs_ - ) internal returns (bytes32 asyncId) { - asyncId = getNextAsyncId(); - bidAndEndAuction(asyncId); - for (uint i = 0; i < chainSlugs_.length; i++) { - bytes32 payloadId = getWritePayloadId( - chainSlugs_[i], - address(getSocketConfig(chainSlugs_[i]).switchboard), - payloadIdCounter++ - ); - finalizeAndExecute(payloadId); - } - } - - function createDeployPayloadDetail( - uint32 chainSlug_, - address appDeployer_, - bytes memory bytecode_ - ) internal returns (PayloadDetails memory payloadDetails) { - bytes32 salt = keccak256(abi.encode(appDeployer_, chainSlug_, deployCounter++)); - bytes memory payload = abi.encodeWithSelector( - IContractFactoryPlug.deployContract.selector, - true, - salt, - address(appDeployer_), - address(0), - bytecode_, - "" - ); - - address asyncPromise = predictAsyncPromiseAddress( - address(deliveryHelper), - address(deliveryHelper) - ); - address[] memory next = new address[](2); - next[0] = asyncPromise; - - payloadDetails = createPayloadDetails( - chainSlug_, - address(appDeployer_), - address(0), - payload, - CallType.DEPLOY, - 1_000_000_0, - next - ); - - SocketContracts memory socketConfig = getSocketConfig(chainSlug_); - payloadDetails.target = address(socketConfig.contractFactoryPlug); - payloadDetails.payload = abi.encode(DEPLOY, payloadDetails.payload); - } - - function createPayloadDetails( - uint32 chainSlug_, - address appGateway_, - address target_, - bytes memory payload_, - CallType callType_, - uint256 executionGasLimit_, - address[] memory next_ - ) internal pure returns (PayloadDetails memory) { - return - PayloadDetails({ - appGateway: appGateway_, - chainSlug: chainSlug_, - target: target_, - payload: payload_, - callType: callType_, - executionGasLimit: executionGasLimit_, - value: 0, - next: next_, - isParallel: Parallel.ON - }); + watcherPrecompileConfig.setAppGateways(gateways, signatureNonce++, watcherSignature); } - //// AUCTION RELATED FUNCTIONS //// - function placeBid(bytes32 asyncId) internal { - // todo: - // vm.expectEmit(false, false, false, false); - // emit BidPlaced( - // asyncId, - // Bid({fee: bidAmount, transmitter: transmitterEOA, extraData: ""}) - // ); - - vm.prank(transmitterEOA); + //////////////////////////////////// Auction //////////////////////////////////// + function placeBid(uint40 requestCount) internal { bytes memory transmitterSignature = _createSignature( - keccak256(abi.encode(address(auctionManager), evmxSlug, asyncId, bidAmount, "")), + keccak256(abi.encode(address(auctionManager), evmxSlug, requestCount, bidAmount, "")), transmitterPrivateKey ); - auctionManager.bid(asyncId, bidAmount, transmitterSignature, ""); + vm.expectEmit(false, false, false, false); + emit BidPlaced( + requestCount, + Bid({transmitter: transmitterEOA, fee: bidAmount, extraData: bytes("")}) + ); + auctionManager.bid(requestCount, bidAmount, transmitterSignature, bytes("")); } - function endAuction() internal { - // todo: - // vm.expectEmit(true, false, false, true); - // emit AuctionEnded( - // asyncId, - // Bid({fee: bidAmount, transmitter: transmitterEOA, extraData: ""}) - // ); - + function endAuction(uint40 requestCount_) internal { if (auctionEndDelaySeconds == 0) return; - bytes32 timeoutId = _encodeId(evmxSlug, address(watcherPrecompile), payloadIdCounter++); + bytes32 timeoutId = _encodeId(evmxSlug, address(watcherPrecompile), timeoutIdCounter++); bytes memory watcherSignature = _createWatcherSignature( + address(watcherPrecompile), abi.encode(IWatcherPrecompile.resolveTimeout.selector, timeoutId) ); - watcherPrecompile.resolveTimeout(timeoutId, signatureNonce++, watcherSignature); - } - - function finalize( - bytes32 payloadId, - PayloadDetails memory payloadDetails - ) internal view returns (bytes memory, bytes32) { - SocketContracts memory socketConfig = getSocketConfig(payloadDetails.chainSlug); - (, , , , , , uint256 deadline, , , ) = watcherPrecompile.asyncRequests(payloadId); - PayloadDigestParams memory digestParams_ = PayloadDigestParams( - payloadDetails.appGateway, - transmitterEOA, - payloadDetails.target, - payloadId, - payloadDetails.value, - payloadDetails.executionGasLimit, - deadline, - payloadDetails.payload + vm.expectEmit(true, true, true, true); + emit AuctionEnded( + requestCount_, + Bid({fee: bidAmount, transmitter: transmitterEOA, extraData: ""}) ); - bytes32 digest = watcherPrecompile.getDigest(digestParams_); - - bytes32 sigDigest = keccak256(abi.encode(address(socketConfig.switchboard), digest)); - bytes memory proof = _createSignature(sigDigest, watcherPrivateKey); - return (proof, digest); + watcherPrecompile.resolveTimeout(timeoutId, signatureNonce++, watcherSignature); } - function createWithdrawPayloadDetail( - uint32 chainSlug_, - address target_, - address appGateway_, - address forwarder_, - bytes memory payload_ - ) internal returns (PayloadDetails memory) { - return - createWritePayloadDetail( - chainSlug_, - target_, - appGateway_, - forwarder_, - WITHDRAW, - payload_ - ); + function bidAndEndAuction(uint40 requestCount) internal { + placeBid(requestCount); + endAuction(requestCount); } - function createExecutePayloadDetail( + //////////////////////////////////// Utils /////////////////////////////////// + function _encodeId( uint32 chainSlug_, - address target_, - address appGateway_, - address forwarder_, - bytes memory payload_ - ) internal returns (PayloadDetails memory) { + address sbOrWatcher_, + uint256 counter_ + ) internal pure returns (bytes32) { return - createWritePayloadDetail( - chainSlug_, - target_, - appGateway_, - forwarder_, - FORWARD_CALL, - payload_ + bytes32( + (uint256(chainSlug_) << 224) | (uint256(uint160(sbOrWatcher_)) << 64) | counter_ ); } - function createWritePayloadDetail( - uint32 chainSlug_, - address target_, - address appGateway_, - address forwarder_, - bytes32, - bytes memory payload_ - ) internal returns (PayloadDetails memory payloadDetails) { - address asyncPromise = predictAsyncPromiseAddress(appGateway_, forwarder_); - address[] memory next = new address[](2); - next[0] = asyncPromise; - - payloadDetails = createPayloadDetails( - chainSlug_, - appGateway_, - target_, - payload_, - CallType.WRITE, - CONFIGURE_GAS_LIMIT, - next - ); - - SocketContracts memory socketConfig = getSocketConfig(chainSlug_); - payloadDetails.target = address(socketConfig.contractFactoryPlug); - } - - function createReadPayloadDetail( + function getOnChainAndForwarderAddresses( uint32 chainSlug_, - address target_, - address appGateway_, - address forwarder_, - bytes memory payload_ - ) internal returns (PayloadDetails memory) { - address asyncPromise = predictAsyncPromiseAddress(appGateway_, forwarder_); - address[] memory next = new address[](2); - next[0] = asyncPromise; - - return - createPayloadDetails( - chainSlug_, - appGateway_, - target_, - payload_, - CallType.READ, - CONFIGURE_GAS_LIMIT, - next - ); - } - - function finalizeQuery(bytes32 payloadId, bytes memory returnData_) internal { - resolvePromise(payloadId, returnData_); - } - - function finalizeAndExecute(bytes32 payloadId) internal { - PayloadDetails memory payloadDetails = deliveryHelper.getPayloadDetails(payloadId); - bytes memory returnData = finalizeAndRelay(payloadId, payloadDetails); - resolvePromise(payloadId, returnData); + bytes32 contractId_, + IAppGateway appGateway_ + ) internal view returns (address, address) { + address app = appGateway_.getOnChainAddress(contractId_, chainSlug_); + address forwarder = appGateway_.forwarderAddresses(contractId_, chainSlug_); + return (app, forwarder); } - function finalizeAndRelay( - bytes32 payloadId_, - PayloadDetails memory payloadDetails - ) internal returns (bytes memory returnData) { - (bytes memory watcherSig, bytes32 digest) = finalize(payloadId_, payloadDetails); - - returnData = relayTx( - payloadDetails.chainSlug, - payloadId_, - digest, - payloadDetails, - watcherSig - ); + function getContractFactoryPlug(uint32 chainSlug_) internal view returns (address) { + return address(getSocketConfig(chainSlug_).contractFactoryPlug); } + //////////////////////////////////// Helpers //////////////////////////////////// function predictAsyncPromiseAddress( address invoker_, address forwarder_ @@ -639,18 +347,49 @@ contract DeliveryHelperTest is SetupTest { return address(uint160(uint256(hash))); } - function getNextAsyncId() public returns (bytes32) { - payloadIdCounter++; - return bytes32((uint256(uint160(address(deliveryHelper))) << 64) | asyncCounterTest++); - } + //////////////////////////////////// Validators //////////////////////////////////// - function getOnChainAndForwarderAddresses( - uint32 chainSlug_, - bytes32 contractId_, - IAppGateway appGateway_ - ) internal view returns (address, address) { - address app = appGateway_.getOnChainAddress(contractId_, chainSlug_); - address forwarder = appGateway_.forwarderAddresses(contractId_, chainSlug_); - return (app, forwarder); + function checkPayloadRequestAndDetails( + PayloadSubmitParams[] memory payloadSubmitParams, + uint40 requestCount, + address appGateway_ + ) internal view { + for (uint i = 0; i < payloadSubmitParams.length; i++) { + PayloadSubmitParams memory payloadSubmitParam = payloadSubmitParams[i]; + + assertEq( + payloadSubmitParam.chainSlug, + payloadSubmitParams[i].chainSlug, + "ChainSlug mismatch" + ); + // todo + assertEq(payloadSubmitParam.target, payloadSubmitParams[i].target, "Target mismatch"); + assertEq( + keccak256(payloadSubmitParam.payload), + keccak256(payloadSubmitParams[i].payload), + "Payload mismatch" + ); + assertEq( + uint(payloadSubmitParam.callType), + uint(payloadSubmitParams[i].callType), + "CallType mismatch" + ); + assertEq( + payloadSubmitParam.gasLimit, + payloadSubmitParams[i].gasLimit, + "gasLimit mismatch" + ); + } + + RequestMetadata memory payloadRequest = deliveryHelper.getRequestMetadata(requestCount); + + assertEq(payloadRequest.appGateway, appGateway_, "AppGateway mismatch"); + assertEq(payloadRequest.auctionManager, address(auctionManager), "AuctionManager mismatch"); + assertEq(payloadRequest.winningBid.fee, bidAmount, "WinningBid mismatch"); + assertEq( + payloadRequest.winningBid.transmitter, + transmitterEOA, + "WinningBid transmitter mismatch" + ); } } diff --git a/test/FeesTest.t.sol b/test/FeesTest.t.sol index 793b4622..4fc2a3a0 100644 --- a/test/FeesTest.t.sol +++ b/test/FeesTest.t.sol @@ -13,22 +13,18 @@ contract FeesTest is DeliveryHelperTest { uint32 feesChainSlug = arbChainSlug; SocketContracts feesConfig; - bytes32 asyncId; CounterAppGateway counterGateway; function setUp() public { setUpDeliveryHelper(); feesConfig = getSocketConfig(feesChainSlug); - counterGateway = new CounterAppGateway( - address(addressResolver), - createFees(feesAmount) - ); + counterGateway = new CounterAppGateway(address(addressResolver), createFees(feesAmount)); depositFees(address(counterGateway), createFees(depositAmount)); bytes32[] memory contractIds = new bytes32[](1); contractIds[0] = counterGateway.counter(); - asyncId = _deploy(contractIds, feesChainSlug, 1, IAppGateway(counterGateway)); + _deploy(feesChainSlug, IAppGateway(counterGateway), contractIds); } function testDistributeFee() public { @@ -49,10 +45,13 @@ contract FeesTest is DeliveryHelperTest { uint256 transmitterReceiverBalanceBefore = address(receiver).balance; hoax(transmitterEOA); - (bytes32 payloadId, , PayloadDetails memory payloadDetails) = feesManager - .withdrawTransmitterFees(feesChainSlug, ETH_ADDRESS, address(receiver)); - payloadIdCounter++; - finalizeAndRelay(payloadId, payloadDetails); + uint40 requestCount = feesManager.withdrawTransmitterFees( + feesChainSlug, + ETH_ADDRESS, + address(receiver) + ); + uint40[] memory batches = watcherPrecompile.getBatches(requestCount); + _finalizeBatch(batches[0], new bytes[](0), 0, false); assertEq( transmitterReceiverBalanceBefore + bidAmount, @@ -77,17 +76,8 @@ contract FeesTest is DeliveryHelperTest { uint256 withdrawAmount = 0.5 ether; counterGateway.withdrawFeeTokens(feesChainSlug, ETH_ADDRESS, withdrawAmount, receiver); + executeRequest(new bytes[](0)); - asyncId = getNextAsyncId(); - bytes32[] memory payloadIds = getWritePayloadIds( - feesChainSlug, - address(getSocketConfig(feesChainSlug).switchboard), - 1 - ); - bidAndEndAuction(asyncId); - - PayloadDetails memory payloadDetails = deliveryHelper.getPayloadDetails(payloadIds[0]); - finalizeAndRelay(payloadIds[0], payloadDetails); assertEq( depositAmount - withdrawAmount, address(feesConfig.feesPlug).balance, diff --git a/test/Inbox.t.sol b/test/Inbox.t.sol index 07bad0a5..f45277fd 100644 --- a/test/Inbox.t.sol +++ b/test/Inbox.t.sol @@ -18,10 +18,7 @@ contract InboxTest is DeliveryHelperTest { inbox = new Counter(); // Deploy the gateway with fees - gateway = new CounterAppGateway( - address(addressResolver), - createFees(feesAmount) - ); + gateway = new CounterAppGateway(address(addressResolver), createFees(feesAmount)); gateway.setIsValidPlug(arbChainSlug, address(inbox)); // Connect the inbox to the gateway and socket @@ -41,12 +38,14 @@ contract InboxTest is DeliveryHelperTest { }); bytes memory watcherSignature = _createWatcherSignature( - abi.encode(IWatcherPrecompile.setAppGateways.selector, gateways) + address(watcherPrecompileConfig), + abi.encode(IWatcherPrecompileConfig.setAppGateways.selector, gateways) ); - watcherPrecompile.setAppGateways(gateways, signatureNonce++, watcherSignature); + + watcherPrecompileConfig.setAppGateways(gateways, signatureNonce++, watcherSignature); hoax(watcherEOA); - watcherPrecompile.setIsValidPlug(arbChainSlug, address(inbox), true); + watcherPrecompileConfig.setIsValidPlug(arbChainSlug, address(inbox), true); } function testInboxIncrement() public { @@ -68,7 +67,8 @@ contract InboxTest is DeliveryHelperTest { }); bytes memory watcherSignature = _createWatcherSignature( - abi.encode(WatcherPrecompile.callAppGateways.selector, params) + address(watcherPrecompile), + abi.encode(IWatcherPrecompile.callAppGateways.selector, params) ); watcherPrecompile.callAppGateways(params, signatureNonce++, watcherSignature); // Check counter was incremented diff --git a/test/Migration.t.sol b/test/Migration.t.sol index 17ffb944..0632d583 100644 --- a/test/Migration.t.sol +++ b/test/Migration.t.sol @@ -8,267 +8,267 @@ import "../contracts/protocol/Forwarder.sol"; import "../contracts/protocol/AsyncPromise.sol"; import "./mock/MockWatcherPrecompileImpl.sol"; -contract MigrationTest is SetupTest { - // ERC1967Factory emits this event with both proxy and implementation addresses - event Upgraded(address indexed proxy, address indexed implementation); - event ImplementationUpdated(string contractName, address newImplementation); - - // ERC1967 implementation slot - bytes32 internal constant _IMPLEMENTATION_SLOT = - 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; - - // Beacon implementation slot - uint256 internal constant _BEACON_IMPLEMENTATION_SLOT = 0x911c5a209f08d5ec5e; - - // Beacon slot in ERC1967 - bytes32 internal constant _BEACON_SLOT = - 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; - - // Error selector for Unauthorized error - bytes4 internal constant UNAUTHORIZED_SELECTOR = 0x82b42900; // bytes4(keccak256("Unauthorized()")) - - function setUp() public { - deployEVMxCore(); - } - - function getImplementation(address proxy) internal view returns (address) { - bytes32 value = vm.load(proxy, _IMPLEMENTATION_SLOT); - return address(uint160(uint256(value))); - } - - function getBeaconImplementation(address beacon) internal view returns (address) { - bytes32 value = vm.load(beacon, bytes32(_BEACON_IMPLEMENTATION_SLOT)); - return address(uint160(uint256(value))); - } - - function getBeacon(address proxy) internal view returns (address) { - bytes32 value = vm.load(proxy, _BEACON_SLOT); - return address(uint160(uint256(value))); - } - - function testAddressResolverUpgrade() public { - // Deploy new implementation - AddressResolver newImpl = new AddressResolver(); - - // Store old implementation address - address oldImpl = getImplementation(address(addressResolver)); - - // Upgrade proxy to new implementation - vm.startPrank(watcherEOA); - vm.expectEmit(true, true, true, true, address(proxyFactory)); - emit Upgraded(address(addressResolver), address(newImpl)); - proxyFactory.upgradeAndCall(address(addressResolver), address(newImpl), ""); - vm.stopPrank(); - - // Verify upgrade was successful - address newImplAddr = getImplementation(address(addressResolver)); - assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); - assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); - - // Verify state is preserved - assertEq(addressResolver.owner(), watcherEOA, "Owner should be preserved after upgrade"); - assertEq( - address(addressResolver.watcherPrecompile__()), - address(watcherPrecompile), - "WatcherPrecompile address should be preserved" - ); - } - - function testWatcherPrecompileUpgrade() public { - // Deploy new implementation - WatcherPrecompile newImpl = new WatcherPrecompile(); - - // Store old implementation address - address oldImpl = getImplementation(address(watcherPrecompile)); - - // Upgrade proxy to new implementation - vm.startPrank(watcherEOA); - vm.expectEmit(true, true, true, true, address(proxyFactory)); - emit Upgraded(address(watcherPrecompile), address(newImpl)); - proxyFactory.upgradeAndCall(address(watcherPrecompile), address(newImpl), ""); - vm.stopPrank(); - - // Verify upgrade was successful - address newImplAddr = getImplementation(address(watcherPrecompile)); - assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); - assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); - - // Verify state is preserved - assertEq(watcherPrecompile.owner(), watcherEOA, "Owner should be preserved after upgrade"); - assertEq( - address(watcherPrecompile.addressResolver__()), - address(addressResolver), - "AddressResolver should be preserved" - ); - assertEq( - watcherPrecompile.defaultLimit(), - defaultLimit * 10 ** 18, - "DefaultLimit should be preserved" - ); - } - - function testUpgradeWithInitializationData() public { - // Deploy new implementation - MockWatcherPrecompileImpl newImpl = new MockWatcherPrecompileImpl(); - - // Store old implementation address for verification - address oldImpl = getImplementation(address(watcherPrecompile)); - - // Prepare initialization data with new defaultLimit - uint256 newDefaultLimit = 2000; - bytes memory initData = abi.encodeWithSelector( - MockWatcherPrecompileImpl.mockReinitialize.selector, - watcherEOA, - address(addressResolver), - newDefaultLimit - ); - - // Upgrade proxy with initialization data - vm.startPrank(watcherEOA); - vm.expectEmit(true, true, true, true, address(proxyFactory)); - emit Upgraded(address(watcherPrecompile), address(newImpl)); - proxyFactory.upgradeAndCall(address(watcherPrecompile), address(newImpl), initData); - vm.stopPrank(); - - // Verify upgrade and initialization was successful - address newImplAddr = getImplementation(address(watcherPrecompile)); - assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); - assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); - assertEq( - watcherPrecompile.defaultLimit(), - newDefaultLimit * 10 ** 18, - "DefaultLimit should be updated" - ); - } - - function testUnauthorizedUpgrade() public { - // Deploy new implementation - WatcherPrecompile newImpl = new WatcherPrecompile(); - - // Try to upgrade from unauthorized account - address unauthorizedUser = address(0xBEEF); - vm.startPrank(unauthorizedUser); - vm.expectRevert(UNAUTHORIZED_SELECTOR); - proxyFactory.upgradeAndCall(address(watcherPrecompile), address(newImpl), ""); - vm.stopPrank(); - - // Verify implementation was not changed - assertEq( - getImplementation(address(watcherPrecompile)), - address(watcherPrecompileImpl), - "Implementation should not have changed" - ); - } - - function testForwarderBeaconUpgrade() public { - // Deploy new implementation - Forwarder newImpl = new Forwarder(); - - // Get current implementation from beacon - address oldImpl = getBeaconImplementation(address(addressResolver.forwarderBeacon())); - - // Upgrade beacon to new implementation - vm.startPrank(watcherEOA); - vm.expectEmit(true, true, true, true, address(addressResolver)); - emit ImplementationUpdated("Forwarder", address(newImpl)); - addressResolver.setForwarderImplementation(address(newImpl)); - vm.stopPrank(); - - // Verify upgrade was successful - address newImplAddr = getBeaconImplementation(address(addressResolver.forwarderBeacon())); - assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); - assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); - - // Deploy a new forwarder and verify it uses the correct beacon - address newForwarder = addressResolver.getOrDeployForwarderContract( - address(this), - address(0x123), - 1 - ); - address beacon = getBeacon(newForwarder); - assertEq( - beacon, - address(addressResolver.forwarderBeacon()), - "Beacon address not set correctly" - ); - - // Get implementation from beacon and verify it matches - address implFromBeacon = getBeaconImplementation(beacon); - assertEq( - implFromBeacon, - address(newImpl), - "Beacon implementation should match new implementation" - ); - } - - function testAsyncPromiseBeaconUpgrade() public { - // Deploy new implementation - AsyncPromise newImpl = new AsyncPromise(); - - // Get current implementation from beacon - address oldImpl = getBeaconImplementation(address(addressResolver.asyncPromiseBeacon())); - - // Upgrade beacon to new implementation - vm.startPrank(watcherEOA); - vm.expectEmit(true, true, true, true, address(addressResolver)); - emit ImplementationUpdated("AsyncPromise", address(newImpl)); - addressResolver.setAsyncPromiseImplementation(address(newImpl)); - vm.stopPrank(); - - // Verify upgrade was successful - address newImplAddr = getBeaconImplementation( - address(addressResolver.asyncPromiseBeacon()) - ); - assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); - assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); - - // Deploy a new async promise and verify it uses the correct beacon - address newPromise = addressResolver.deployAsyncPromiseContract(address(this)); - address beacon = getBeacon(newPromise); - assertEq( - beacon, - address(addressResolver.asyncPromiseBeacon()), - "Beacon address not set correctly" - ); - - // Get implementation from beacon and verify it matches - address implFromBeacon = getBeaconImplementation(beacon); - assertEq( - implFromBeacon, - address(newImpl), - "Beacon implementation should match new implementation" - ); - } - - function testUnauthorizedBeaconUpgrade() public { - // Deploy new implementations - Forwarder newForwarderImpl = new Forwarder(); - AsyncPromise newAsyncPromiseImpl = new AsyncPromise(); - - // Try to upgrade from unauthorized account - address unauthorizedUser = address(0xBEEF); - - vm.startPrank(unauthorizedUser); - // Try upgrading forwarder beacon - vm.expectRevert(abi.encodeWithSelector(Ownable.Unauthorized.selector)); - addressResolver.setForwarderImplementation(address(newForwarderImpl)); - - // Try upgrading async promise beacon - vm.expectRevert(abi.encodeWithSelector(Ownable.Unauthorized.selector)); - addressResolver.setAsyncPromiseImplementation(address(newAsyncPromiseImpl)); - - vm.stopPrank(); - - // Verify implementations were not changed - assertNotEq( - getBeaconImplementation(address(addressResolver.forwarderBeacon())), - address(newForwarderImpl), - "Forwarder implementation should not have changed" - ); - assertNotEq( - getBeaconImplementation(address(addressResolver.asyncPromiseBeacon())), - address(newAsyncPromiseImpl), - "AsyncPromise implementation should not have changed" - ); - } -} +// contract MigrationTest is SetupTest { +// // ERC1967Factory emits this event with both proxy and implementation addresses +// event Upgraded(address indexed proxy, address indexed implementation); +// event ImplementationUpdated(string contractName, address newImplementation); + +// // ERC1967 implementation slot +// bytes32 internal constant _IMPLEMENTATION_SLOT = +// 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + +// // Beacon implementation slot +// uint256 internal constant _BEACON_IMPLEMENTATION_SLOT = 0x911c5a209f08d5ec5e; + +// // Beacon slot in ERC1967 +// bytes32 internal constant _BEACON_SLOT = +// 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; + +// // Error selector for Unauthorized error +// bytes4 internal constant UNAUTHORIZED_SELECTOR = 0x82b42900; // bytes4(keccak256("Unauthorized()")) + +// function setUp() public { +// deployEVMxCore(); +// } + +// function getImplementation(address proxy) internal view returns (address) { +// bytes32 value = vm.load(proxy, _IMPLEMENTATION_SLOT); +// return address(uint160(uint256(value))); +// } + +// function getBeaconImplementation(address beacon) internal view returns (address) { +// bytes32 value = vm.load(beacon, bytes32(_BEACON_IMPLEMENTATION_SLOT)); +// return address(uint160(uint256(value))); +// } + +// function getBeacon(address proxy) internal view returns (address) { +// bytes32 value = vm.load(proxy, _BEACON_SLOT); +// return address(uint160(uint256(value))); +// } + +// function testAddressResolverUpgrade() public { +// // Deploy new implementation +// AddressResolver newImpl = new AddressResolver(); + +// // Store old implementation address +// address oldImpl = getImplementation(address(addressResolver)); + +// // Upgrade proxy to new implementation +// vm.startPrank(watcherEOA); +// vm.expectEmit(true, true, true, true, address(proxyFactory)); +// emit Upgraded(address(addressResolver), address(newImpl)); +// proxyFactory.upgradeAndCall(address(addressResolver), address(newImpl), ""); +// vm.stopPrank(); + +// // Verify upgrade was successful +// address newImplAddr = getImplementation(address(addressResolver)); +// assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); +// assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); + +// // Verify state is preserved +// assertEq(addressResolver.owner(), watcherEOA, "Owner should be preserved after upgrade"); +// assertEq( +// address(addressResolver.watcherPrecompile__()), +// address(watcherPrecompile), +// "WatcherPrecompile address should be preserved" +// ); +// } + +// function testWatcherPrecompileUpgrade() public { +// // Deploy new implementation +// WatcherPrecompile newImpl = new WatcherPrecompile(); + +// // Store old implementation address +// address oldImpl = getImplementation(address(watcherPrecompile)); + +// // Upgrade proxy to new implementation +// vm.startPrank(watcherEOA); +// vm.expectEmit(true, true, true, true, address(proxyFactory)); +// emit Upgraded(address(watcherPrecompile), address(newImpl)); +// proxyFactory.upgradeAndCall(address(watcherPrecompile), address(newImpl), ""); +// vm.stopPrank(); + +// // Verify upgrade was successful +// address newImplAddr = getImplementation(address(watcherPrecompile)); +// assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); +// assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); + +// // Verify state is preserved +// assertEq(watcherPrecompile.owner(), watcherEOA, "Owner should be preserved after upgrade"); +// assertEq( +// address(watcherPrecompile.addressResolver__()), +// address(addressResolver), +// "AddressResolver should be preserved" +// ); +// assertEq( +// watcherPrecompile.defaultLimit(), +// defaultLimit * 10 ** 18, +// "DefaultLimit should be preserved" +// ); +// } + +// function testUpgradeWithInitializationData() public { +// // Deploy new implementation +// MockWatcherPrecompileImpl newImpl = new MockWatcherPrecompileImpl(); + +// // Store old implementation address for verification +// address oldImpl = getImplementation(address(watcherPrecompile)); + +// // Prepare initialization data with new defaultLimit +// uint256 newDefaultLimit = 2000; +// bytes memory initData = abi.encodeWithSelector( +// MockWatcherPrecompileImpl.mockReinitialize.selector, +// watcherEOA, +// address(addressResolver), +// newDefaultLimit +// ); + +// // Upgrade proxy with initialization data +// vm.startPrank(watcherEOA); +// vm.expectEmit(true, true, true, true, address(proxyFactory)); +// emit Upgraded(address(watcherPrecompile), address(newImpl)); +// proxyFactory.upgradeAndCall(address(watcherPrecompile), address(newImpl), initData); +// vm.stopPrank(); + +// // Verify upgrade and initialization was successful +// address newImplAddr = getImplementation(address(watcherPrecompile)); +// assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); +// assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); +// assertEq( +// watcherPrecompile.defaultLimit(), +// newDefaultLimit * 10 ** 18, +// "DefaultLimit should be updated" +// ); +// } + +// function testUnauthorizedUpgrade() public { +// // Deploy new implementation +// WatcherPrecompile newImpl = new WatcherPrecompile(); + +// // Try to upgrade from unauthorized account +// address unauthorizedUser = address(0xBEEF); +// vm.startPrank(unauthorizedUser); +// vm.expectRevert(UNAUTHORIZED_SELECTOR); +// proxyFactory.upgradeAndCall(address(watcherPrecompile), address(newImpl), ""); +// vm.stopPrank(); + +// // Verify implementation was not changed +// assertEq( +// getImplementation(address(watcherPrecompile)), +// address(watcherPrecompileImpl), +// "Implementation should not have changed" +// ); +// } + +// function testForwarderBeaconUpgrade() public { +// // Deploy new implementation +// Forwarder newImpl = new Forwarder(); + +// // Get current implementation from beacon +// address oldImpl = getBeaconImplementation(address(addressResolver.forwarderBeacon())); + +// // Upgrade beacon to new implementation +// vm.startPrank(watcherEOA); +// vm.expectEmit(true, true, true, true, address(addressResolver)); +// emit ImplementationUpdated("Forwarder", address(newImpl)); +// addressResolver.setForwarderImplementation(address(newImpl)); +// vm.stopPrank(); + +// // Verify upgrade was successful +// address newImplAddr = getBeaconImplementation(address(addressResolver.forwarderBeacon())); +// assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); +// assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); + +// // Deploy a new forwarder and verify it uses the correct beacon +// address newForwarder = addressResolver.getOrDeployForwarderContract( +// address(this), +// address(0x123), +// 1 +// ); +// address beacon = getBeacon(newForwarder); +// assertEq( +// beacon, +// address(addressResolver.forwarderBeacon()), +// "Beacon address not set correctly" +// ); + +// // Get implementation from beacon and verify it matches +// address implFromBeacon = getBeaconImplementation(beacon); +// assertEq( +// implFromBeacon, +// address(newImpl), +// "Beacon implementation should match new implementation" +// ); +// } + +// function testAsyncPromiseBeaconUpgrade() public { +// // Deploy new implementation +// AsyncPromise newImpl = new AsyncPromise(); + +// // Get current implementation from beacon +// address oldImpl = getBeaconImplementation(address(addressResolver.asyncPromiseBeacon())); + +// // Upgrade beacon to new implementation +// vm.startPrank(watcherEOA); +// vm.expectEmit(true, true, true, true, address(addressResolver)); +// emit ImplementationUpdated("AsyncPromise", address(newImpl)); +// addressResolver.setAsyncPromiseImplementation(address(newImpl)); +// vm.stopPrank(); + +// // Verify upgrade was successful +// address newImplAddr = getBeaconImplementation( +// address(addressResolver.asyncPromiseBeacon()) +// ); +// assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); +// assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); + +// // Deploy a new async promise and verify it uses the correct beacon +// address newPromise = addressResolver.deployAsyncPromiseContract(address(this)); +// address beacon = getBeacon(newPromise); +// assertEq( +// beacon, +// address(addressResolver.asyncPromiseBeacon()), +// "Beacon address not set correctly" +// ); + +// // Get implementation from beacon and verify it matches +// address implFromBeacon = getBeaconImplementation(beacon); +// assertEq( +// implFromBeacon, +// address(newImpl), +// "Beacon implementation should match new implementation" +// ); +// } + +// function testUnauthorizedBeaconUpgrade() public { +// // Deploy new implementations +// Forwarder newForwarderImpl = new Forwarder(); +// AsyncPromise newAsyncPromiseImpl = new AsyncPromise(); + +// // Try to upgrade from unauthorized account +// address unauthorizedUser = address(0xBEEF); + +// vm.startPrank(unauthorizedUser); +// // Try upgrading forwarder beacon +// vm.expectRevert(abi.encodeWithSelector(Ownable.Unauthorized.selector)); +// addressResolver.setForwarderImplementation(address(newForwarderImpl)); + +// // Try upgrading async promise beacon +// vm.expectRevert(abi.encodeWithSelector(Ownable.Unauthorized.selector)); +// addressResolver.setAsyncPromiseImplementation(address(newAsyncPromiseImpl)); + +// vm.stopPrank(); + +// // Verify implementations were not changed +// assertNotEq( +// getBeaconImplementation(address(addressResolver.forwarderBeacon())), +// address(newForwarderImpl), +// "Forwarder implementation should not have changed" +// ); +// assertNotEq( +// getBeaconImplementation(address(addressResolver.asyncPromiseBeacon())), +// address(newAsyncPromiseImpl), +// "AsyncPromise implementation should not have changed" +// ); +// } +// } diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index fa419020..8a6ee9a2 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -3,8 +3,12 @@ pragma solidity ^0.8.0; import "forge-std/Test.sol"; import "../contracts/protocol/utils/common/Structs.sol"; +import "../contracts/protocol/utils/common/Errors.sol"; import "../contracts/protocol/utils/common/Constants.sol"; import "../contracts/protocol/watcherPrecompile/WatcherPrecompile.sol"; +import "../contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol"; +import "../contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol"; +import "../contracts/protocol/watcherPrecompile/DumpDecoder.sol"; import "../contracts/interfaces/IForwarder.sol"; import "../contracts/protocol/utils/common/AccessRoles.sol"; import {Socket} from "../contracts/protocol/socket/Socket.sol"; @@ -20,6 +24,7 @@ import {ResolvedPromises} from "../contracts/protocol/utils/common/Structs.sol"; import "solady/utils/ERC1967Factory.sol"; contract SetupTest is Test { + using DumpDecoder for bytes32; uint public c = 1; address owner = address(uint160(c++)); @@ -34,9 +39,11 @@ contract SetupTest is Test { uint32 optChainSlug = 11155420; uint32 evmxSlug = 1; uint256 expiryTime = 10000000; + uint256 maxReAuctionCount = 10; - uint256 public signatureNonce = 0; - uint256 public payloadIdCounter = 0; + uint256 public signatureNonce; + uint256 public payloadIdCounter; + uint256 public timeoutIdCounter; uint256 public defaultLimit = 1000; bytes public asyncPromiseBytecode = type(AsyncPromise).creationCode; @@ -53,15 +60,23 @@ contract SetupTest is Test { AddressResolver public addressResolver; WatcherPrecompile public watcherPrecompile; + WatcherPrecompileConfig public watcherPrecompileConfig; + WatcherPrecompileLimits public watcherPrecompileLimits; + SocketContracts public arbConfig; SocketContracts public optConfig; // Add new variables for proxy admin and implementation contracts WatcherPrecompile public watcherPrecompileImpl; + WatcherPrecompileConfig public watcherPrecompileConfigImpl; + WatcherPrecompileLimits public watcherPrecompileLimitsImpl; AddressResolver public addressResolverImpl; ERC1967Factory public proxyFactory; event Initialized(uint64 version); + event FinalizeRequested(bytes32 payloadId, PayloadParams payloadParams); + + //////////////////////////////////// Setup //////////////////////////////////// function deploySocket(uint32 chainSlug_) internal returns (SocketContracts memory) { Socket socket = new Socket(chainSlug_, owner, "test"); @@ -77,19 +92,20 @@ contract SetupTest is Test { // switchboard switchboard.registerSwitchboard(); - switchboard.grantWatcherRole(watcherEOA); + switchboard.grantRole(WATCHER_ROLE, watcherEOA); vm.stopPrank(); hoax(watcherEOA); - watcherPrecompile.setOnChainContracts( + watcherPrecompileConfig.setOnChainContracts( chainSlug_, - FAST, - address(switchboard), address(socket), address(contractFactoryPlug), address(feesPlug) ); + hoax(watcherEOA); + watcherPrecompileConfig.setSwitchboard(chainSlug_, FAST, address(switchboard)); + return SocketContracts({ chainSlug: chainSlug_, @@ -105,6 +121,8 @@ contract SetupTest is Test { // Deploy implementations addressResolverImpl = new AddressResolver(); watcherPrecompileImpl = new WatcherPrecompile(); + watcherPrecompileConfigImpl = new WatcherPrecompileConfig(); + watcherPrecompileLimitsImpl = new WatcherPrecompileLimits(); proxyFactory = new ERC1967Factory(); // Deploy and initialize proxies @@ -120,13 +138,42 @@ contract SetupTest is Test { addressResolverData ); + bytes memory watcherPrecompileLimitsData = abi.encodeWithSelector( + WatcherPrecompileLimits.initialize.selector, + watcherEOA, + address(addressResolverProxy), + defaultLimit + ); + vm.expectEmit(true, true, true, false); + emit Initialized(version); + address watcherPrecompileLimitsProxy = proxyFactory.deployAndCall( + address(watcherPrecompileLimitsImpl), + watcherEOA, + watcherPrecompileLimitsData + ); + + bytes memory watcherPrecompileConfigData = abi.encodeWithSelector( + WatcherPrecompileConfig.initialize.selector, + watcherEOA, + address(addressResolverProxy), + evmxSlug + ); + vm.expectEmit(true, true, true, false); + emit Initialized(version); + address watcherPrecompileConfigProxy = proxyFactory.deployAndCall( + address(watcherPrecompileConfigImpl), + watcherEOA, + watcherPrecompileConfigData + ); + bytes memory watcherPrecompileData = abi.encodeWithSelector( WatcherPrecompile.initialize.selector, watcherEOA, address(addressResolverProxy), - defaultLimit, expiryTime, - evmxSlug + evmxSlug, + address(watcherPrecompileLimitsProxy), + address(watcherPrecompileConfigProxy) ); vm.expectEmit(true, true, true, false); emit Initialized(version); @@ -139,29 +186,98 @@ contract SetupTest is Test { // Assign proxy addresses to public variables addressResolver = AddressResolver(address(addressResolverProxy)); watcherPrecompile = WatcherPrecompile(address(watcherPrecompileProxy)); + watcherPrecompileConfig = WatcherPrecompileConfig(address(watcherPrecompileConfigProxy)); + watcherPrecompileLimits = WatcherPrecompileLimits(address(watcherPrecompileLimitsProxy)); vm.startPrank(watcherEOA); - watcherPrecompile.grantRole(WATCHER_ROLE, watcherEOA); addressResolver.setWatcherPrecompile(address(watcherPrecompile)); vm.stopPrank(); } - function _createSignature( - bytes32 digest_, - uint256 privateKey_ - ) internal 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); + //////////////////////////////////// Watcher precompiles //////////////////////////////////// - assembly { - mstore(add(sig, 96), v32) - mstore(add(sig, 32), sigR) - mstore(add(sig, 64), sigS) + function _checkIfOnlyReads(uint40 batchCount_) internal view returns (bool) { + bytes32[] memory payloadIds = watcherPrecompile.getBatchPayloadIds(batchCount_); + + for (uint i = 0; i < payloadIds.length; i++) { + PayloadParams memory payloadParams = watcherPrecompile.getPayloadParams(payloadIds[i]); + if (payloadParams.dump.getCallType() != CallType.READ) { + return false; + } + } + + return true; + } + + function _resolveAndExpectFinalizeRequested( + bytes32 payloadId_, + PayloadParams memory payloadParams, + bytes memory returnData, + bool isLastPayload + ) internal { + if (isLastPayload) { + vm.expectEmit(false, false, false, false); + emit FinalizeRequested(payloadId_, payloadParams); } + + _resolvePromise(payloadId_, returnData); } + function _finalizeBatch( + uint40 batchCount_, + bytes[] memory readReturnData_, + uint256 readCount_, + bool hasMoreBatches + ) internal returns (uint256) { + bytes32[] memory payloadIds = watcherPrecompile.getBatchPayloadIds(batchCount_); + + for (uint i = 0; i < payloadIds.length; i++) { + PayloadParams memory payloadParams = watcherPrecompile.getPayloadParams(payloadIds[i]); + bool isLastPayload = i == payloadIds.length - 1 && hasMoreBatches; + + if (payloadParams.dump.getCallType() == CallType.READ) { + _resolveAndExpectFinalizeRequested( + payloadParams.payloadId, + payloadParams, + readReturnData_[readCount_++], + isLastPayload + ); + } else { + bytes memory returnData = _uploadProofAndExecute(payloadParams); + _resolveAndExpectFinalizeRequested( + payloadParams.payloadId, + payloadParams, + returnData, + isLastPayload + ); + } + } + return readCount_; + } + + function _uploadProofAndExecute( + PayloadParams memory payloadParams + ) internal returns (bytes memory) { + (bytes memory watcherProof, bytes32 digest) = _generateWatcherProof(payloadParams); + _writeProof(payloadParams.payloadId, watcherProof); + + ( + ExecuteParams memory params, + SocketBatcher socketBatcher, + , + bytes memory transmitterSig + ) = _getExecuteParams(payloadParams); + + return socketBatcher.attestAndExecute(params, digest, watcherProof, transmitterSig); + } + + function resolvePromises(bytes32[] memory payloadIds, bytes[] memory returnData) internal { + for (uint i = 0; i < payloadIds.length; i++) { + _resolvePromise(payloadIds[i], returnData[i]); + } + } + + //////////////////////////////////// Helpers //////////////////////////////////// function getSocketConfig(uint32 chainSlug_) internal view returns (SocketContracts memory) { return chainSlug_ == arbChainSlug ? arbConfig : optConfig; } @@ -170,66 +286,109 @@ contract SetupTest is Test { return Fees({feePoolChain: arbChainSlug, feePoolToken: ETH_ADDRESS, amount: maxFees_}); } - function relayTx( - uint32 chainSlug_, - bytes32 payloadId, - bytes32 digest, - PayloadDetails memory payloadDetails, - bytes memory watcherProof - ) internal returns (bytes memory) { - SocketContracts memory socketConfig = getSocketConfig(chainSlug_); - bytes32 transmitterDigest = keccak256(abi.encode(address(socketConfig.socket), payloadId)); - bytes memory transmitterSig = _createSignature(transmitterDigest, transmitterPrivateKey); - - (, , , , , , uint256 deadline, , , ) = watcherPrecompile.asyncRequests(payloadId); - - vm.startPrank(transmitterEOA); - AttestAndExecutePayloadParams memory params = AttestAndExecutePayloadParams({ - switchboard: address(socketConfig.switchboard), - digest: digest, - proof: watcherProof, - payloadId: payloadId, - appGateway: payloadDetails.appGateway, - executionGasLimit: payloadDetails.executionGasLimit, - transmitterSignature: transmitterSig, - payload: payloadDetails.payload, - target: payloadDetails.target, - deadline: deadline - }); + function _generateWatcherProof( + PayloadParams memory params_ + ) internal view returns (bytes memory, bytes32) { + SocketContracts memory socketConfig = getSocketConfig(params_.dump.getChainSlug()); + DigestParams memory digestParams_ = DigestParams( + transmitterEOA, + params_.payloadId, + params_.deadline, + params_.dump.getCallType(), + params_.dump.getWriteFinality(), + params_.gasLimit, + params_.value, + params_.readAt, + params_.payload, + params_.target, + params_.appGateway, + params_.prevDigestsHash + ); + bytes32 digest = watcherPrecompile.getDigest(digestParams_); - bytes memory returnData = socketConfig.socketBatcher.attestAndExecute(params); - vm.stopPrank(); - return returnData; + bytes32 sigDigest = keccak256(abi.encode(address(socketConfig.switchboard), digest)); + bytes memory proof = _createSignature(sigDigest, watcherPrivateKey); + return (proof, digest); } - function resolvePromises(bytes32[] memory payloadIds, bytes[] memory returnDatas_) internal { - for (uint i = 0; i < payloadIds.length; i++) { - resolvePromise(payloadIds[i], returnDatas_[i]); - } + function _writeProof(bytes32 payloadId_, bytes memory watcherProof_) internal { + bytes memory bytesInput = abi.encode( + IWatcherPrecompile.finalized.selector, + payloadId_, + watcherProof_ + ); + bytes memory watcherSignature = _createWatcherSignature( + address(watcherPrecompile), + bytesInput + ); + watcherPrecompile.finalized(payloadId_, watcherProof_, signatureNonce++, watcherSignature); + assertEq(watcherPrecompile.watcherProofs(payloadId_), watcherProof_); } - function resolvePromise(bytes32 payloadId, bytes memory returnData) internal { - ResolvedPromises[] memory resolvedPromises = new ResolvedPromises[](1); + function _getExecuteParams( + PayloadParams memory payloadParams + ) + internal + view + returns ( + ExecuteParams memory params, + SocketBatcher socketBatcher, + uint256 value, + bytes memory transmitterSig + ) + { + SocketContracts memory socketConfig = getSocketConfig(payloadParams.dump.getChainSlug()); + bytes32 transmitterDigest = keccak256( + abi.encode(address(socketConfig.socket), payloadParams.payloadId) + ); + transmitterSig = _createSignature(transmitterDigest, transmitterPrivateKey); + + params = ExecuteParams({ + deadline: payloadParams.deadline, + callType: payloadParams.dump.getCallType(), + writeFinality: payloadParams.dump.getWriteFinality(), + gasLimit: payloadParams.gasLimit, + readAt: payloadParams.readAt, + payload: payloadParams.payload, + target: payloadParams.target, + requestCount: payloadParams.dump.getRequestCount(), + batchCount: payloadParams.dump.getBatchCount(), + payloadCount: payloadParams.dump.getPayloadCount(), + prevDigestsHash: payloadParams.prevDigestsHash, + switchboard: payloadParams.switchboard + }); - bytes[] memory returnDatas = new bytes[](2); - returnDatas[0] = returnData; + value = payloadParams.value; + socketBatcher = socketConfig.socketBatcher; + } - resolvedPromises[0] = ResolvedPromises({payloadId: payloadId, returnData: returnDatas}); + function _resolvePromise(bytes32 payloadId, bytes memory returnData) internal { + ResolvedPromises[] memory resolvedPromises = new ResolvedPromises[](1); + resolvedPromises[0] = ResolvedPromises({payloadId: payloadId, returnData: returnData}); bytes memory watcherSignature = _createWatcherSignature( + address(watcherPrecompile), abi.encode(WatcherPrecompile.resolvePromises.selector, resolvedPromises) ); watcherPrecompile.resolvePromises(resolvedPromises, signatureNonce++, watcherSignature); } function _createWatcherSignature( + address watcherPrecompile_, bytes memory params_ - ) internal view returns (bytes memory sig) { + ) internal view returns (bytes memory) { bytes32 digest = keccak256( - abi.encode(address(watcherPrecompile), evmxSlug, signatureNonce, params_) + abi.encode(watcherPrecompile_, evmxSlug, signatureNonce, params_) ); - digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest)); - (uint8 sigV, bytes32 sigR, bytes32 sigS) = vm.sign(watcherPrivateKey, digest); + return _createSignature(digest, watcherPrivateKey); + } + + function _createSignature( + bytes32 digest_, + uint256 privateKey_ + ) internal 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); @@ -239,35 +398,4 @@ contract SetupTest is Test { mstore(add(sig, 64), sigS) } } - - function getWritePayloadId( - uint32 chainSlug_, - address switchboard_, - uint256 counter_ - ) internal pure returns (bytes32) { - return _encodeId(chainSlug_, switchboard_, counter_); - } - - function getWritePayloadIds( - uint32 chainSlug_, - address switchboard_, - uint256 numPayloads - ) internal returns (bytes32[] memory) { - bytes32[] memory payloadIds = new bytes32[](numPayloads); - for (uint256 i = 0; i < numPayloads; i++) { - payloadIds[i] = _encodeId(chainSlug_, switchboard_, payloadIdCounter++); - } - return payloadIds; - } - - function _encodeId( - uint32 chainSlug_, - address sbOrWatcher_, - uint256 counter_ - ) internal pure returns (bytes32) { - return - bytes32( - (uint256(chainSlug_) << 224) | (uint256(uint160(sbOrWatcher_)) << 64) | counter_ - ); - } } diff --git a/test/Storage.t.sol b/test/Storage.t.sol index 89b5b3b9..67f31252 100644 --- a/test/Storage.t.sol +++ b/test/Storage.t.sol @@ -3,77 +3,77 @@ pragma solidity ^0.8.0; import "./DeliveryHelper.t.sol"; -contract StorageTest is DeliveryHelperTest { - DeliveryHelper public deliveryHelperImpl; - - function setUp() public { - setUpDeliveryHelper(); - } - - function testAddressResolverSlot() public view { - // Test AddressResolver version at slot 59 - bytes32 versionSlot = vm.load(address(addressResolver), bytes32(uint256(59))); - assertEq(uint64(uint256(versionSlot)), 1); - - // Test auction manager address at slot 61 in AddressResolver - bytes32 slotValue = vm.load(address(addressResolver), bytes32(uint256(61))); - assertEq(address(uint160(uint256(slotValue))), address(auctionManager)); - } - - function testWatcherPrecompileSlot() public view { - // Test AddressResolver address at slot 109 in WatcherPrecompile - bytes32 slotValue = vm.load(address(watcherPrecompile), bytes32(uint256(52))); - assertEq(uint256(slotValue), evmxSlug); - - slotValue = vm.load(address(watcherPrecompile), bytes32(uint256(220))); - assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); - } - - function testFeesManagerSlot() public view { - bytes32 slotValue = vm.load(address(feesManager), bytes32(uint256(51))); - assertEq(uint32(uint256(slotValue)), evmxSlug); - - slotValue = vm.load(address(feesManager), bytes32(uint256(106))); - assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); - } - - function testAuctionManagerSlot() public view { - bytes32 slotValue = vm.load(address(auctionManager), bytes32(uint256(50))); - assertEq(uint32(uint256(slotValue)), evmxSlug); - - slotValue = vm.load(address(auctionManager), bytes32(uint256(105))); - assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); - } - - function testForwarderSlot() public { - address forwarder = addressResolver.getOrDeployForwarderContract( - address(this), - address(this), - evmxSlug - ); - - bytes32 slotValue = vm.load(address(forwarder), bytes32(uint256(50))); - assertEq(uint32(uint256(slotValue)), evmxSlug); - - slotValue = vm.load(address(forwarder), bytes32(uint256(53))); - assertEq(address(uint160(uint256(slotValue))), address(0)); - } - - function testAsyncPromiseSlot() public { - address asyncPromise = addressResolver.deployAsyncPromiseContract(address(this)); - - bytes32 slotValue = vm.load(address(asyncPromise), bytes32(uint256(51))); - assertEq(address(uint160(uint256(slotValue))), address(this)); - - slotValue = vm.load(address(asyncPromise), bytes32(uint256(103))); - assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); - } - - function testDeliveryHelperSlot() public view { - bytes32 slotValue = vm.load(address(deliveryHelper), bytes32(uint256(50))); - assertEq(uint256(uint256(slotValue)), 0); - - slotValue = vm.load(address(deliveryHelper), bytes32(uint256(109))); - assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); - } -} +// contract StorageTest is DeliveryHelperTest { +// DeliveryHelper public deliveryHelperImpl; + +// function setUp() public { +// setUpDeliveryHelper(); +// } + +// function testAddressResolverSlot() public view { +// // Test AddressResolver version at slot 59 +// bytes32 versionSlot = vm.load(address(addressResolver), bytes32(uint256(59))); +// assertEq(uint64(uint256(versionSlot)), 1); + +// // Test auction manager address at slot 61 in AddressResolver +// bytes32 slotValue = vm.load(address(addressResolver), bytes32(uint256(61))); +// assertEq(address(uint160(uint256(slotValue))), address(auctionManager)); +// } + +// function testWatcherPrecompileSlot() public view { +// // Test AddressResolver address at slot 109 in WatcherPrecompile +// bytes32 slotValue = vm.load(address(watcherPrecompile), bytes32(uint256(52))); +// assertEq(uint256(slotValue), evmxSlug); + +// slotValue = vm.load(address(watcherPrecompile), bytes32(uint256(220))); +// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); +// } + +// function testFeesManagerSlot() public view { +// bytes32 slotValue = vm.load(address(feesManager), bytes32(uint256(51))); +// assertEq(uint32(uint256(slotValue)), evmxSlug); + +// slotValue = vm.load(address(feesManager), bytes32(uint256(106))); +// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); +// } + +// function testAuctionManagerSlot() public view { +// bytes32 slotValue = vm.load(address(auctionManager), bytes32(uint256(50))); +// assertEq(uint32(uint256(slotValue)), evmxSlug); + +// slotValue = vm.load(address(auctionManager), bytes32(uint256(105))); +// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); +// } + +// function testForwarderSlot() public { +// address forwarder = addressResolver.getOrDeployForwarderContract( +// address(this), +// address(this), +// evmxSlug +// ); + +// bytes32 slotValue = vm.load(address(forwarder), bytes32(uint256(50))); +// assertEq(uint32(uint256(slotValue)), evmxSlug); + +// slotValue = vm.load(address(forwarder), bytes32(uint256(53))); +// assertEq(address(uint160(uint256(slotValue))), address(0)); +// } + +// function testAsyncPromiseSlot() public { +// address asyncPromise = addressResolver.deployAsyncPromiseContract(address(this)); + +// bytes32 slotValue = vm.load(address(asyncPromise), bytes32(uint256(51))); +// assertEq(address(uint160(uint256(slotValue))), address(this)); + +// slotValue = vm.load(address(asyncPromise), bytes32(uint256(103))); +// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); +// } + +// function testDeliveryHelperSlot() public view { +// bytes32 slotValue = vm.load(address(deliveryHelper), bytes32(uint256(50))); +// assertEq(uint256(uint256(slotValue)), 0); + +// slotValue = vm.load(address(deliveryHelper), bytes32(uint256(109))); +// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); +// } +// } diff --git a/test/apps/Counter.t.sol b/test/apps/Counter.t.sol index cd029d40..22207236 100644 --- a/test/apps/Counter.t.sol +++ b/test/apps/Counter.t.sol @@ -16,18 +16,15 @@ contract CounterTest is DeliveryHelperTest { function deploySetup() internal { setUpDeliveryHelper(); - counterGateway = new CounterAppGateway( - address(addressResolver), - createFees(feesAmount) - ); + counterGateway = new CounterAppGateway(address(addressResolver), createFees(feesAmount)); depositFees(address(counterGateway), createFees(1 ether)); counterId = counterGateway.counter(); contractIds[0] = counterId; } - function deployCounterApp(uint32 chainSlug) internal returns (bytes32 asyncId) { - asyncId = _deploy(contractIds, chainSlug, 1, IAppGateway(counterGateway)); + function deployCounterApp(uint32 chainSlug) internal returns (uint40 requestCount) { + requestCount = _deploy(chainSlug, IAppGateway(counterGateway), contractIds); } function testCounterDeployment() external { @@ -52,6 +49,13 @@ contract CounterTest is DeliveryHelperTest { ); } + function testCounterDeploymentWithoutAsync() external { + deploySetup(); + + vm.expectRevert(abi.encodeWithSelector(AsyncModifierNotUsed.selector)); + counterGateway.deployContractsWithoutAsync(arbChainSlug); + } + function testCounterIncrement() external { deploySetup(); deployCounterApp(arbChainSlug); @@ -67,8 +71,8 @@ contract CounterTest is DeliveryHelperTest { address[] memory instances = new address[](1); instances[0] = arbCounterForwarder; counterGateway.incrementCounters(instances); + executeRequest(new bytes[](0)); - _executeWriteBatchSingleChain(arbChainSlug, 1); assertEq(Counter(arbCounter).counter(), arbCounterBefore + 1); } @@ -99,8 +103,8 @@ contract CounterTest is DeliveryHelperTest { uint32[] memory chains = new uint32[](2); chains[0] = arbChainSlug; chains[1] = optChainSlug; - _executeWriteBatchMultiChain(chains); + executeRequest(new bytes[](0)); assertEq(Counter(arbCounter).counter(), arbCounterBefore + 1); assertEq(Counter(optCounter).counter(), optCounterBefore + 1); } @@ -108,12 +112,12 @@ contract CounterTest is DeliveryHelperTest { function testCounterReadMultipleChains() external { testCounterIncrementMultipleChains(); - (address arbCounter, address arbCounterForwarder) = getOnChainAndForwarderAddresses( + (, address arbCounterForwarder) = getOnChainAndForwarderAddresses( arbChainSlug, counterId, counterGateway ); - (address optCounter, address optCounterForwarder) = getOnChainAndForwarderAddresses( + (, address optCounterForwarder) = getOnChainAndForwarderAddresses( optChainSlug, counterId, counterGateway @@ -123,23 +127,12 @@ contract CounterTest is DeliveryHelperTest { instances[0] = arbCounterForwarder; instances[1] = optCounterForwarder; - bytes32 bridgeAsyncId = getNextAsyncId(); - - bytes32[] memory payloadIds = new bytes32[](3); - payloadIds[0] = _encodeId(evmxSlug, address(watcherPrecompile), payloadIdCounter++); - payloadIds[1] = _encodeId(evmxSlug, address(watcherPrecompile), payloadIdCounter++); - - payloadIds[2] = getWritePayloadId( - arbChainSlug, - address(getSocketConfig(arbChainSlug).switchboard), - payloadIdCounter++ - ); - counterGateway.readCounters(instances); - bidAndEndAuction(bridgeAsyncId); - finalizeQuery(payloadIds[0], abi.encode(Counter(arbCounter).counter())); - finalizeQuery(payloadIds[1], abi.encode(Counter(optCounter).counter())); - finalizeAndExecute(payloadIds[2]); + bytes[] memory readReturnData = new bytes[](2); + readReturnData[0] = abi.encode(10); + readReturnData[1] = abi.encode(10); + + executeRequest(readReturnData); } } diff --git a/test/apps/ParallelCounter.t.sol b/test/apps/ParallelCounter.t.sol index 56261031..b7fdd7bf 100644 --- a/test/apps/ParallelCounter.t.sol +++ b/test/apps/ParallelCounter.t.sol @@ -27,30 +27,9 @@ contract ParallelCounterTest is DeliveryHelperTest { contractIds[1] = counterId2; } - function _deployParallel(uint32[] memory chainSlugs_) internal returns (bytes32 asyncId) { - asyncId = getNextAsyncId(); - bytes32[] memory payloadIds = new bytes32[](contractIds.length * chainSlugs_.length); - for (uint32 i = 0; i < chainSlugs_.length; i++) { - for (uint j = 0; j < contractIds.length; j++) { - payloadIds[i * contractIds.length + j] = getWritePayloadId( - chainSlugs_[i], - address(getSocketConfig(chainSlugs_[i]).switchboard), - i * contractIds.length + j + payloadIdCounter - ); - } - } - // for fees - payloadIdCounter += chainSlugs_.length * contractIds.length + 1; - - parallelCounterGateway.deployMultiChainContracts(chainSlugs_); - bidAndExecute(payloadIds, asyncId); - for (uint i = 0; i < chainSlugs_.length; i++) { - setupGatewayAndPlugs(chainSlugs_[i], parallelCounterGateway, contractIds); - } - } - - function deployCounterApps(uint32[] memory chainSlugs) internal returns (bytes32 asyncId) { - asyncId = _deployParallel(chainSlugs); + function deployCounterApps(uint32[] memory chainSlugs) internal { + parallelCounterGateway.deployMultiChainContracts(chainSlugs); + executeRequest(new bytes[](0)); } function testParallelCounterDeployment() external { @@ -160,7 +139,7 @@ contract ParallelCounterTest is DeliveryHelperTest { // instances[0] = arbCounterForwarder; // counterGateway.incrementCounters(instances); - // _executeBatchSingleChain(arbChainSlug, 1); + // _executeRequestSingleChain(arbChainSlug, 1); // assertEq(Counter(arbCounter).counter(), arbCounterBefore + 1); // } @@ -191,7 +170,7 @@ contract ParallelCounterTest is DeliveryHelperTest { // uint32[] memory chains = new uint32[](2); // chains[0] = arbChainSlug; // chains[1] = optChainSlug; - // _executeBatchMultiChain(chains); + // _executeRequestMultiChain(chains); // assertEq(Counter(arbCounter).counter(), arbCounterBefore + 1); // assertEq(Counter(optCounter).counter(), optCounterBefore + 1); // } diff --git a/test/apps/SuperToken.t.sol b/test/apps/SuperToken.t.sol index 34b438ac..45d62893 100644 --- a/test/apps/SuperToken.t.sol +++ b/test/apps/SuperToken.t.sol @@ -92,7 +92,7 @@ contract SuperTokenTest is DeliveryHelperTest { * - Correct setup of forwarder contracts for multi-chain communication */ function testContractDeployment() public { - _deploy(contractIds, arbChainSlug, 1, IAppGateway(appContracts.superTokenApp)); + _deploy(arbChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); (address onChain, address forwarder) = getOnChainAndForwarderAddresses( arbChainSlug, @@ -123,8 +123,8 @@ contract SuperTokenTest is DeliveryHelperTest { * @dev Deploys necessary contracts on both Arbitrum and Optimism chains */ function beforeTransfer() internal { - _deploy(contractIds, arbChainSlug, 1, IAppGateway(appContracts.superTokenApp)); - _deploy(contractIds, optChainSlug, 1, IAppGateway(appContracts.superTokenApp)); + _deploy(arbChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); + _deploy(optChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); } /** @@ -160,15 +160,10 @@ contract SuperTokenTest is DeliveryHelperTest { srcAmount: srcAmount, deadline: block.timestamp + 1000000 }); + bytes memory encodedOrder = abi.encode(transferOrder); appContracts.superTokenApp.transfer(encodedOrder); - - uint32[] memory chainSlugs = new uint32[](2); - chainSlugs[0] = IForwarder(forwarderArb).getChainSlug(); - chainSlugs[1] = IForwarder(forwarderOpt).getChainSlug(); - // You can run the function below whenever you want to simulate the onchain execution for - // the txs in batch of the current asyncId. It bids, finalises, relays and resolves promises - _executeWriteBatchMultiChain(chainSlugs); + executeRequest(new bytes[](0)); assertEq( SuperToken(onChainArb).balanceOf(owner), diff --git a/test/apps/SuperTokenLockable.t.sol b/test/apps/SuperTokenLockable.t.sol deleted file mode 100644 index b1161169..00000000 --- a/test/apps/SuperTokenLockable.t.sol +++ /dev/null @@ -1,637 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {SuperTokenLockableAppGateway} from "./app-gateways/super-token-lockable/SuperTokenLockableAppGateway.sol"; -import {SuperTokenLockable} from "./app-gateways/super-token-lockable/SuperTokenLockable.sol"; -import {LimitHook} from "./app-gateways/super-token-lockable/LimitHook.sol"; -import {QUERY, FINALIZE, SCHEDULE} from "../../contracts/protocol/utils/common/Constants.sol"; - -import "../DeliveryHelper.t.sol"; - -contract SuperTokenLockableTest is DeliveryHelperTest { - struct AppContracts { - SuperTokenLockableAppGateway superTokenLockableApp; - bytes32 superTokenLockable; - bytes32 limitHook; - } - AppContracts appContracts; - bytes32[] contractIds = new bytes32[](2); - - uint256 srcAmount = 0.01 ether; - SuperTokenLockableAppGateway.UserOrder userOrder; - - function setUp() public { - // core - setUpDeliveryHelper(); - - // app specific - deploySuperTokenApp(); - - contractIds[0] = appContracts.superTokenLockable; - contractIds[1] = appContracts.limitHook; - } - - function deploySuperTokenApp() internal { - SuperTokenLockableAppGateway superTokenLockableApp = new SuperTokenLockableAppGateway( - address(addressResolver), - owner, - createFees(maxFees), - SuperTokenLockableAppGateway.ConstructorParams({ - _burnLimit: 10000000000000000000000, - _mintLimit: 10000000000000000000000, - name_: "SUPER TOKEN", - symbol_: "SUPER", - decimals_: 18, - initialSupplyHolder_: owner, - initialSupply_: 1000000000 ether - }) - ); - depositFees(address(superTokenLockableApp), createFees(1 ether)); - - appContracts = AppContracts({ - superTokenLockableApp: superTokenLockableApp, - superTokenLockable: superTokenLockableApp.superTokenLockable(), - limitHook: superTokenLockableApp.limitHook() - }); - } - - function createDeployPayloadDetailsArray( - uint32 chainSlug_ - ) internal returns (PayloadDetails[] memory) { - PayloadDetails[] memory payloadDetails = new PayloadDetails[](2); - payloadDetails[0] = createDeployPayloadDetail( - chainSlug_, - address(appContracts.superTokenLockableApp), - appContracts.superTokenLockableApp.creationCodeWithArgs(appContracts.superTokenLockable) - ); - payloadDetails[1] = createDeployPayloadDetail( - chainSlug_, - address(appContracts.superTokenLockableApp), - appContracts.superTokenLockableApp.creationCodeWithArgs(appContracts.limitHook) - ); - - return payloadDetails; - } - - function createConfigurePayloadDetailsArray( - uint32 chainSlug_ - ) internal returns (PayloadDetails[] memory) { - address superTokenForwarder = appContracts.superTokenLockableApp.forwarderAddresses( - appContracts.superTokenLockable, - chainSlug_ - ); - address limitHookForwarder = appContracts.superTokenLockableApp.forwarderAddresses( - appContracts.limitHook, - chainSlug_ - ); - - address deployedToken = IForwarder(superTokenForwarder).getOnChainAddress(); - address deployedLimitHook = IForwarder(limitHookForwarder).getOnChainAddress(); - - PayloadDetails[] memory payloadDetails = new PayloadDetails[](1); - payloadDetails[0] = createExecutePayloadDetail( - chainSlug_, - deployedToken, - address(appContracts.superTokenLockableApp), - superTokenForwarder, - abi.encodeWithSignature("setLimitHook(address)", deployedLimitHook) - ); - - return payloadDetails; - } - - function testPredictForwarderAddress() external { - address appDeployer = address(uint160(c++)); - address chainContractAddress = address(uint160(c++)); - - address predicted = addressResolver.getForwarderAddress(chainContractAddress, evmxSlug); - address forwarder = addressResolver.getOrDeployForwarderContract( - appDeployer, - chainContractAddress, - evmxSlug - ); - - assertEq(forwarder, predicted); - } - - function testPredictPromiseAddress() external { - address invoker = address(uint160(c++)); - - address predicted = addressResolver.getAsyncPromiseAddress(invoker); - address asyncPromise = addressResolver.deployAsyncPromiseContract(invoker); - - assertEq(asyncPromise, predicted); - } - - function testContractDeployment() public { - bytes32 asyncId = _deploy( - contractIds, - arbChainSlug, - 2, - IAppGateway(appContracts.superTokenLockableApp) - ); - - (address onChainSuperToken, address forwarderSuperToken) = getOnChainAndForwarderAddresses( - arbChainSlug, - appContracts.superTokenLockable, - IAppGateway(appContracts.superTokenLockableApp) - ); - - (address onChainLimitHook, address forwarderLimitHook) = getOnChainAndForwarderAddresses( - arbChainSlug, - appContracts.limitHook, - IAppGateway(appContracts.superTokenLockableApp) - ); - - assertEq( - SuperTokenLockable(onChainSuperToken).name(), - "SUPER TOKEN", - "Token name should be correct" - ); - assertEq( - SuperTokenLockable(onChainSuperToken).decimals(), - 18, - "Token decimals should be correct" - ); - assertEq( - SuperTokenLockable(onChainSuperToken).symbol(), - "SUPER", - "Token symbol should be correct" - ); - - assertEq( - IForwarder(forwarderSuperToken).getChainSlug(), - arbChainSlug, - "Forwarder chainSlug should be correct" - ); - assertEq( - IForwarder(forwarderSuperToken).getOnChainAddress(), - onChainSuperToken, - "Forwarder onChainAddress should be correct" - ); - - assertEq( - IForwarder(forwarderLimitHook).getChainSlug(), - arbChainSlug, - "Forwarder chainSlug should be correct" - ); - assertEq( - IForwarder(forwarderLimitHook).getOnChainAddress(), - onChainLimitHook, - "Forwarder onChainAddress should be correct" - ); - assertEq( - SuperTokenLockable(onChainSuperToken).owner(), - owner, - "SuperToken owner should be correct" - ); - assertEq(LimitHook(onChainLimitHook).owner(), owner, "LimitHook owner should be correct"); - - PayloadDetails[] memory payloadDetails = createDeployPayloadDetailsArray(arbChainSlug); - checkPayloadBatchAndDetails( - payloadDetails, - asyncId, - address(appContracts.superTokenLockableApp) - ); - } - - function testConfigure() public { - _deploy(contractIds, arbChainSlug, 2, IAppGateway(appContracts.superTokenLockableApp)); - - bytes32 asyncId = _executeWriteBatchSingleChain(arbChainSlug, 1); - - (address onChainSuperToken, ) = getOnChainAndForwarderAddresses( - arbChainSlug, - appContracts.superTokenLockable, - IAppGateway(appContracts.superTokenLockableApp) - ); - (address onChainLimitHook, ) = getOnChainAndForwarderAddresses( - arbChainSlug, - appContracts.limitHook, - IAppGateway(appContracts.superTokenLockableApp) - ); - assertEq( - address(SuperTokenLockable(onChainSuperToken).limitHook__()), - address(onChainLimitHook), - "Limit hook should be correct" - ); - - PayloadDetails[] memory payloadDetails = createConfigurePayloadDetailsArray(arbChainSlug); - checkPayloadBatchAndDetails( - payloadDetails, - asyncId, - address(appContracts.superTokenLockableApp) - ); - } - - function _deployBridge() internal { - _deploy(contractIds, arbChainSlug, 2, IAppGateway(appContracts.superTokenLockableApp)); - - _executeWriteBatchSingleChain(arbChainSlug, 1); - - _deploy(contractIds, optChainSlug, 2, IAppGateway(appContracts.superTokenLockableApp)); - - _executeWriteBatchSingleChain(optChainSlug, 1); - } - - function _bridge() internal returns (bytes32, bytes32[] memory) { - _deployBridge(); - - userOrder = SuperTokenLockableAppGateway.UserOrder({ - srcToken: appContracts.superTokenLockableApp.forwarderAddresses( - appContracts.superTokenLockable, - arbChainSlug - ), - dstToken: appContracts.superTokenLockableApp.forwarderAddresses( - appContracts.superTokenLockable, - optChainSlug - ), - user: owner, // 2 account anvil - srcAmount: srcAmount, // .01 ETH in wei - deadline: 1672531199 // Unix timestamp for a future date - }); - uint32 srcChainSlug = IForwarder(userOrder.srcToken).getChainSlug(); - uint32 dstChainSlug = IForwarder(userOrder.dstToken).getChainSlug(); - bytes32 bridgeAsyncId = getNextAsyncId(); - - bytes32[] memory payloadIds = new bytes32[](4); - payloadIds[0] = getWritePayloadId( - srcChainSlug, - address(getSocketConfig(srcChainSlug).switchboard), - payloadIdCounter++ - ); - payloadIds[1] = _encodeId(evmxSlug, address(watcherPrecompile), payloadIdCounter++); - payloadIds[2] = getWritePayloadId( - dstChainSlug, - address(getSocketConfig(dstChainSlug).switchboard), - payloadIdCounter++ - ); - payloadIds[3] = getWritePayloadId( - srcChainSlug, - address(getSocketConfig(srcChainSlug).switchboard), - payloadIdCounter++ - ); - payloadIdCounter++; - - bytes memory encodedOrder = abi.encode(userOrder); - appContracts.superTokenLockableApp.bridge(encodedOrder); - bidAndEndAuction(bridgeAsyncId); - return (bridgeAsyncId, payloadIds); - } - - function testBridge() public { - (bytes32 bridgeAsyncId, bytes32[] memory payloadIds) = _bridge(); - - PayloadDetails memory payloadDetails = deliveryHelper.getPayloadIndexDetails( - bridgeAsyncId, - 0 - ); - finalizeAndExecute(payloadIds[0]); - - payloadDetails = deliveryHelper.getPayloadIndexDetails(bridgeAsyncId, 2); - vm.expectEmit(true, false, false, false); - emit FinalizeRequested( - payloadIds[2], - AsyncRequest( - address(deliveryHelper), - address(0), - transmitterEOA, - payloadDetails.target, - address(0), - payloadDetails.executionGasLimit, - 0, - bridgeAsyncId, - bytes32(0), - payloadDetails.payload, - payloadDetails.next - ) - ); - finalizeQuery(payloadIds[1], abi.encode(srcAmount)); - finalizeAndExecute(payloadIds[2]); - - payloadDetails = deliveryHelper.getPayloadIndexDetails(bridgeAsyncId, 3); - finalizeAndExecute(payloadIds[3]); - } - - function testCancel() public { - (bytes32 bridgeAsyncId, bytes32[] memory payloadIds) = _bridge(); - - finalizeAndExecute(payloadIds[0]); - - vm.expectEmit(true, true, false, true); - emit BatchCancelled(bridgeAsyncId); - finalizeQuery(payloadIds[1], abi.encode(0.001 ether)); - - bytes32[] memory cancelPayloadIds = new bytes32[](1); - uint32 srcChainSlug = IForwarder(userOrder.srcToken).getChainSlug(); - - cancelPayloadIds[0] = getWritePayloadId( - srcChainSlug, - address(getSocketConfig(srcChainSlug).switchboard), - payloadIdCounter++ - ); - - // bytes32 cancelAsyncId = getNextAsyncId(); - // bidAndEndAuction(cancelAsyncId); - // finalizeAndExecute( - // cancelPayloadIds[0], - // false - // ); - } - - // function createBridgePayloadDetailsArray( - // uint32 srcChainSlug_, - // uint32 dstChainSlug_ - // ) internal returns (PayloadDetails[] memory) { - // PayloadDetails[] memory payloadDetails = new PayloadDetails[](4); - - // address deployedSrcToken = IForwarder(userOrder.srcToken) - // .getOnChainAddress(); - // address deployedDstToken = IForwarder(userOrder.dstToken) - // .getOnChainAddress(); - - // payloadDetails[0] = createExecutePayloadDetail( - // srcChainSlug_, - // deployedSrcToken, - // address(appContracts.superTokenApp), - // userOrder.srcToken, - // abi.encodeWithSignature( - // "lockTokens(address,uint256)", - // userOrder.user, - // userOrder.srcAmount - // ) - // ); - - // payloadDetails[1] = createReadPayloadDetail( - // srcChainSlug_, - // deployedSrcToken, - // address(appContracts.superTokenApp), - // userOrder.srcToken, - // abi.encodeWithSignature("balanceOf(address)", userOrder.user) - // ); - - // payloadDetails[2] = createExecutePayloadDetail( - // dstChainSlug_, - // deployedDstToken, - // address(appContracts.superTokenApp), - // userOrder.dstToken, - // abi.encodeWithSignature( - // "mint(address,uint256)", - // userOrder.user, - // userOrder.srcAmount - // ) - // ); - - // payloadDetails[3] = createExecutePayloadDetail( - // srcChainSlug_, - // deployedSrcToken, - // address(appContracts.superTokenApp), - // userOrder.srcToken, - // abi.encodeWithSignature( - // "burn(address,uint256)", - // userOrder.user, - // userOrder.srcAmount - // ) - // ); - - // for (uint i = 0; i < payloadDetails.length; i++) { - // payloadDetails[i].next[1] = predictAsyncPromiseAddress( - // address(deliveryHelper), - // address(deliveryHelper) - // ); - // } - - // return payloadDetails; - // } - - // function createCancelPayloadDetailsArray( - // uint32 srcChainSlug_ - // ) internal returns (PayloadDetails[] memory) { - // PayloadDetails[] memory payloadDetails = new PayloadDetails[](1); - - // address deployedSrcToken = IForwarder(userOrder.srcToken) - // .getOnChainAddress(); - - // payloadDetails[0] = createExecutePayloadDetail( - // srcChainSlug_, - // deployedSrcToken, - // address(appContracts.superTokenApp), - // userOrder.srcToken, - // abi.encodeWithSignature( - // "unlockTokens(address,uint256)", - // userOrder.user, - // userOrder.srcAmount - // ) - // ); - - // payloadDetails[0].next[1] = predictAsyncPromiseAddress( - // address(deliveryHelper), - // address(deliveryHelper) - // ); - // return payloadDetails; - // } - - // function _deployBridge() internal { - // bytes32[] memory payloadIds = getWritePayloadIds( - // optChainSlug, - // getContractFactoryPlug(optChainSlug), - // 2 - // ); - // PayloadDetails[] - // memory payloadDetails = createDeployPayloadDetailsArray( - // optChainSlug - // ); - // _deploy( - // payloadIds, - // optChainSlug, - // maxFees, - // 0, - // appContracts.superTokenDeployer, - // payloadDetails - // ); - - // payloadIds = getWritePayloadIds( - // optChainSlug, - // getContractFactoryPlug(optChainSlug), - // 1 - // ); - // payloadDetails = createConfigurePayloadDetailsArray(optChainSlug); - // _executeBatchSingleChain( - // payloadIds - // ); - - // payloadIds = getWritePayloadIds( - // arbChainSlug, - // getContractFactoryPlug(arbChainSlug), - // 2 - // ); - - // payloadDetails = createDeployPayloadDetailsArray(arbChainSlug); - // _deploy( - // payloadIds, - // arbChainSlug, - // maxFees, - // 0, - // appContracts.superTokenDeployer, - // payloadDetails - // ); - - // payloadIds = getWritePayloadIds( - // arbChainSlug, - // getContractFactoryPlug(arbChainSlug), - // 1 - // ); - // payloadDetails = createConfigurePayloadDetailsArray(arbChainSlug); - // _executeBatchSingleChain( - // payloadIds - // ); - // } - - // function _bridge() - // internal - // returns (bytes32, bytes32[] memory, PayloadDetails[] memory) - // { - // _deployBridge(); - - // userOrder = SuperTokenApp.UserOrder({ - // srcToken: appContracts.superTokenDeployer.forwarderAddresses( - // appContracts.superToken, - // arbChainSlug - // ), - // dstToken: appContracts.superTokenDeployer.forwarderAddresses( - // appContracts.superToken, - // optChainSlug - // ), - // user: owner, // 2 account anvil - // srcAmount: srcAmount, // .01 ETH in wei - // deadline: 1672531199 // Unix timestamp for a future date - // }); - // uint32 srcChainSlug = IForwarder(userOrder.srcToken).getChainSlug(); - // uint32 dstChainSlug = IForwarder(userOrder.dstToken).getChainSlug(); - - // bytes32[] memory payloadIds = new bytes32[](4); - // payloadIds[0] = getWritePayloadId( - // srcChainSlug, - // address(getSocketConfig(srcChainSlug).contractFactoryPlug), - // payloadIdCounter++ - // ); - // payloadIds[1] = _encodeId(evmxSlug, address(watcherPrecompile), payloadIdCounter++); - // payloadIds[2] = getWritePayloadId( - // dstChainSlug, - // address(getSocketConfig(dstChainSlug).contractFactoryPlug), - // payloadIdCounter++ - // ); - // payloadIds[3] = getWritePayloadId( - // srcChainSlug, - // address(getSocketConfig(srcChainSlug).contractFactoryPlug), - // payloadIdCounter++ - // ); - // payloadIdCounter++; - - // PayloadDetails[] - // memory payloadDetails = createBridgePayloadDetailsArray( - // srcChainSlug, - // dstChainSlug - // ); - // bytes32 bridgeAsyncId = getNextAsyncId(); - // asyncCounterTest++; - - // bytes memory encodedOrder = abi.encode(userOrder); - // appContracts.superTokenApp.bridge(encodedOrder); - // bidAndValidate( - // maxFees, - // 0, - // bridgeAsyncId, - // address(appContracts.superTokenApp), - // payloadDetails - // ); - // return (bridgeAsyncId, payloadIds, payloadDetails); - // } - - // function testBridge() public { - // ( - // bytes32 bridgeAsyncId, - // bytes32[] memory payloadIds, - // PayloadDetails[] memory payloadDetails - // ) = _bridge(); - - // finalizeAndExecute( - // payloadIds[0], - // false, - // payloadDetails[0] - // ); - - // vm.expectEmit(true, false, false, false); - // emit FinalizeRequested( - // payloadIds[2], - // AsyncRequest( - // payloadDetails[2].next, - // address(0), - // transmitterEOA, - // payloadDetails[2].executionGasLimit, - // payloadDetails[2].payload, - // address(0), - // bytes32(0) - // ) - // ); - // finalizeQuery(payloadIds[1], abi.encode(srcAmount)); - // finalizeAndExecute( - // payloadIds[2], - // false, - // payloadDetails[2] - // ); - // finalizeAndExecute( - // payloadIds[3], - // false, - // payloadDetails[3] - // ); - // } - - // function testCancel() public { - // ( - // bytes32 bridgeAsyncId, - // bytes32[] memory payloadIds, - // PayloadDetails[] memory payloadDetails - // ) = _bridge(); - - // finalizeAndExecute( - // payloadIds[0], - // false, - // payloadDetails[0] - // ); - - // vm.expectEmit(true, true, false, true); - // emit BatchCancelled(bridgeAsyncId); - // finalizeQuery(payloadIds[1], abi.encode(0.001 ether)); - - // bytes32[] memory cancelPayloadIds = new bytes32[](1); - // uint32 srcChainSlug = IForwarder(userOrder.srcToken).getChainSlug(); - - // cancelPayloadIds[0] = getWritePayloadId( - // srcChainSlug, - // address(getSocketConfig(srcChainSlug).contractFactoryPlug), - // payloadIdCounter++ - // ); - - // PayloadDetails[] - // memory cancelPayloadDetails = createCancelPayloadDetailsArray( - // srcChainSlug - // ); - - // bytes32 cancelAsyncId = getNextAsyncId(); - // asyncCounterTest++; - - // bidAndValidate( - // maxFees, - // 0, - // cancelAsyncId, - // address(appContracts.superTokenApp), - // cancelPayloadDetails - // ); - // finalizeAndExecute( - // cancelPayloadIds[0], - // false, - // cancelPayloadDetails[0] - // ); - // } -} diff --git a/test/apps/app-gateways/counter/Counter.sol b/test/apps/app-gateways/counter/Counter.sol index b4d585ef..9625635d 100644 --- a/test/apps/app-gateways/counter/Counter.sol +++ b/test/apps/app-gateways/counter/Counter.sol @@ -6,9 +6,10 @@ import "../../../../contracts/base/PlugBase.sol"; contract Counter is Ownable, PlugBase { uint256 public counter; - + event CounterIncreased(uint256 value); function increase() external onlySocket { counter++; + emit CounterIncreased(counter); } function getCounter() external view returns (uint256) { diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index bb415e70..deef0e53 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -13,14 +13,11 @@ contract CounterAppGateway is AppGatewayBase, Ownable { uint256 public counterVal; - uint256 arbCounter; - uint256 optCounter; + uint256 public arbCounter; + uint256 public optCounter; event TimeoutResolved(uint256 creationTimestamp, uint256 executionTimestamp); - constructor( - address addressResolver_, - Fees memory fees_ - ) AppGatewayBase(addressResolver_) { + constructor(address addressResolver_, Fees memory fees_) AppGatewayBase(addressResolver_) { creationCodeWithArgs[counter] = abi.encodePacked(type(Counter).creationCode); creationCodeWithArgs[counter1] = abi.encodePacked(type(Counter).creationCode); _setOverrides(fees_); @@ -32,6 +29,10 @@ contract CounterAppGateway is AppGatewayBase, Ownable { _deploy(counter, chainSlug_, IsPlug.YES); } + function deployContractsWithoutAsync(uint32 chainSlug_) external { + _deploy(counter, chainSlug_, IsPlug.YES); + } + function deployParallelContracts(uint32 chainSlug_) external async { _setOverrides(Parallel.ON); _deploy(counter, chainSlug_, IsPlug.YES); @@ -77,7 +78,13 @@ contract CounterAppGateway is AppGatewayBase, Ownable { IPromise(instances_[i]).then(this.setCounterValues.selector, abi.encode(chainSlug)); } _setOverrides(Read.OFF, Parallel.OFF); - ICounter(instances_[0]).increase(); + } + + function readCounterAtBlock(address instance_, uint256 blockNumber_) public async { + uint32 chainSlug = IForwarder(instance_).getChainSlug(); + _setOverrides(Read.ON, Parallel.ON, blockNumber_); + ICounter(instance_).getCounter(); + IPromise(instance_).then(this.setCounterValues.selector, abi.encode(chainSlug)); } function setCounterValues(bytes memory data, bytes memory returnData) external onlyPromises { @@ -92,14 +99,14 @@ contract CounterAppGateway is AppGatewayBase, Ownable { // INBOX function setIsValidPlug(uint32 chainSlug_, address plug_) public { - watcherPrecompile__().setIsValidPlug(chainSlug_, plug_, true); + watcherPrecompileConfig().setIsValidPlug(chainSlug_, plug_, true); } function callFromChain( uint32, address, - bytes calldata payload_, - bytes32 + bytes32, + bytes calldata payload_ ) external override onlyWatcherPrecompile { uint256 value = abi.decode(payload_, (uint256)); counterVal += value; @@ -111,7 +118,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { this.resolveTimeout.selector, block.timestamp ); - watcherPrecompile__().setTimeout(address(this), payload, delayInSeconds_); + watcherPrecompile__().setTimeout(delayInSeconds_, payload); } function resolveTimeout(uint256 creationTimestamp_) external onlyWatcherPrecompile { @@ -119,7 +126,6 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } // UTILS - function setFees(Fees memory fees_) public { fees = fees_; } @@ -129,7 +135,26 @@ contract CounterAppGateway is AppGatewayBase, Ownable { address token_, uint256 amount_, address receiver_ - ) external { - _withdrawFeeTokens(chainSlug_, token_, amount_, receiver_); + ) external returns (uint40) { + return _withdrawFeeTokens(chainSlug_, token_, amount_, receiver_); + } + + function testOnChainRevert(uint32 chainSlug) public async { + address instance = forwarderAddresses[counter][chainSlug]; + ICounter(instance).wrongFunction(); + } + + function testCallBackRevert(uint32 chainSlug) public async { + // the increase function is called on given list of instances + _setOverrides(Read.ON, Parallel.ON); + address instance = forwarderAddresses[counter][chainSlug]; + ICounter(instance).getCounter(); + // wrong function call in callback so it reverts + IPromise(instance).then(this.withdrawFeeTokens.selector, abi.encode(chainSlug)); + _setOverrides(Read.OFF, Parallel.OFF); + } + + function increaseFees(uint40 requestCount_, uint256 newMaxFees_) public { + _increaseFees(requestCount_, newMaxFees_); } } diff --git a/test/apps/app-gateways/counter/ICounter.sol b/test/apps/app-gateways/counter/ICounter.sol index 6e254974..0bb3b319 100644 --- a/test/apps/app-gateways/counter/ICounter.sol +++ b/test/apps/app-gateways/counter/ICounter.sol @@ -5,4 +5,7 @@ interface ICounter { function increase() external; function getCounter() external; + + // A function that is not part of the interface, used for testing on-chian revert. + function wrongFunction() external; } diff --git a/test/apps/app-gateways/super-token-lockable/LimitHook.sol b/test/apps/app-gateways/super-token-lockable/LimitHook.sol deleted file mode 100644 index d2ac0939..00000000 --- a/test/apps/app-gateways/super-token-lockable/LimitHook.sol +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {Ownable} from "solady/auth/Ownable.sol"; -import "../../../../contracts/base/PlugBase.sol"; - -contract LimitHook is Ownable, PlugBase { - // Define any state variables or functions for the LimitHook contract here - uint256 public burnLimit; - uint256 public mintLimit; - - error BurnLimitExceeded(); - error MintLimitExceeded(); - error InvalidSender(); - - constructor(uint256 _burnLimit_, uint256 _mintLimit_) { - burnLimit = _burnLimit_; - mintLimit = _mintLimit_; - } - - function setLimits(uint256 _burnLimit_, uint256 _mintLimit_) external onlyOwner { - burnLimit = _burnLimit_; - mintLimit = _mintLimit_; - } - - function beforeBurn(uint256 amount_) external view { - if (amount_ > burnLimit) revert BurnLimitExceeded(); - } - - function beforeMint(uint256 amount_) external view { - if (amount_ > mintLimit) revert MintLimitExceeded(); - } - - function setOwner(address owner_) external { - if (owner() != address(0) && owner() != msg.sender) revert InvalidSender(); - _initializeOwner(owner_); - } - - function connectSocket( - address appGateway_, - address socket_, - address switchboard_ - ) external onlyOwner { - _connectSocket(appGateway_, socket_, switchboard_); - } -} diff --git a/test/apps/app-gateways/super-token-lockable/SuperTokenLockable.sol b/test/apps/app-gateways/super-token-lockable/SuperTokenLockable.sol deleted file mode 100644 index 5aec4aec..00000000 --- a/test/apps/app-gateways/super-token-lockable/SuperTokenLockable.sol +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.21; - -import "solmate/tokens/ERC20.sol"; -import {Ownable} from "solady/auth/Ownable.sol"; -import {LimitHook} from "./LimitHook.sol"; -import "../../../../contracts/base/PlugBase.sol"; - -/** - * @title SuperToken - * @notice An ERC20 contract which enables bridging a token to its sibling chains. - */ -contract SuperTokenLockable is ERC20, Ownable, PlugBase { - LimitHook public limitHook__; - mapping(address => uint256) public lockedTokens; - - error InsufficientBalance(); - error InsufficientLockedTokens(); - error InvalidSender(); - - constructor( - string memory name_, - string memory symbol_, - uint8 decimals_, - address initialSupplyHolder_, - uint256 initialSupply_ - ) ERC20(name_, symbol_, decimals_) { - _mint(initialSupplyHolder_, initialSupply_); - } - - function lockTokens(address user_, uint256 amount_) external onlySocket { - if (balanceOf[user_] < amount_) revert InsufficientBalance(); - limitHook__.beforeBurn(amount_); - - lockedTokens[user_] += amount_; - _burn(user_, amount_); - } - - function mint(address receiver_, uint256 amount_) external onlySocket { - limitHook__.beforeMint(amount_); - _mint(receiver_, amount_); - } - - function burn(address user_, uint256 amount_) external onlySocket { - lockedTokens[user_] -= amount_; - } - - function unlockTokens(address user_, uint256 amount_) external onlySocket { - if (lockedTokens[user_] < amount_) revert InsufficientLockedTokens(); - lockedTokens[user_] -= amount_; - _mint(user_, amount_); - } - - function setSocket(address newSocket_) external onlyOwner { - _setSocket(newSocket_); - } - - function setLimitHook(address limitHook_) external onlySocket { - limitHook__ = LimitHook(limitHook_); - } - - function setOwner(address owner_) external { - if (owner() != address(0) && owner() != msg.sender) revert InvalidSender(); - _initializeOwner(owner_); - } -} diff --git a/test/apps/app-gateways/super-token-lockable/SuperTokenLockableAppGateway.sol b/test/apps/app-gateways/super-token-lockable/SuperTokenLockableAppGateway.sol deleted file mode 100644 index e20bca57..00000000 --- a/test/apps/app-gateways/super-token-lockable/SuperTokenLockableAppGateway.sol +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.21; - -import "solady/auth/Ownable.sol"; -import {ISuperToken} from "../super-token/ISuperToken.sol"; -import "../../../../contracts/base/AppGatewayBase.sol"; -import "./SuperTokenLockable.sol"; -import "./LimitHook.sol"; - -contract SuperTokenLockableAppGateway is AppGatewayBase, Ownable { - bytes32 public superTokenLockable = _createContractId("superTokenLockable"); - bytes32 public limitHook = _createContractId("limitHook"); - - event Bridged(bytes32 asyncId); - - struct UserOrder { - address srcToken; - address dstToken; - address user; - uint256 srcAmount; - uint256 deadline; - } - - struct ConstructorParams { - uint256 _burnLimit; - uint256 _mintLimit; - string name_; - string symbol_; - uint8 decimals_; - address initialSupplyHolder_; - uint256 initialSupply_; - } - - constructor( - address addressResolver_, - address owner_, - Fees memory fees_, - ConstructorParams memory params - ) AppGatewayBase(addressResolver_) { - creationCodeWithArgs[superTokenLockable] = abi.encodePacked( - type(SuperTokenLockable).creationCode, - abi.encode( - params.name_, - params.symbol_, - params.decimals_, - params.initialSupplyHolder_, - params.initialSupply_ - ) - ); - - creationCodeWithArgs[limitHook] = abi.encodePacked( - type(LimitHook).creationCode, - abi.encode(params._burnLimit, params._mintLimit) - ); - - _setOverrides(fees_); - _initializeOwner(owner_); - } - - function deployContracts(uint32 chainSlug_) external async { - bytes memory initData = abi.encodeWithSelector( - SuperTokenLockable.setOwner.selector, - owner() - ); - _deploy(superTokenLockable, chainSlug_, IsPlug.YES, initData); - _deploy(limitHook, chainSlug_, IsPlug.YES, initData); - } - - // don't need to call this directly, will be called automatically after all contracts are deployed. - // check AppGatewayBase.onBatchComplete - function initialize(uint32 chainSlug_) public override async { - address limitHookContract = getOnChainAddress(limitHook, chainSlug_); - SuperTokenLockable(forwarderAddresses[superTokenLockable][chainSlug_]).setLimitHook( - limitHookContract - ); - } - - function checkBalance(bytes memory data_, bytes memory returnData_) external onlyPromises { - (UserOrder memory order, bytes32 asyncId) = abi.decode(data_, (UserOrder, bytes32)); - - uint256 balance = abi.decode(returnData_, (uint256)); - if (balance < order.srcAmount) { - _revertTx(asyncId); - return; - } - _unlockTokens(order.srcToken, order.user, order.srcAmount); - } - - function _unlockTokens(address srcToken_, address user_, uint256 amount_) internal async { - ISuperToken(srcToken_).unlockTokens(user_, amount_); - } - - function bridge(bytes memory order_) external async returns (bytes32 asyncId_) { - UserOrder memory order = abi.decode(order_, (UserOrder)); - asyncId_ = _getCurrentAsyncId(); - ISuperToken(order.srcToken).lockTokens(order.user, order.srcAmount); - - _setOverrides(Read.ON); - // goes to forwarder and deploys promise and stores it - ISuperToken(order.srcToken).balanceOf(order.user); - IPromise(order.srcToken).then(this.checkBalance.selector, abi.encode(order, asyncId_)); - - _setOverrides(Read.OFF); - ISuperToken(order.dstToken).mint(order.user, order.srcAmount); - ISuperToken(order.srcToken).burn(order.user, order.srcAmount); - - emit Bridged(asyncId_); - } - - function withdrawFeeTokens( - uint32 chainSlug_, - address token_, - uint256 amount_, - address receiver_ - ) external onlyOwner { - _withdrawFeeTokens(chainSlug_, token_, amount_, receiver_); - } -} diff --git a/test/apps/app-gateways/super-token/SuperToken.sol b/test/apps/app-gateways/super-token/SuperToken.sol index 4d7dfe05..8c6de970 100644 --- a/test/apps/app-gateways/super-token/SuperToken.sol +++ b/test/apps/app-gateways/super-token/SuperToken.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.21; -import "solmate/tokens/ERC20.sol"; +import "solady/tokens/ERC20.sol"; import {Ownable} from "solady/auth/Ownable.sol"; import "../../../../contracts/base/PlugBase.sol"; @@ -10,16 +10,23 @@ import "../../../../contracts/base/PlugBase.sol"; * @notice An ERC20 contract which enables bridging a token to its sibling chains. */ contract SuperToken is ERC20, Ownable, PlugBase { + string private _name; + string private _symbol; + uint8 private _decimals; mapping(address => uint256) public lockedTokens; error InvalidSender(); + constructor( string memory name_, string memory symbol_, uint8 decimals_, address initialSupplyHolder_, uint256 initialSupply_ - ) ERC20(name_, symbol_, decimals_) { + ) { + _name = name_; + _symbol = symbol_; + _decimals = decimals_; _mint(initialSupplyHolder_, initialSupply_); } @@ -31,6 +38,18 @@ contract SuperToken is ERC20, Ownable, PlugBase { _burn(user_, amount_); } + function name() public view virtual override returns (string memory) { + return _name; + } + + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + function decimals() public view virtual override returns (uint8) { + return _decimals; + } + function setSocket(address newSocket_) external onlyOwner { _setSocket(newSocket_); } diff --git a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol index 08fd2eac..c1cd0457 100644 --- a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol +++ b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol @@ -8,8 +8,7 @@ import "./SuperToken.sol"; contract SuperTokenAppGateway is AppGatewayBase, Ownable { bytes32 public superToken = _createContractId("superToken"); - - event Transferred(bytes32 asyncId); + event Transferred(uint40 requestCount); struct ConstructorParams { string name_; @@ -56,7 +55,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.onBatchComplete + // check AppGatewayBase._deploy and AppGatewayBase.onRequestComplete function initialize(uint32) public pure override { return; } diff --git a/test/mock/MockSocket.sol b/test/mock/MockSocket.sol index 98c87f09..da1765a9 100644 --- a/test/mock/MockSocket.sol +++ b/test/mock/MockSocket.sol @@ -113,13 +113,17 @@ contract MockSocket is ISocket { * @notice Executes a payload that has been delivered by transmitters and authenticated by switchboards */ function execute( - address, - ExecuteParams memory params_, - bytes memory - ) external payable returns (bytes memory) { + ExecuteParams memory executeParams_, + bytes memory transmitterSignature_ + ) external payable override returns (bytes memory) { // execute payload - return - _execute(params_.target, params_.payloadId, params_.executionGasLimit, params_.payload); + // return + // _execute( + // executeParams_.target, + // executeParams_.payloadId, + // executeParams_.gasLimit, + // executeParams_.payload + // ); } //////////////////////////////////////////////////////// diff --git a/test/mock/MockWatcherPrecompile.sol b/test/mock/MockWatcherPrecompile.sol index d1886b89..42247124 100644 --- a/test/mock/MockWatcherPrecompile.sol +++ b/test/mock/MockWatcherPrecompile.sol @@ -5,7 +5,7 @@ import "../../contracts/interfaces/IAppGateway.sol"; import "../../contracts/interfaces/IWatcherPrecompile.sol"; import "../../contracts/interfaces/IPromise.sol"; -import {PayloadDigestParams, AsyncRequest, FinalizeParams, TimeoutRequest, CallFromChainParams, PlugConfig, ResolvedPromises, AppGatewayConfig} from "../../contracts/protocol/utils/common/Structs.sol"; +import {TimeoutRequest, CallFromChainParams, PlugConfig, ResolvedPromises, AppGatewayConfig} from "../../contracts/protocol/utils/common/Structs.sol"; import {QUERY, FINALIZE, SCHEDULE} from "../../contracts/protocol/utils/common/Constants.sol"; import {TimeoutDelayTooLarge, TimeoutAlreadyResolved, InvalidInboxCaller, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled} from "../../contracts/protocol/utils/common/Errors.sol"; import "solady/utils/ERC1967Factory.sol"; @@ -14,15 +14,10 @@ import "solady/utils/ERC1967Factory.sol"; /// @notice Contract that handles payload verification, execution and app configurations contract MockWatcherPrecompile { uint256 public maxTimeoutDelayInSeconds = 24 * 60 * 60; // 24 hours - /// @notice Counter for tracking query requests - uint256 public queryCounter; /// @notice Counter for tracking payload execution requests uint256 public payloadCounter; /// @notice Counter for tracking timeout requests uint256 public timeoutCounter; - /// @notice Mapping to store async requests - /// @dev payloadId => AsyncRequest struct - mapping(bytes32 => AsyncRequest) public asyncRequests; /// @notice Mapping to store timeout requests /// @dev timeoutId => TimeoutRequest struct mapping(bytes32 => TimeoutRequest) public timeoutRequests; @@ -50,15 +45,12 @@ contract MockWatcherPrecompile { event QueryRequested(uint32 chainSlug, address targetAddress, bytes32 payloadId, bytes payload); /// @notice Emitted when a finalize request is made - /// @param payloadId The unique identifier for the request - /// @param asyncRequest The async request details - event FinalizeRequested(bytes32 indexed payloadId, AsyncRequest asyncRequest); + event FinalizeRequested(bytes32 digest, PayloadParams params); /// @notice Emitted when a request is finalized /// @param payloadId The unique identifier for the request - /// @param asyncRequest The async request details /// @param proof The proof from the watcher - event Finalized(bytes32 indexed payloadId, AsyncRequest asyncRequest, bytes proof); + event Finalized(bytes32 indexed payloadId, bytes proof); /// @notice Emitted when a promise is resolved /// @param payloadId The unique identifier for the resolved promise @@ -122,35 +114,11 @@ contract MockWatcherPrecompile { /// @notice Finalizes a payload request, requests the watcher to release the proofs to execute on chain /// @param params_ The finalization parameters - /// @return payloadId The unique identifier for the finalized request /// @return digest The digest of the payload parameters - function finalize( - FinalizeParams memory params_ - ) external returns (bytes32 payloadId, bytes32 digest) { + function finalize(PayloadParams memory params_) external returns (bytes32 digest) { digest = keccak256(abi.encode(block.timestamp)); // Generate a unique payload ID by combining chain, target, and counter - payloadId = encodePayloadId( - params_.payloadDetails.chainSlug, - params_.payloadDetails.target, - payloadCounter++ - ); - address[] memory next = new address[](1); - emit FinalizeRequested( - payloadId, - AsyncRequest( - msg.sender, - address(0), - address(0), - params_.payloadDetails.target, - address(0), - 0, - block.timestamp + 1000, - params_.asyncId, - bytes32(0), - bytes(""), - next - ) - ); + emit FinalizeRequested(digest, params_); } // ================== Query functions ================== @@ -165,7 +133,7 @@ contract MockWatcherPrecompile { address[] memory, bytes memory payload ) public returns (bytes32 payloadId) { - payloadId = bytes32(queryCounter++); + payloadId = bytes32(payloadCounter++); emit QueryRequested(chainSlug, targetAddress, payloadId, payload); } @@ -174,7 +142,7 @@ contract MockWatcherPrecompile { /// @param proof_ The watcher's proof /// @dev Only callable by the contract owner function finalized(bytes32 payloadId_, bytes calldata proof_) external { - emit Finalized(payloadId_, asyncRequests[payloadId_], proof_); + emit Finalized(payloadId_, proof_); } /// @notice Resolves multiple promises with their return data diff --git a/test/mock/MockWatcherPrecompileImpl.sol b/test/mock/MockWatcherPrecompileImpl.sol index 0298e103..e888a9bb 100644 --- a/test/mock/MockWatcherPrecompileImpl.sol +++ b/test/mock/MockWatcherPrecompileImpl.sol @@ -5,18 +5,9 @@ import "../../contracts/protocol/watcherPrecompile/WatcherPrecompile.sol"; contract MockWatcherPrecompileImpl is WatcherPrecompile { // Mock function to test reinitialization with version 2 - function mockReinitialize( - address owner_, - address addressResolver_, - uint256 defaultLimit_ - ) external reinitializer(2) { + function mockReinitialize(address owner_, address addressResolver_) external reinitializer(2) { _setAddressResolver(addressResolver_); _initializeOwner(owner_); maxTimeoutDelayInSeconds = 24 * 60 * 60; // 24 hours - - // limit per day - defaultLimit = defaultLimit_ * 10 ** LIMIT_DECIMALS; - // limit per second - defaultRatePerSecond = defaultLimit / (24 * 60 * 60); } } diff --git a/testScript.sh b/testScript.sh deleted file mode 100644 index c3a1f30c..00000000 --- a/testScript.sh +++ /dev/null @@ -1,61 +0,0 @@ - - -## Parallel Counter -source .env && forge script script/parallel-counter/deployOnEVMx.s.sol --broadcast --skip-simulation -## set limits for the app gateway using API -source .env && cast send $APP_GATEWAY "deployMultiChainContracts(uint32[])" '[421614, 11155420]' --private-key $PRIVATE_KEY -source .env && forge script script/parallel-counter/checkCounters.s.sol --broadcast --skip-simulation - - -## Counter -source .env && forge script script/counter/deployEVMxCounterApp.s.sol --broadcast --skip-simulation --legacy --gas-price 0 -source .env && forge script script/counter/DeployCounterOnchain.s.sol --broadcast --skip-simulation -## set limits for the app gateway using API -source .env && cast send $APP_GATEWAY "deployContracts(uint32)" 421614 --private-key $PRIVATE_KEY --legacy --gas-price 0 -cast call $APP_GATEWAY "getOnChainAddress(bytes32,uint32)(address)" 0x5ab1536adcb0c297300e651c684f844c311727059d17eb2be15c313b5839b9eb 421614 -cast call $APP_GATEWAY "forwarderAddresses(bytes32,uint32)(address)" 0x5ab1536adcb0c297300e651c684f844c311727059d17eb2be15c313b5839b9eb 421614 -source .env && cast send $APP_GATEWAY "incrementCounters(address[])" '[0xB491b4b9343471d79d33A7c45Dc4d0a7EA818F93]' --private-key $PRIVATE_KEY --legacy --gas-price 0 -source .env && cast send $APP_GATEWAY "readCounters(address[])" '[0x18a93d520879524e0c215b64f05914da5883540f]' --private-key $PRIVATE_KEY --legacy --gas-price 0 -source .env && cast send $APP_GATEWAY "withdrawFeeTokens(uint32,address,uint256,address)" 421614 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 987793576908782 0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18 --private-key $PRIVATE_KEY --legacy --gas-price 0 - -forge script script/counter/incrementCounters.s.sol --broadcast --skip-simulation -forge script script/counter/checkCounters.s.sol --broadcast --skip-simulation - -## Cron -source .env && forge script script/cron/DeployGateway.s.sol:DeployGateway --broadcast --skip-simulation -source .env && forge script script/cron/SetTimeout.s.sol:SetTimeoutScript --broadcast --skip-simulation -source .env && cast send $APP_GATEWAY "setTimeout(uint256)" 0 --private-key $PRIVATE_KEY - -## Super Token Lockable -forge script script/super-token-lockable/DeployGateway.s.sol --broadcast --skip-simulation -source .env && cast send $APP_GATEWAY "deployContracts(uint32)" 421614 --private-key $PRIVATE_KEY -source .env && cast send $APP_GATEWAY "deployContracts(uint32)" 11155420 --private-key $PRIVATE_KEY -forge script script/super-token-lockable/Bridge.s.sol --broadcast --skip-simulation -source .env && cast send $APP_GATEWAY $data --private-key $PRIVATE_KEY - - -## Counter Inbox -source .env && forge script script/counter-inbox/DeployCounterAndGateway.s.sol --broadcast --skip-simulation -source .env && cast send $COUNTER_INBOX "connectSocket(address,address,address)" $APP_GATEWAY $SOCKET $SWITCHBOARD --rpc-url $ARBITRUM_SEPOLIA_RPC --private-key $SPONSOR_KEY -source .env && cast send $COUNTER_INBOX "increaseOnGateway(uint256)" 100 --rpc-url $ARBITRUM_SEPOLIA_RPC --private-key $SPONSOR_KEY -source .env && forge script script/counter-inbox/CheckGatewayCounter.s.sol --broadcast --skip-simulation - - - -## Mock Testing -source .env && forge script script/mock/DeployEVMx.s.sol --broadcast --skip-simulation -source .env && forge script script/mock/DeploySocket.s.sol --broadcast --skip-simulation -source .env && forge script script/mock/Timeout.s.sol --broadcast --skip-simulation -source .env && forge script script/mock/Query.s.sol --broadcast --skip-simulation -source .env && forge script script/mock/Inbox.s.sol --broadcast --skip-simulation -source .env && forge script script/mock/FinalizeAndExecution.s.sol --broadcast --skip-simulation - - -## Check Limits -source .env && forge script script/admin/checkLimits.s.sol --broadcast --skip-simulation -source .env && forge script script/admin/UpdateLimits.s.sol --broadcast --skip-simulation - - -# add fees -source .env && forge script script/helpers/PayFeesInArbitrumETH.s.sol --broadcast --skip-simulation -source .env && forge script script/helpers/AppGatewayFeeBalance.s.sol diff --git a/tsconfig.json b/tsconfig.json index 39cbab7d..7356b140 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "moduleResolution": "Node", "allowSyntheticDefaultImports": true, "esModuleInterop": true, + "types": ["node"], "importHelpers": true, "resolveJsonModule": true, "sourceMap": true, diff --git a/yarn.lock b/yarn.lock index 3cf308a7..74278d03 100644 --- a/yarn.lock +++ b/yarn.lock @@ -558,6 +558,11 @@ "@smithy/types" "^4.1.0" tslib "^2.6.2" +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -2071,21 +2076,21 @@ "@smithy/types" "^4.1.0" tslib "^2.6.2" -"@socket.tech/socket-protocol-common@1.1.31": - version "1.1.31" - resolved "https://registry.yarnpkg.com/@socket.tech/socket-protocol-common/-/socket-protocol-common-1.1.31.tgz#d95b1b6caf69a11c6bd13b18b7871c57e7d283fb" - integrity sha512-Hp1er4kRqCfeuvQFFgxooT0XBbO4nBrpL8/SYB/BNMdWfR9hk6PVE8MUnoIqTUJJTvIePKk+GOajl8MVqPD3VQ== +"@socket.tech/socket-protocol-common@1.1.44": + version "1.1.44" + resolved "https://registry.yarnpkg.com/@socket.tech/socket-protocol-common/-/socket-protocol-common-1.1.44.tgz#ee78da13cad3e5544ceed5a352ef7988c55e4044" + integrity sha512-ntrx/71ETxl4xN62F+D8jVNWUMrrpReLUX16DK9M1oAggQHBT1mem4e9EhvoRBriXFmGBmFHs1xJ35BvHsFPDQ== dependencies: - "@socket.tech/socket-protocol" "^1.0.15" + "@socket.tech/socket-protocol" "1.0.16" axios "^1.7.9" ethers "^5.6.5" pino "^9.6.0" sequelize "^6.21.6" -"@socket.tech/socket-protocol@^1.0.15": - version "1.0.15" - resolved "https://registry.yarnpkg.com/@socket.tech/socket-protocol/-/socket-protocol-1.0.15.tgz#091eaaf954a58658fa74370880a6fe54f09a7ee8" - integrity sha512-aBDYdpFkQro+NVNGUbridJQbtGSEk9ZoqMmtRPA+ti0gT0X2ZAryta0lS2TfqsL4sF2fqbmz1Vd+IuK3wb5dTg== +"@socket.tech/socket-protocol@1.0.16": + version "1.0.16" + resolved "https://registry.yarnpkg.com/@socket.tech/socket-protocol/-/socket-protocol-1.0.16.tgz#06820a213fa8d0661d3c22b3f871db4058ef1440" + integrity sha512-8r68OPqld3fzitu53SDuwGOCEHxECF+6GKBRQ8UtyDS6sAt3HHYGXdYGJ8sYvLtwZePwplautRKVcpDwk/LAgg== "@solidity-parser/parser@^0.19.0": version "0.19.0" @@ -2178,6 +2183,13 @@ dependencies: undici-types "~6.20.0" +"@types/node@^22.13.9": + version "22.13.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.9.tgz#5d9a8f7a975a5bd3ef267352deb96fb13ec02eca" + integrity sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw== + dependencies: + undici-types "~6.20.0" + "@types/pbkdf2@^3.0.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.2.tgz#2dc43808e9985a2c69ff02e2d2027bd4fe33e8dc" @@ -2190,6 +2202,14 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== +"@types/prompts@^2.4.9": + version "2.4.9" + resolved "https://registry.yarnpkg.com/@types/prompts/-/prompts-2.4.9.tgz#8775a31e40ad227af511aa0d7f19a044ccbd371e" + integrity sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA== + dependencies: + "@types/node" "*" + kleur "^3.0.3" + "@types/qs@^6.9.7": version "6.9.18" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.18.tgz#877292caa91f7c1b213032b34626505b746624c2" @@ -2577,7 +2597,7 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.1.0, chalk@^4.1.2: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -2629,6 +2649,15 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== +cli-table3@^0.6.0: + version "0.6.5" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f" + integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== + dependencies: + string-width "^4.2.0" + optionalDependencies: + "@colors/colors" "1.5.0" + cliui@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" @@ -3153,11 +3182,6 @@ follow-redirects@^1.0.0, follow-redirects@^1.12.1, follow-redirects@^1.14.0, fol resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== -forge-std@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/forge-std/-/forge-std-1.1.2.tgz#f4a0eda103538d56f9c563f3cd1fa2fd01bd9378" - integrity sha512-Wfb0iAS9PcfjMKtGpWQw9mXzJxrWD62kJCUqqLcyuI0+VRtJ3j20XembjF3kS20qELYdXft1vD/SPFVWVKMFOw== - form-data@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.2.tgz#35cabbdd30c3ce73deb2c42d3c8d3ed9ca51794c" @@ -3343,6 +3367,15 @@ hardhat-change-network@^0.0.7: resolved "https://registry.yarnpkg.com/hardhat-change-network/-/hardhat-change-network-0.0.7.tgz#9f9b7943ff966515658b70bf5e44bc2f073af402" integrity sha512-Usp9fJan9SOJnOlVcv/jMJDchseE7bIDA5ZsBnracgVk4MiBwkvMqpmLWn5G1aDBvnUCthvS2gO3odfahgkV0Q== +hardhat-contract-sizer@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/hardhat-contract-sizer/-/hardhat-contract-sizer-2.10.0.tgz#72646f43bfe50e9a5702c9720c9bc3e77d93a2c9" + integrity sha512-QiinUgBD5MqJZJh1hl1jc9dNnpJg7eE/w4/4GEnrcmZJJTDbVFNe3+/3Ep24XqISSkYxRz36czcPHKHd/a0dwA== + dependencies: + chalk "^4.0.0" + cli-table3 "^0.6.0" + strip-ansi "^6.0.0" + hardhat-deploy@0.11.20: version "0.11.20" resolved "https://registry.yarnpkg.com/hardhat-deploy/-/hardhat-deploy-0.11.20.tgz#d95499a0d29b75f1f1d3838c9a3eb6d2d0d20f57" @@ -3591,6 +3624,11 @@ inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, i resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + io-ts@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.10.4.tgz#cd5401b138de88e4f920adbcb7026e2d1967e6e2" @@ -3713,6 +3751,11 @@ klaw@^1.0.0: optionalDependencies: graceful-fs "^4.1.9" +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + level-supports@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" @@ -4095,6 +4138,14 @@ path-starts-with@^2.0.0: resolved "https://registry.yarnpkg.com/path-starts-with/-/path-starts-with-2.0.1.tgz#cd8b6213c141a9f2dd86c748310acdfa6493abb1" integrity sha512-wZ3AeiRBRlNwkdUxvBANh0+esnt38DLffHDujZyRHkqkaKHTglnY2EP5UX3b8rdeiSutgO4y9NEJwXezNP5vHg== +path@^0.12.7: + version "0.12.7" + resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" + integrity sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q== + dependencies: + process "^0.11.1" + util "^0.10.3" + pbkdf2@^3.0.17: version "3.1.2" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" @@ -4191,6 +4242,19 @@ process-warning@^4.0.0: resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-4.0.1.tgz#5c1db66007c67c756e4e09eb170cdece15da32fb" integrity sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q== +process@^0.11.1: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + +prompts@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -4493,6 +4557,11 @@ side-channel@^1.1.0: side-channel-map "^1.0.1" side-channel-weakmap "^1.0.2" +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + slice-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" @@ -4836,6 +4905,13 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"