diff --git a/README.md b/README.md index 350abab..dc4793a 100644 --- a/README.md +++ b/README.md @@ -228,17 +228,13 @@ interface IWormholeReceiver { * * NOTE: This function should be restricted such that only the Wormhole Relayer contract can call it. * - * We also recommend that this function: - * - Stores all received `deliveryHash`s in a mapping `(bytes32 => bool)`, and - * on every call, checks that deliveryHash has not already been stored in the - * map (This is to prevent other users maliciously trying to relay the same message) - * - Checks that `sourceChain` and `sourceAddress` are indeed who + * We also recommend that this function checks that `sourceChain` and `sourceAddress` are indeed who * you expect to have requested the calling of `send` on the source chain * * The invocation of this function corresponding to the `send` request will have msg.value equal * to the receiverValue specified in the send request. * - * If the invocation of this function reverts or exceeds the gas limit + * If the invocation of this function reverts or exceeds the gas limit * specified by the send requester, this delivery will result in a `ReceiverFailure`. * * @param payload - an arbitrary message which was included in the delivery by the @@ -276,48 +272,6 @@ So, in receiveWormholeMessages, we want to: To provide certainty about the validity of the payload, we must restrict the msg.sender of this function to only be the Wormhole Relayer contract. Otherwise, anyone could call this receiveWormholeMessages endpoint with fake greetings, source chains, and source senders. -### One more step - -You should store each delivery hash in a mapping from delivery hashes to booleans, to prevent duplicate processing of deliveries! This also gives you a way of tracking the completion of sent deliveries - -```solidity - event GreetingReceived(string greeting, uint16 senderChain, address sender); - - string public latestGreeting; - - mapping(bytes32 => bool) public seenDeliveryVaaHashes; - - /** - * @notice Endpoint that the Wormhole Relayer contract will call - * to deliver the greeting - */ - function receiveWormholeMessages( - bytes memory payload, - bytes[] memory, // additionalVaas - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 // deliveryHash - ) public payable override { - require(msg.sender == address(wormholeRelayer), "Only relayer allowed"); - - // Ensure no duplicate deliveries - require(!seenDeliveryVaaHashes[deliveryHash], "Message already processed"); - seenDeliveryVaaHashes[deliveryHash] = true; - - // Parse the payload and do the corresponding actions! - - (string memory greeting, address sender) = abi.decode(payload, (string, address)); - - latestGreeting = greeting; - - emit GreetingReceived( - latestGreeting, - sourceChain, - fromWormholeFormat(sourceAddress) - ); - } -``` - And voila, we have a full contract that can be deployed to many EVM chains, and in totality would form a full cross-chain application powered by Wormhole! Users with any wallet can request greetings to be emitted on any chain that is part of the system. diff --git a/package-lock.json b/package-lock.json index 1834739..363f19f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "Apache 2.0", "dependencies": { - "@certusone/wormhole-sdk": "^0.9.20", + "@certusone/wormhole-sdk": "^0.10.5", "@improbable-eng/grpc-web-node-http-transport": "^0.15.0", "@typechain/ethers-v5": "^11.0.0", "ethers": "^5", @@ -606,9 +606,9 @@ "dev": true }, "node_modules/@certusone/wormhole-sdk": { - "version": "0.9.20", - "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.9.20.tgz", - "integrity": "sha512-sHmvqK0FYUa+NCO+kqPQ7CkPrFnl40pGQ8pmp3KW/xn3ECz7ECA3M1/07UvMNzcifbHwM1nmO0QhkEAjREB8wg==", + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.10.5.tgz", + "integrity": "sha512-wKONuigkakoFx9HplBt2Jh5KPxc7xgtDJVrIb2/SqYWbFrdpiZrMC4H6kTZq2U4+lWtqaCa1aJ1q+3GOTNx2CQ==", "dependencies": { "@certusone/wormhole-sdk-proto-web": "0.0.6", "@certusone/wormhole-sdk-wasm": "^0.0.1", @@ -619,7 +619,7 @@ "@solana/web3.js": "^1.66.2", "@terra-money/terra.js": "3.1.9", "@xpla/xpla.js": "^0.2.1", - "algosdk": "^1.15.0", + "algosdk": "^2.4.0", "aptos": "1.5.0", "axios": "^0.24.0", "bech32": "^2.0.0", @@ -3580,20 +3580,17 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/algo-msgpack-with-bigint/-/algo-msgpack-with-bigint-2.1.1.tgz", "integrity": "sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==", - "license": "ISC", "engines": { "node": ">= 10" } }, "node_modules/algosdk": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/algosdk/-/algosdk-1.24.1.tgz", - "integrity": "sha512-9moZxdqeJ6GdE4N6fA/GlUP4LrbLZMYcYkt141J4Ss68OfEgH9qW0wBuZ3ZOKEx/xjc5bg7mLP2Gjg7nwrkmww==", - "license": "MIT", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/algosdk/-/algosdk-2.7.0.tgz", + "integrity": "sha512-sBE9lpV7bup3rZ+q2j3JQaFAE9JwZvjWKX00vPlG8e9txctXbgLL56jZhSWZndqhDI9oI+0P4NldkuQIWdrUyg==", "dependencies": { "algo-msgpack-with-bigint": "^2.1.1", - "buffer": "^6.0.2", - "cross-fetch": "^3.1.5", + "buffer": "^6.0.3", "hi-base32": "^0.5.1", "js-sha256": "^0.9.0", "js-sha3": "^0.8.0", @@ -3603,7 +3600,7 @@ "vlq": "^2.0.4" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" } }, "node_modules/ansi-escapes": { @@ -5565,8 +5562,7 @@ "node_modules/hi-base32": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/hi-base32/-/hi-base32-0.5.1.tgz", - "integrity": "sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==", - "license": "MIT" + "integrity": "sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==" }, "node_modules/hmac-drbg": { "version": "1.0.1", @@ -7116,8 +7112,7 @@ "node_modules/js-sha512": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz", - "integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==", - "license": "MIT" + "integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==" }, "node_modules/js-tokens": { "version": "4.0.0", @@ -7164,7 +7159,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "license": "MIT", "dependencies": { "bignumber.js": "^9.0.0" } @@ -9314,8 +9308,7 @@ "node_modules/vlq": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/vlq/-/vlq-2.0.4.tgz", - "integrity": "sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA==", - "license": "MIT" + "integrity": "sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA==" }, "node_modules/walker": { "version": "1.0.8", @@ -9980,9 +9973,9 @@ "dev": true }, "@certusone/wormhole-sdk": { - "version": "0.9.20", - "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.9.20.tgz", - "integrity": "sha512-sHmvqK0FYUa+NCO+kqPQ7CkPrFnl40pGQ8pmp3KW/xn3ECz7ECA3M1/07UvMNzcifbHwM1nmO0QhkEAjREB8wg==", + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.10.5.tgz", + "integrity": "sha512-wKONuigkakoFx9HplBt2Jh5KPxc7xgtDJVrIb2/SqYWbFrdpiZrMC4H6kTZq2U4+lWtqaCa1aJ1q+3GOTNx2CQ==", "requires": { "@certusone/wormhole-sdk-proto-web": "0.0.6", "@certusone/wormhole-sdk-wasm": "^0.0.1", @@ -9996,7 +9989,7 @@ "@solana/web3.js": "^1.66.2", "@terra-money/terra.js": "3.1.9", "@xpla/xpla.js": "^0.2.1", - "algosdk": "^1.15.0", + "algosdk": "^2.4.0", "aptos": "1.5.0", "axios": "^0.24.0", "bech32": "^2.0.0", @@ -12203,13 +12196,12 @@ "integrity": "sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==" }, "algosdk": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/algosdk/-/algosdk-1.24.1.tgz", - "integrity": "sha512-9moZxdqeJ6GdE4N6fA/GlUP4LrbLZMYcYkt141J4Ss68OfEgH9qW0wBuZ3ZOKEx/xjc5bg7mLP2Gjg7nwrkmww==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/algosdk/-/algosdk-2.7.0.tgz", + "integrity": "sha512-sBE9lpV7bup3rZ+q2j3JQaFAE9JwZvjWKX00vPlG8e9txctXbgLL56jZhSWZndqhDI9oI+0P4NldkuQIWdrUyg==", "requires": { "algo-msgpack-with-bigint": "^2.1.1", - "buffer": "^6.0.2", - "cross-fetch": "^3.1.5", + "buffer": "^6.0.3", "hi-base32": "^0.5.1", "js-sha256": "^0.9.0", "js-sha3": "^0.8.0", diff --git a/package.json b/package.json index d91b0dc..7b692a3 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "clean": "rm -rf ts-scripts/ethers-contracts/; rm -rf out/;" }, "dependencies": { - "@certusone/wormhole-sdk": "^0.9.20", + "@certusone/wormhole-sdk": "^0.10.5", "@improbable-eng/grpc-web-node-http-transport": "^0.15.0", "@typechain/ethers-v5": "^11.0.0", "ethers": "^5", diff --git a/src/HelloWormhole.sol b/src/HelloWormhole.sol index 7acdad8..9d1bcc9 100644 --- a/src/HelloWormhole.sol +++ b/src/HelloWormhole.sol @@ -17,11 +17,21 @@ contract HelloWormhole is IWormholeReceiver { wormholeRelayer = IWormholeRelayer(_wormholeRelayer); } - function quoteCrossChainGreeting(uint16 targetChain) public view returns (uint256 cost) { - (cost,) = wormholeRelayer.quoteEVMDeliveryPrice(targetChain, 0, GAS_LIMIT); + function quoteCrossChainGreeting( + uint16 targetChain + ) public view returns (uint256 cost) { + (cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); } - function sendCrossChainGreeting(uint16 targetChain, address targetAddress, string memory greeting) public payable { + function sendCrossChainGreeting( + uint16 targetChain, + address targetAddress, + string memory greeting + ) public payable { uint256 cost = quoteCrossChainGreeting(targetChain); require(msg.value == cost); wormholeRelayer.sendPayloadToEvm{value: cost}( @@ -33,8 +43,6 @@ contract HelloWormhole is IWormholeReceiver { ); } - mapping(bytes32 => bool) public seenDeliveryVaaHashes; - function receiveWormholeMessages( bytes memory payload, bytes[] memory, // additionalVaas @@ -44,14 +52,12 @@ contract HelloWormhole is IWormholeReceiver { ) public payable override { require(msg.sender == address(wormholeRelayer), "Only relayer allowed"); - // Ensure no duplicate deliveries - require(!seenDeliveryVaaHashes[deliveryHash], "Message already processed"); - seenDeliveryVaaHashes[deliveryHash] = true; - // Parse the payload and do the corresponding actions! - (string memory greeting, address sender) = abi.decode(payload, (string, address)); + (string memory greeting, address sender) = abi.decode( + payload, + (string, address) + ); latestGreeting = greeting; emit GreetingReceived(latestGreeting, sourceChain, sender); } - -} \ No newline at end of file +} diff --git a/ts-scripts/getStatus.ts b/ts-scripts/getStatus.ts index 23b1fb9..ec1ed14 100644 --- a/ts-scripts/getStatus.ts +++ b/ts-scripts/getStatus.ts @@ -4,11 +4,18 @@ import { storeDeployedAddresses, getChain, loadDeployedAddresses, -} from "./utils" -import {relayer, ChainName} from "@certusone/wormhole-sdk" +} from "./utils"; +import { relayer, ChainName } from "@certusone/wormhole-sdk"; -export async function getStatus(sourceChain: ChainName, transactionHash: string): Promise<{status: string, info: string}> { - const info = await relayer.getWormholeRelayerInfo(sourceChain, transactionHash, {environment: "TESTNET"}); +export async function getStatus( + sourceChain: ChainName, + transactionHash: string +): Promise<{ status: string; info: string }> { + const info = await relayer.getWormholeRelayerInfo( + sourceChain, + transactionHash, + { environment: "TESTNET" } + ); const status = info.targetChainStatus.events[0].status; - return {status, info: relayer.stringifyWormholeRelayerInfo(info)}; + return { status, info: info.stringified || "Info not obtained" }; }