Skip to content

Commit 3f56da6

Browse files
authored
Tests and fixes when core bridge messageFee is > 0 (wormhole-foundation#609)
* Set core bridge fee > 0 in sdk e2e and cli tests + fixes * forge fmt * delete typo
1 parent 0dc1596 commit 3f56da6

File tree

6 files changed

+98
-13
lines changed

6 files changed

+98
-13
lines changed

cli/test/sepolia-bsc.sh

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,52 @@ set -euox pipefail
88

99
BSC_PORT=8545
1010
SEPOLIA_PORT=8546
11-
12-
anvil --silent --rpc-url https://bsc-testnet-rpc.publicnode.com -p "$BSC_PORT" &
11+
BSC_RPC_URL=https://bsc-testnet-rpc.publicnode.com
12+
SEPOLIA_RPC_URL=wss://ethereum-sepolia-rpc.publicnode.com
13+
SEPOLIA_FORK_RPC_URL=http://127.0.0.1:$SEPOLIA_PORT
14+
BSC_FORK_RPC_URL=http://127.0.0.1:$BSC_PORT
15+
SEPOLIA_CORE_BRIDGE=0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78
16+
BSC_CORE_BRIDGE=0x68605AD7b15c732a30b1BbC62BE8F2A509D74b4D
17+
18+
anvil --silent --rpc-url $BSC_RPC_URL -p "$BSC_PORT" &
1319
pid1=$!
14-
anvil --silent --rpc-url wss://ethereum-sepolia-rpc.publicnode.com -p "$SEPOLIA_PORT" &
20+
anvil --silent --rpc-url $SEPOLIA_RPC_URL -p "$SEPOLIA_PORT" &
1521
pid2=$!
16-
1722
# check both processes are running
1823
if ! kill -0 $pid1 || ! kill -0 $pid2; then
1924
echo "Failed to start the servers"
2025
exit 1
2126
fi
2227

28+
# wait for RPC endpoints to be ready
29+
wait_for_rpc() {
30+
local url=$1
31+
local max_attempts=30
32+
local attempt=1
33+
34+
echo "Waiting for RPC endpoint $url to be ready..."
35+
while [ $attempt -le $max_attempts ]; do
36+
if curl -s -X POST "$url" \
37+
-H "Content-Type: application/json" \
38+
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' > /dev/null 2>&1; then
39+
echo "RPC endpoint $url is ready"
40+
return 0
41+
fi
42+
echo "Attempt $attempt/$max_attempts: RPC not ready yet, waiting..."
43+
sleep 1
44+
attempt=$((attempt + 1))
45+
done
46+
echo "RPC endpoint $url failed to become ready after $max_attempts attempts"
47+
return 1
48+
}
49+
50+
wait_for_rpc "$SEPOLIA_FORK_RPC_URL" || exit 1
51+
wait_for_rpc "$BSC_FORK_RPC_URL" || exit 1
52+
53+
# setting core bridge fee to 0.001 (7 = `messageFee` storage slot)
54+
curl "$SEPOLIA_FORK_RPC_URL" -H "Content-Type: application/json" --data "{\"jsonrpc\":\"2.0\",\"method\":\"anvil_setStorageAt\",\"params\":[\"$SEPOLIA_CORE_BRIDGE\", 7 ,\"0x00000000000000000000000000000000000000000000000000038D7EA4C68000\"],\"id\":1}"
55+
curl "$BSC_FORK_RPC_URL" -H "Content-Type: application/json" --data "{\"jsonrpc\":\"2.0\",\"method\":\"anvil_setStorageAt\",\"params\":[\"$BSC_CORE_BRIDGE\", 7 ,\"0x00000000000000000000000000000000000000000000000000038D7EA4C68000\"],\"id\":1}"
56+
2357
# create tmp directory
2458
dir=$(mktemp -d)
2559

@@ -44,10 +78,10 @@ cat <<EOF > overrides.json
4478
{
4579
"chains": {
4680
"Bsc": {
47-
"rpc": "http://127.0.0.1:$BSC_PORT"
81+
"rpc": "$BSC_FORK_RPC_URL"
4882
},
4983
"Sepolia": {
50-
"rpc": "http://127.0.0.1:$SEPOLIA_PORT"
84+
"rpc": "$SEPOLIA_FORK_RPC_URL"
5185
}
5286
}
5387
}

evm/script/ConfigureWormholeNtt.s.sol

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import "../src/interfaces/IOwnableUpgradeable.sol";
1010

1111
import {ParseNttConfig} from "./helpers/ParseNttConfig.sol";
1212
import {WormholeTransceiver} from "../src/Transceiver/WormholeTransceiver/WormholeTransceiver.sol";
13+
import {WormholeTransceiverState} from
14+
"../src/Transceiver/WormholeTransceiver/WormholeTransceiverState.sol";
1315

1416
contract ConfigureWormholeNtt is ParseNttConfig {
1517
using stdJson for string;
@@ -42,9 +44,10 @@ contract ConfigureWormholeNtt is ParseNttConfig {
4244
wormholeTransceiver.setIsSpecialRelayingEnabled(targetConfig.chainId, true);
4345
console2.log("Special relaying enabled for chain", targetConfig.chainId);
4446
}
45-
47+
uint256 messageFee =
48+
WormholeTransceiverState(address(wormholeTransceiver)).wormhole().messageFee();
4649
// Set peer.
47-
wormholeTransceiver.setWormholePeer(
50+
wormholeTransceiver.setWormholePeer{value: messageFee}(
4851
targetConfig.chainId, targetConfig.wormholeTransceiver
4952
);
5053
console2.log("Wormhole peer set for chain", targetConfig.chainId);

evm/script/helpers/DeployWormholeNttBase.sol

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import {WormholeTransceiver} from
1212
"../../src/Transceiver/WormholeTransceiver/WormholeTransceiver.sol";
1313
import {ERC1967Proxy} from "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol";
1414

15+
interface IWormhole {
16+
function messageFee() external view returns (uint256);
17+
}
18+
1519
contract DeployWormholeNttBase is ParseNttConfig {
1620
struct DeploymentParams {
1721
address token;
@@ -71,7 +75,10 @@ contract DeployWormholeNttBase is ParseNttConfig {
7175
WormholeTransceiver transceiverProxy =
7276
WormholeTransceiver(address(new ERC1967Proxy(address(implementation), "")));
7377

74-
transceiverProxy.initialize();
78+
IWormhole wh = IWormhole(params.wormholeCoreBridge);
79+
uint256 messageFee = wh.messageFee();
80+
// wh transceiver sends a WH_TRANSCEIVER_INIT_PREFIX message
81+
transceiverProxy.initialize{value: messageFee}();
7582

7683
console2.log("WormholeTransceiver:", address(transceiverProxy));
7784

evm/ts/src/ntt.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,20 @@ export class EvmNttWormholeTranceiver<N extends Network, C extends EvmChains>
8080
async *setPeer<P extends Chain>(
8181
peer: ChainAddress<P>
8282
): AsyncGenerator<EvmUnsignedTransaction<N, C>> {
83+
const coreBridge = new Contract(this.manager.contracts.coreBridge!, [
84+
"function messageFee() public view returns (uint256)",
85+
],
86+
this.manager.provider
87+
)
88+
const messageFee = await coreBridge.getFunction("messageFee").staticCall()
8389
const tx = await this.transceiver.setWormholePeer.populateTransaction(
8490
toChainId(peer.chain),
8591
universalAddress(peer)
8692
);
87-
yield this.manager.createUnsignedTx(tx, "WormholeTransceiver.registerPeer");
93+
yield this.manager.createUnsignedTx({
94+
...tx,
95+
value: messageFee
96+
}, "WormholeTransceiver.registerPeer");
8897
}
8998

9099
async getPauser(): Promise<AccountAddress<C> | null> {

sdk/__tests__/index.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { web3 } from "@coral-xyz/anchor";
22
import { chainToPlatform } from "@wormhole-foundation/sdk-connect";
33

44
import { registerRelayers } from "./accountant.js";
5-
import { Ctx, testHub } from "./utils.js";
5+
import { Ctx, setMessageFee, testHub } from "./utils.js";
6+
import { ethers } from "ethers";
67

78
// Note: Currently, in order for this to run, the evm bindings with extra contracts must be build
89
// To do that, at the root, run `npm run generate:test`
@@ -62,6 +63,11 @@ const makeGetNativeSigner =
6263
describe("Hub and Spoke Tests", function () {
6364
beforeAll(async () => {
6465
await registerRelayers(ACCT_MNEMONIC);
66+
await setMessageFee(["Ethereum", "Bsc"], ethers.parseEther("0.001"));
67+
});
68+
69+
afterAll(async () => {
70+
await setMessageFee(["Ethereum", "Bsc"], 0n);
6571
});
6672

6773
test("Test Solana and Ethereum Hubs", async () => {

sdk/__tests__/utils.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ export async function link(chainInfos: Ctx[], accountantPrivateKey: string) {
205205
);
206206
vaas.push(serialize(vaa));
207207
}
208-
208+
209209
// Submit all registrations at once
210210
await submitAccountantVAAs(vaas, accountantPrivateKey);
211211
}
@@ -240,6 +240,7 @@ export async function transferWithChecks(sourceCtx: Ctx, destinationCtx: Ctx) {
240240

241241
console.log("Calling transfer on: ", sourceCtx.context.chain);
242242
const srcNtt = await getNtt(sourceCtx);
243+
243244
const transferTxs = srcNtt.transfer(sender.address, srcAmt, receiver, {
244245
queue: false,
245246
automatic: useRelayer,
@@ -260,6 +261,8 @@ export async function transferWithChecks(sourceCtx: Ctx, destinationCtx: Ctx) {
260261
const [managerBalanceAfterRecv, userBalanceAfterRecv] =
261262
await getManagerAndUserBalance(destinationCtx);
262263

264+
265+
263266
checkBalances(
264267
sourceCtx.mode,
265268
[managerBalanceBeforeSend, managerBalanceAfterSend],
@@ -459,7 +462,10 @@ async function deployEvm(ctx: Ctx): Promise<Ctx> {
459462
console.log("Initialize the manager");
460463
await tryAndWaitThrice(() => manager.initialize());
461464
console.log("Initialize the transceiver");
462-
await tryAndWaitThrice(() => transceiver.initialize());
465+
const coreFee = await (await ctx.context.getWormholeCore()).getMessageFee()
466+
await tryAndWaitThrice(() => transceiver.initialize({
467+
value: coreFee
468+
}));
463469

464470
// Setup the initial calls, like transceivers for the manager
465471
console.log("Set transceiver for manager");
@@ -728,6 +734,26 @@ async function tryAndWaitThrice(
728734
return null;
729735
}
730736

737+
export async function setMessageFee(chains: Chain[], fee: bigint) {
738+
console.log(`Setting message fee for ${chains} to ${fee}`)
739+
for (const chain of chains) {
740+
const chainCtx = wh.getChain(chain)
741+
const core = await chainCtx.getWormholeCore()
742+
const coreAddress = chainCtx.config.contracts.coreBridge
743+
const existingFee = await core.getMessageFee()
744+
console.log(`Existing core bridge fee for ${chain}: ${existingFee}`)
745+
const rpc = await chainCtx.getRpc()
746+
await rpc.send("anvil_setStorageAt", [
747+
coreAddress,
748+
7, // messageFee storage slot
749+
ethers.zeroPadValue(ethers.toBeHex(fee), 32)
750+
]);
751+
752+
const newFee = await core.getMessageFee()
753+
console.log(`New core bridge fee for ${chain}: ${newFee}`)
754+
}
755+
}
756+
731757
export async function testHub(
732758
source: Chain,
733759
destinationA: Chain,

0 commit comments

Comments
 (0)