diff --git a/evm/env/localnet/Base.env b/evm/env/localnet/Base.env deleted file mode 100644 index 5122b61c3..000000000 --- a/evm/env/localnet/Base.env +++ /dev/null @@ -1,49 +0,0 @@ -export RELEASE_CHAIN_TYPE=evm - -### Wormhole Chain ID (uint16) -export RELEASE_CHAIN_ID=30 - -### Circle Domain (uint32) -export RELEASE_DOMAIN=6 - -### Token (evm address) -### -### Token Info: https://basescan.org/address/0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 -export RELEASE_TOKEN_ADDRESS=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 - - -############################# Wormhole Contracts ############################# - - -### Wormhole (evm address) -export RELEASE_WORMHOLE_ADDRESS=0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 - - -############################# Circle Contracts ################################# - -### Circle Token Messenger (evm address) -export RELEASE_TOKEN_MESSENGER_ADDRESS=0x1682Ae6375C4E4A97e4B583BC394c861A46D8962 - - -################################# Ownership ################################## - - -### Owner Assistant (evm address) -export RELEASE_OWNER_ASSISTANT_ADDRESS=0xACa94ef8bD5ffEE41947b4585a84BdA5a3d3DA6E - - -############################### Token Router ################################# - - -### Token Router Proxy (evm address) -export RELEASE_TOKEN_ROUTER_ADDRESS=0x1943bd00e3a4f46b10e6657dd9236be95e20398a - - -############################### Matching Engine ############################### - - -### Matching Engine Proxy (universal evm address) -export RELEASE_MATCHING_ENGINE_CHAIN=6 -export RELEASE_MATCHING_ENGINE_ADDRESS=0x00000000000000000000000027D44c7337ce4D67b7cd573e9c36bDEED2b2162a -export RELEASE_MATCHING_ENGINE_MINT_RECIPIENT=0x00000000000000000000000027D44c7337ce4D67b7cd573e9c36bDEED2b2162a -export RELEASE_MATCHING_ENGINE_DOMAIN=1 \ No newline at end of file diff --git a/evm/env/testing.env b/evm/env/testing.env index b52cfac67..b371d1e07 100644 --- a/evm/env/testing.env +++ b/evm/env/testing.env @@ -1,6 +1,5 @@ export AVALANCHE_RPC=https://api.avax.network/ext/bc/C/rpc export ETHEREUM_RPC=https://rpc.ankr.com/eth -export BASE_RPC=https://mainnet.base.org export AVAX_USDC_ADDRESS=0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E diff --git a/evm/package.json b/evm/package.json index 2f6057a0f..a8876698e 100644 --- a/evm/package.json +++ b/evm/package.json @@ -31,9 +31,9 @@ }, "dependencies": { "@wormhole-foundation/example-liquidity-layer-definitions": "0.0.1", - "@wormhole-foundation/sdk-base": "^0.10.9", - "@wormhole-foundation/sdk-definitions": "^0.10.9", - "@wormhole-foundation/sdk-evm": "^0.10.9", + "@wormhole-foundation/sdk-base": "^1.4.4", + "@wormhole-foundation/sdk-definitions": "^1.4.4", + "@wormhole-foundation/sdk-evm": "^1.4.4", "ethers-v5": "npm:ethers@^5.7.2" }, "devDependencies": { diff --git a/evm/sh/upgrade_token_router.sh b/evm/sh/upgrade_token_router.sh index 19e0ca360..744379af5 100644 --- a/evm/sh/upgrade_token_router.sh +++ b/evm/sh/upgrade_token_router.sh @@ -54,7 +54,7 @@ then rpc=$RPC fi -forge script $FORGE_SCRIPTS/UpgradeTokenRouter.s.sol \ +forge script $FORGE_SCRIPTS/UpgradeTokenRouter.s.sol -vvvv \ --rpc-url $rpc \ --broadcast \ --private-key $private_key diff --git a/evm/ts/tests/00__environment.ts b/evm/ts/tests/00__environment.ts index da5d48002..fec106109 100644 --- a/evm/ts/tests/00__environment.ts +++ b/evm/ts/tests/00__environment.ts @@ -22,7 +22,7 @@ import { } from "../src/testing"; describe("Environment", () => { - const chainNames: ValidNetwork[] = ["Avalanche", "Ethereum", "Base"]; + const chainNames: ValidNetwork[] = ["Avalanche", "Ethereum"]; for (const chainName of chainNames) { if (!(chainName in LOCALHOSTS)) { @@ -282,9 +282,9 @@ describe("Environment", () => { const scripts = `${__dirname}/../../sh`; const cmd = `bash ${scripts}/upgrade_token_router.sh ` + - `-n localnet -c ${chainName} -u ${localhost} -k ${owner.privateKey}` + - `> /dev/null 2>&1`; + `-n localnet -c ${chainName} -u ${localhost} -k ${owner.privateKey}`; const out = execSync(cmd, { encoding: "utf8" }); + console.log(out); await provider.send("evm_setAutomine", [false]); }); }); diff --git a/evm/ts/tests/01__registration.ts b/evm/ts/tests/01__registration.ts index 8d93876d3..a3b5a1eae 100644 --- a/evm/ts/tests/01__registration.ts +++ b/evm/ts/tests/01__registration.ts @@ -16,7 +16,7 @@ import { expect } from "chai"; import { toChainId } from "@wormhole-foundation/sdk-base"; import { toUniversal } from "@wormhole-foundation/sdk-definitions"; -const CHAIN_PATHWAYS: ValidNetwork[] = ["Ethereum", "Avalanche", "Base"]; +const CHAIN_PATHWAYS: ValidNetwork[] = ["Ethereum", "Avalanche"]; describe("Registration", () => { const envPath = `${__dirname}/../../env/localnet`; diff --git a/evm/ts/tests/02__configuration.ts b/evm/ts/tests/02__configuration.ts index 5897d1c28..4c160c831 100644 --- a/evm/ts/tests/02__configuration.ts +++ b/evm/ts/tests/02__configuration.ts @@ -12,7 +12,7 @@ import { import { expect } from "chai"; import { toUniversal } from "@wormhole-foundation/sdk-definitions"; -const CHAIN_PATHWAYS: ValidNetwork[] = ["Ethereum", "Avalanche", "Base"]; +const CHAIN_PATHWAYS: ValidNetwork[] = ["Ethereum", "Avalanche"]; describe("Configuration", () => { const envPath = `${__dirname}/../../env/localnet`; diff --git a/evm/ts/tests/03__marketOrder.ts b/evm/ts/tests/03__marketOrder.ts index ea0858ce8..dbaad9999 100644 --- a/evm/ts/tests/03__marketOrder.ts +++ b/evm/ts/tests/03__marketOrder.ts @@ -20,10 +20,6 @@ import { toChainId } from "@wormhole-foundation/sdk-base"; const CHAIN_PATHWAYS: ValidNetwork[][] = [ ["Ethereum", "Avalanche"], ["Avalanche", "Ethereum"], - ["Ethereum", "Base"], - ["Base", "Ethereum"], - ["Avalanche", "Base"], - ["Base", "Avalanche"], ]; const TEST_AMOUNT = ethers.utils.parseUnits("1000", 6); diff --git a/evm/ts/tests/04__fastMarketOrder.ts b/evm/ts/tests/04__fastMarketOrder.ts deleted file mode 100644 index ed1d11574..000000000 --- a/evm/ts/tests/04__fastMarketOrder.ts +++ /dev/null @@ -1,1361 +0,0 @@ -import "@wormhole-foundation/sdk-evm/address"; - -import { expect } from "chai"; -import { ethers } from "ethers-v5"; -import { - EvmTokenRouter, - EvmMatchingEngine, - errorDecoder, - OrderResponse, - MessageDecoder, -} from "../src"; -import { IERC20__factory } from "../src/types"; -import { - ChainType, - parseLiquidityLayerEnvFile, - CircleAttester, - GuardianNetwork, - LOCALHOSTS, - MATCHING_ENGINE_CHAIN, - MATCHING_ENGINE_NAME, - ScoreKeeper, - ValidNetwork, - WALLET_PRIVATE_KEYS, - burnAllUsdc, - mineWait, - mine, - mintNativeUsdc, - mineToGracePeriod, - mineToPenaltyPeriod, - tryNativeToUint8Array, -} from "../src/testing"; - -import { toChainId } from "@wormhole-foundation/sdk-base"; -import { deserialize, keccak256, toUniversal } from "@wormhole-foundation/sdk-definitions"; - -// Cannot send a fast market order from the matching engine chain. -const CHAIN_PATHWAYS: ValidNetwork[][] = [ - ["Base", "Ethereum"], - ["Ethereum", "Base"], - ["Base", "Avalanche"], - ["Ethereum", "Avalanche"], -]; - -const TEST_AMOUNT = ethers.utils.parseUnits("1000", 6); -const FEE_AMOUNT = BigInt(ethers.utils.parseUnits("10", 6).toString()); - -describe("Fast Market Order Business Logic -- CCTP to CCTP", function (this: Mocha.Suite) { - const envPath = `${__dirname}/../../env/localnet`; - - const guardianNetwork = new GuardianNetwork(); - const circleAttester = new CircleAttester(); - - // Matching Engine configuration. - const engineProvider = new ethers.providers.StaticJsonRpcProvider( - LOCALHOSTS[MATCHING_ENGINE_NAME], - ); - const engineWallet = new ethers.Wallet(WALLET_PRIVATE_KEYS[2], engineProvider); - const engineEnv = parseLiquidityLayerEnvFile(`${envPath}/${MATCHING_ENGINE_NAME}.env`); - const engine = (() => { - if (engineEnv.chainType === ChainType.Evm) { - return new EvmMatchingEngine( - engineWallet, - toUniversal("Avalanche", engineEnv.matchingEngineAddress) - .toNative("Avalanche") - .toString(), - engineEnv.tokenMessengerAddress, - ); - } else { - throw new Error("Unsupported chain"); - } - })(); - - // Auction participants. - const initialBidder = new ethers.Wallet(WALLET_PRIVATE_KEYS[3], engineProvider); - const bidderTwo = new ethers.Wallet(WALLET_PRIVATE_KEYS[4], engineProvider); - const bidderThree = new ethers.Wallet(WALLET_PRIVATE_KEYS[5], engineProvider); - const highestBidder = new ethers.Wallet(WALLET_PRIVATE_KEYS[6], engineProvider); - const liquidator = new ethers.Wallet(WALLET_PRIVATE_KEYS[7], engineProvider); - - for (const [fromChainName, toChainName] of CHAIN_PATHWAYS) { - const localVariables = new Map(); - - describe(`${fromChainName} <> ${toChainName}`, () => { - // From setup. - const fromProvider = new ethers.providers.StaticJsonRpcProvider( - LOCALHOSTS[fromChainName], - ); - const fromWallet = new ethers.Wallet(WALLET_PRIVATE_KEYS[0], fromProvider); - - const fromEnv = parseLiquidityLayerEnvFile(`${envPath}/${fromChainName}.env`); - const fromTokenRouter = (() => { - if (fromEnv.chainType === ChainType.Evm) { - return new EvmTokenRouter( - fromWallet, - fromEnv.tokenRouterAddress, - fromEnv.tokenMessengerAddress, - ); - } else { - throw new Error("Unsupported chain"); - } - })(); - - // To setup. - const toProvider = new ethers.providers.StaticJsonRpcProvider(LOCALHOSTS[toChainName]); - const toWallet = new ethers.Wallet(WALLET_PRIVATE_KEYS[1], toProvider); - - const toEnv = parseLiquidityLayerEnvFile(`${envPath}/${toChainName}.env`); - const toTokenRouter = (() => { - if (toEnv.chainType === ChainType.Evm) { - return new EvmTokenRouter( - toWallet, - toEnv.tokenRouterAddress, - fromEnv.tokenMessengerAddress, - ); - } else { - throw new Error("Unsupported chain"); - } - })(); - - describe(`Successful Auction`, () => { - before(`From Network -- Mint USDC`, async () => { - if (fromEnv.chainId == MATCHING_ENGINE_CHAIN) { - console.log("Skipfrom outbound tests from Matching Engine."); - this.ctx.skip(); - } - - const usdc = IERC20__factory.connect(fromEnv.tokenAddress, fromWallet); - - await burnAllUsdc(usdc); - - await mintNativeUsdc( - IERC20__factory.connect(fromEnv.tokenAddress, fromProvider), - fromWallet.address, - TEST_AMOUNT, - ); - }); - - after(`Burn USDC`, async () => { - const usdc = IERC20__factory.connect(fromEnv.tokenAddress, fromWallet); - await burnAllUsdc(usdc); - }); - - it(`From Network -- Place Fast Market Order`, async () => { - const amountIn = await (async () => { - if (fromEnv.chainType == ChainType.Evm) { - const usdc = IERC20__factory.connect(fromEnv.tokenAddress, fromWallet); - const amount = await usdc.balanceOf(fromWallet.address); - await usdc - .approve(fromTokenRouter.address, amount) - .then((tx) => mineWait(fromProvider, tx)); - - return BigInt(amount.toString()); - } else { - throw new Error("Unsupported chain"); - } - })(); - localVariables.set("amountIn", amountIn); - - const targetChain = toChainId(toChainName); - const minAmountOut = BigInt(0); - const deadline = 0; - const receipt = await fromTokenRouter - .placeFastMarketOrder( - amountIn, - targetChain, - Buffer.from(tryNativeToUint8Array(toWallet.address, toChainName)), - Buffer.from("All your base are belong to us."), - FEE_AMOUNT, - deadline, - minAmountOut, - fromWallet.address, - ) - .then((tx) => mineWait(fromProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - const transactionResult = await fromTokenRouter.getTransactionResults( - receipt.transactionHash, - ); - expect(transactionResult.wormhole.emitterAddress).to.eql( - tryNativeToUint8Array(fromEnv.tokenRouterAddress, fromChainName), - ); - expect(transactionResult.wormhole.message.body).has.property( - "slowOrderResponse", - ); - expect(transactionResult.circleMessage).is.not.undefined; - expect(transactionResult.fastMessage).is.not.undefined; - - const signedVaas = await guardianNetwork.observeManyEvm( - fromProvider, - fromChainName, - receipt, - ); - expect(signedVaas.length).to.eql(2); - - // The first message is the slow CCTP transfer. - const [slowOrderResponse, fastVaa] = signedVaas; - - const circleBridgeMessage = transactionResult.circleMessage!; - const circleAttestation = circleAttester.createAttestation(circleBridgeMessage); - - const redeemParameters: OrderResponse = { - encodedWormholeMessage: slowOrderResponse, - circleBridgeMessage, - circleAttestation, - }; - localVariables.set("redeemParameters", redeemParameters); - localVariables.set("fastVaa", fastVaa); - }); - - it(`Matching Engine -- Start Fast Order Auction`, async () => { - const fastVaa = localVariables.get("fastVaa") as Uint8Array; - - // Parse the vaa, we will need the hash for later. - const parsedFastVaa = deserialize("Uint8Array", fastVaa); - localVariables.set("auctionId", keccak256(parsedFastVaa.hash)); - const fastOrder = MessageDecoder.decode(parsedFastVaa.payload).body - .fastMarketOrder; - - if (fastOrder === undefined) { - throw new Error("Fast order undefined"); - } - - // Security deposit amount of the initial bid. - const initialDeposit = fastOrder.amountIn + fastOrder.maxFee; - - // Prepare usdc for the auction. - const usdc = IERC20__factory.connect(engineEnv.tokenAddress, initialBidder); - await mintNativeUsdc(usdc, initialBidder.address, initialDeposit); - await usdc.approve(engine.address, initialDeposit); - - const balanceBefore = await usdc.balanceOf(initialBidder.address); - - const receipt = await engine - .connect(initialBidder) - .placeInitialBid(fastVaa, fastOrder.maxFee) - .then((tx) => mineWait(engineProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - - const balanceAfter = await usdc.balanceOf(initialBidder.address); - expect(balanceBefore.sub(balanceAfter).toString()).to.eql( - initialDeposit.toString(), - ); - - // Validate state changes. - const auctionData = await engine.liveAuctionInfo( - localVariables.get("auctionId"), - ); - - expect(auctionData.status).to.eql(1); - expect(auctionData.startBlock.toString()).to.eql( - receipt.blockNumber.toString(), - ); - expect(auctionData.highestBidder).to.eql(initialBidder.address); - expect(auctionData.initialBidder).to.eql(initialBidder.address); - expect(auctionData.amount.toString()).to.eql(fastOrder.amountIn.toString()); - expect(auctionData.securityDeposit.toString()).to.eql( - fastOrder.maxFee.toString(), - ); - expect(auctionData.bidPrice.toString()).to.eql(fastOrder.maxFee.toString()); - }); - - it(`Matching Engine -- Fast Order Auction Period`, async () => { - const auctionId = localVariables.get("auctionId") as Uint8Array; - - const auctionInfoBefore = await engine.liveAuctionInfo(auctionId); - const startingBid = ethers.BigNumber.from(auctionInfoBefore.bidPrice); - const initialDeposit = ethers.BigNumber.from(auctionInfoBefore.amount).add( - ethers.BigNumber.from(auctionInfoBefore.securityDeposit), - ); - expect(startingBid.gt(0) && initialDeposit.gt(0)).is.true; - - // Create array of test bids. This structure should not change, otherwise - // the following tests will fail. - const bids: ScoreKeeper[] = [ - { - player: bidderTwo, - bid: startingBid.sub(1), - balance: ethers.BigNumber.from(0), - }, - { - player: bidderThree, - bid: startingBid.div(2), - balance: ethers.BigNumber.from(0), - }, - { - player: highestBidder, - bid: startingBid.div(3), - balance: ethers.BigNumber.from(0), - }, - ]; - - // Loop through and make multiple bids in the same block. - for (let i = 0; i < bids.length; i++) { - const player = bids[i].player; - const usdc = IERC20__factory.connect(engineEnv.tokenAddress, player); - await mintNativeUsdc(usdc, player.address, initialDeposit, false); - await usdc.approve(engine.address, initialDeposit); - - bids[i].balance = await usdc.balanceOf(player.address); - - // Improve the bid. - await engine.connect(player).improveBid(auctionId, bids[i].bid); - } - - // Mine the block. - await mine(engineProvider); - - // Validate balance changes. The lowest bid should have zero balance, the others - // should've been refunded. - for (let i = 0; i < bids.length; i++) { - const player = bids[i].player; - const usdc = IERC20__factory.connect(engineEnv.tokenAddress, player); - const balanceAfter = await usdc.balanceOf(player.address); - - if (i == 2) { - expect(balanceAfter.sub(bids[i].balance).toString()).to.eql("0"); - } else { - expect(balanceAfter.toString()).to.eql( - bids[i].balance.add(initialDeposit).toString(), - ); - } - } - - // Validate state changes. - const auctionInfoAfter = await engine.liveAuctionInfo(auctionId); - - expect(auctionInfoAfter.status).to.eql(1); - expect(auctionInfoAfter.startBlock.toString()).to.eql( - auctionInfoBefore.startBlock.toString(), - ); - expect(auctionInfoAfter.highestBidder).to.eql(highestBidder.address); - expect(auctionInfoAfter.initialBidder).to.eql(auctionInfoBefore.initialBidder); - expect(auctionInfoAfter.amount.toString()).to.eql( - auctionInfoBefore.amount.toString(), - ); - expect(auctionInfoAfter.securityDeposit.toString()).to.eql( - auctionInfoBefore.securityDeposit.toString(), - ); - expect(auctionInfoAfter.bidPrice.toString()).to.eql(bids[2].bid.toString()); - }); - - it(`Matching Engine -- Execute Fast Order Within Grace Period`, async () => { - const auctionId = localVariables.get("auctionId") as Uint8Array; - - await mineToGracePeriod(auctionId, engine, engineProvider); - - // Fetch the initial bidder so we can do a balance check. - const auctionInfo = await engine.liveAuctionInfo(auctionId); - - const usdc = IERC20__factory.connect(engineEnv.tokenAddress, highestBidder); - const balanceBefore = await usdc.balanceOf(highestBidder.address); - const initialBidderBefore = await usdc.balanceOf(auctionInfo.initialBidder); - - const receipt = await engine - .connect(highestBidder) - .executeFastOrder(localVariables.get("fastVaa")) - .then((tx) => mineWait(engineProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - - const transactionResult = await engine.getTransactionResults( - receipt.transactionHash, - ); - - if (toChainName == MATCHING_ENGINE_NAME) { - expect(transactionResult.wormhole.emitterAddress).to.eql( - tryNativeToUint8Array(engine.address, MATCHING_ENGINE_NAME), - ); - expect(transactionResult.wormhole.message.body).has.property("fastFill"); - expect(transactionResult.circleMessage).is.undefined; - } else { - expect(transactionResult.wormhole.emitterAddress).to.eql( - tryNativeToUint8Array(engine.address, MATCHING_ENGINE_NAME), - ); - expect(transactionResult.wormhole.message.body).has.property("fill"); - expect(transactionResult.circleMessage).is.not.undefined; - } - - expect(transactionResult.fastMessage).is.undefined; - - // Validate state and balance changes. - const balanceAfter = await usdc.balanceOf(highestBidder.address); - const initialBidderAfter = await usdc.balanceOf(auctionInfo.initialBidder); - const initAuctionFee = await fromTokenRouter.getInitialAuctionFee(); - - expect(balanceAfter.sub(balanceBefore).toString()).to.eql( - ethers.BigNumber.from(auctionInfo.bidPrice) - .add(ethers.BigNumber.from(auctionInfo.securityDeposit)) - .toString(), - ); - expect(initialBidderAfter.sub(initialBidderBefore).eq(initAuctionFee)).is.true; - - // Auction status should be complete (2). - const auctionStatus = await engine - .liveAuctionInfo(auctionId) - .then((info) => info.status); - expect(auctionStatus).to.eql(2); - - // Fetch and store the vaa for redeeming the fill. - const signedVaa = await guardianNetwork.observeEvm( - engineProvider, - MATCHING_ENGINE_NAME, - receipt, - ); - - let orderResponse: OrderResponse; - if (toChainName == MATCHING_ENGINE_NAME) { - orderResponse = { - encodedWormholeMessage: signedVaa, - circleBridgeMessage: Buffer.from(""), - circleAttestation: Buffer.from(""), - }; - } else { - const circleBridgeMessage = transactionResult.circleMessage!; - const circleAttestation = - circleAttester.createAttestation(circleBridgeMessage); - - orderResponse = { - encodedWormholeMessage: signedVaa, - circleBridgeMessage, - circleAttestation, - }; - } - - localVariables.set("fastOrderResponse", orderResponse); - }); - - it(`To Network -- Redeem Fill`, async () => { - const auctionId = localVariables.get("auctionId") as Uint8Array; - const orderResponse = localVariables.get("fastOrderResponse") as OrderResponse; - expect(localVariables.delete("fastOrderResponse")).is.true; - - const usdc = IERC20__factory.connect(toEnv.tokenAddress, toProvider); - const balanceBefore = await usdc.balanceOf(toWallet.address); - - const receipt = await toTokenRouter - .redeemFill(orderResponse) - .then((tx) => mineWait(toProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - - // Validate balance changes. - const [bidPrice, amount] = await engine - .liveAuctionInfo(auctionId) - .then((info) => [ - ethers.BigNumber.from(info.bidPrice), - ethers.BigNumber.from(info.amount), - ]); - const initAuctionFee = await fromTokenRouter.getInitialAuctionFee(); - const balanceAfter = await usdc.balanceOf(toWallet.address); - - expect(balanceAfter.sub(balanceBefore).toString()).to.eql( - amount.sub(bidPrice).sub(initAuctionFee).toString(), - ); - }); - - it(`Matching Engine -- Execute Slow Vaa And Redeem`, async () => { - const auctionId = localVariables.get("auctionId") as Uint8Array; - const fastVaa = localVariables.get("fastVaa") as Uint8Array; - const params = localVariables.get("redeemParameters") as OrderResponse; - expect(localVariables.delete("redeemParameters")).is.true; - expect(localVariables.delete("fastVaa")).is.true; - expect(localVariables.delete("auctionId")).is.true; - - // Fetch balance of player four since they were the highest bidder. - const usdc = IERC20__factory.connect(engineEnv.tokenAddress, engineProvider); - const balanceBefore = await usdc.balanceOf(highestBidder.address); - const expectedAmount = await engine - .liveAuctionInfo(auctionId) - .then((info) => info.amount); - - const receipt = await engine - .executeSlowOrderAndRedeem(fastVaa, params) - .then((tx) => mineWait(engineProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - - const balanceAfter = await usdc.balanceOf(highestBidder.address); - expect(balanceAfter.sub(balanceBefore).toString()).to.eql( - expectedAmount.toString(), - ); - }); - }); - - describe(`Penalized Auction`, () => { - before(`From Network -- Mint USDC`, async () => { - if (fromEnv.chainId == MATCHING_ENGINE_CHAIN) { - console.log("Skipfrom outbound tests from Matching Engine."); - this.ctx.skip(); - } - - const usdc = IERC20__factory.connect(fromEnv.tokenAddress, fromWallet); - - await burnAllUsdc(usdc); - - await mintNativeUsdc( - IERC20__factory.connect(fromEnv.tokenAddress, fromProvider), - fromWallet.address, - TEST_AMOUNT, - ); - }); - - after(`Burn USDC`, async () => { - const usdc = IERC20__factory.connect(fromEnv.tokenAddress, fromWallet); - await burnAllUsdc(usdc); - }); - - it(`From Network -- Place Fast Market Order`, async () => { - const amountIn = await (async () => { - if (fromEnv.chainType == ChainType.Evm) { - const usdc = IERC20__factory.connect(fromEnv.tokenAddress, fromWallet); - const amount = await usdc.balanceOf(fromWallet.address); - await usdc - .approve(fromTokenRouter.address, amount) - .then((tx) => mineWait(fromProvider, tx)); - - return BigInt(amount.toString()); - } else { - throw new Error("Unsupported chain"); - } - })(); - localVariables.set("amountIn", amountIn); - - const targetChain = toChainId(toChainName); - const minAmountOut = BigInt(0); - const deadline = 0; - const receipt = await fromTokenRouter - .placeFastMarketOrder( - amountIn, - targetChain, - Buffer.from(tryNativeToUint8Array(toWallet.address, toChainName)), - Buffer.from("All your base are belong to us."), - FEE_AMOUNT, - deadline, - minAmountOut, - fromWallet.address, - ) - .then((tx) => mineWait(fromProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - const transactionResult = await fromTokenRouter.getTransactionResults( - receipt.transactionHash, - ); - expect(transactionResult.wormhole.emitterAddress).to.eql( - tryNativeToUint8Array(fromEnv.tokenRouterAddress, fromChainName), - ); - expect(transactionResult.wormhole.message.body).has.property( - "slowOrderResponse", - ); - expect(transactionResult.circleMessage).is.not.undefined; - expect(transactionResult.fastMessage).is.not.undefined; - - const signedVaas = await guardianNetwork.observeManyEvm( - fromProvider, - fromChainName, - receipt, - ); - expect(signedVaas.length).to.eql(2); - - // The first message is the slow CCTP transfer. - const [slowOrderResponse, fastVaa] = signedVaas; - - const circleBridgeMessage = transactionResult.circleMessage!; - const circleAttestation = circleAttester.createAttestation(circleBridgeMessage); - - const redeemParameters: OrderResponse = { - encodedWormholeMessage: slowOrderResponse, - circleBridgeMessage, - circleAttestation, - }; - localVariables.set("redeemParameters", redeemParameters); - localVariables.set("fastVaa", fastVaa); - }); - - it(`Matching Engine -- Start Fast Order Auction`, async () => { - const fastVaa = localVariables.get("fastVaa") as Uint8Array; - - // Parse the vaa, we will need the hash for later. - const parsedFastVaa = deserialize("Uint8Array", fastVaa); - localVariables.set("auctionId", keccak256(parsedFastVaa.hash)); - const fastOrder = MessageDecoder.decode(parsedFastVaa.payload).body - .fastMarketOrder; - - if (fastOrder === undefined) { - throw new Error("Fast order undefined"); - } - - // Security deposit amount of the initial bid. - const initialDeposit = fastOrder.amountIn + fastOrder.maxFee; - - // Prepare usdc for the auction. - const usdc = IERC20__factory.connect(engineEnv.tokenAddress, initialBidder); - await mintNativeUsdc(usdc, initialBidder.address, initialDeposit); - await usdc.approve(engine.address, initialDeposit); - - const balanceBefore = await usdc.balanceOf(initialBidder.address); - - const receipt = await engine - .connect(initialBidder) - .placeInitialBid(fastVaa, fastOrder.maxFee) - .then((tx) => mineWait(engineProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - - const balanceAfter = await usdc.balanceOf(initialBidder.address); - expect(balanceBefore.sub(balanceAfter).toString()).to.eql( - initialDeposit.toString(), - ); - - // Validate state changes. - const auctionData = await engine.liveAuctionInfo( - localVariables.get("auctionId"), - ); - - expect(auctionData.status).to.eql(1); - expect(auctionData.startBlock.toString()).to.eql( - receipt.blockNumber.toString(), - ); - expect(auctionData.highestBidder).to.eql(initialBidder.address); - expect(auctionData.initialBidder).to.eql(initialBidder.address); - expect(auctionData.amount.toString()).to.eql(fastOrder.amountIn.toString()); - expect(auctionData.securityDeposit.toString()).to.eql( - fastOrder.maxFee.toString(), - ); - expect(auctionData.bidPrice.toString()).to.eql(fastOrder.maxFee.toString()); - }); - - it(`Matching Engine -- Fast Order Auction Period`, async () => { - const auctionId = localVariables.get("auctionId") as Uint8Array; - - const auctionInfoBefore = await engine.liveAuctionInfo(auctionId); - const startingBid = ethers.BigNumber.from(auctionInfoBefore.bidPrice); - const initialDeposit = ethers.BigNumber.from(auctionInfoBefore.amount).add( - ethers.BigNumber.from(auctionInfoBefore.securityDeposit), - ); - expect(startingBid.gt(0) && initialDeposit.gt(0)).is.true; - - // Create array of test bids. This structure should not change, otherwise - // the following tests will fail. - const bids: ScoreKeeper[] = [ - { - player: bidderTwo, - bid: startingBid.sub(1), - balance: ethers.BigNumber.from(0), - }, - { - player: bidderThree, - bid: startingBid.div(2), - balance: ethers.BigNumber.from(0), - }, - { - player: highestBidder, - bid: startingBid.div(3), - balance: ethers.BigNumber.from(0), - }, - ]; - - // Loop through and make multiple bids in the same block. - for (let i = 0; i < bids.length; i++) { - const player = bids[i].player; - const usdc = IERC20__factory.connect(engineEnv.tokenAddress, player); - await mintNativeUsdc(usdc, player.address, initialDeposit, false); - await usdc.approve(engine.address, initialDeposit); - - bids[i].balance = await usdc.balanceOf(player.address); - - // Improve the bid. - await engine.connect(player).improveBid(auctionId, bids[i].bid); - } - - // Mine the block. - await mine(engineProvider); - - // Validate balance changes. The lowest bid should have zero balance, the others - // should've been refunded. - for (let i = 0; i < bids.length; i++) { - const player = bids[i].player; - const usdc = IERC20__factory.connect(engineEnv.tokenAddress, player); - const balanceAfter = await usdc.balanceOf(player.address); - - if (i == 2) { - expect(balanceAfter.sub(bids[i].balance).toString()).to.eql("0"); - } else { - expect(balanceAfter.toString()).to.eql( - bids[i].balance.add(initialDeposit).toString(), - ); - } - } - - // Validate state changes. - const auctionInfoAfter = await engine.liveAuctionInfo(auctionId); - - expect(auctionInfoAfter.status).to.eql(1); - expect(auctionInfoAfter.startBlock.toString()).to.eql( - auctionInfoBefore.startBlock.toString(), - ); - expect(auctionInfoAfter.highestBidder).to.eql(highestBidder.address); - expect(auctionInfoAfter.initialBidder).to.eql(auctionInfoBefore.initialBidder); - expect(auctionInfoAfter.amount.toString()).to.eql( - auctionInfoBefore.amount.toString(), - ); - expect(auctionInfoAfter.securityDeposit.toString()).to.eql( - auctionInfoBefore.securityDeposit.toString(), - ); - expect(auctionInfoAfter.bidPrice.toString()).to.eql(bids[2].bid.toString()); - }); - - it(`Matching Engine -- Execute Fast Order As Liquidator (After Grace Period Ends)`, async () => { - const auctionId = localVariables.get("auctionId") as Uint8Array; - - // Mine 50% of the way through the penalty period. - await engine - .getPenaltyBlocks() - .then((blocks) => - mineToPenaltyPeriod(auctionId, engine, engineProvider, blocks / 2), - ); - - // Fetch the initial bidder so we can do a balance check. - const auctionInfo = await engine.liveAuctionInfo(auctionId); - - const usdc = IERC20__factory.connect(engineEnv.tokenAddress, highestBidder); - const balanceBefore = await usdc.balanceOf(highestBidder.address); - const balanceLiquidatorBefore = await usdc.balanceOf(liquidator.address); - const initialBidderBefore = await usdc.balanceOf(auctionInfo.initialBidder); - - const receipt = await engine - .connect(liquidator) - .executeFastOrder(localVariables.get("fastVaa")) - .then((tx) => mineWait(engineProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - - const [penalty, reward] = await engine.calculateDynamicPenalty(auctionId); - - const transactionResult = await engine.getTransactionResults( - receipt.transactionHash, - ); - - if (toChainName == MATCHING_ENGINE_NAME) { - expect(transactionResult.wormhole.emitterAddress).to.eql( - tryNativeToUint8Array(engine.address, MATCHING_ENGINE_NAME), - ); - expect(transactionResult.wormhole.message.body).has.property("fastFill"); - expect(transactionResult.circleMessage).is.undefined; - } else { - expect(transactionResult.wormhole.emitterAddress).to.eql( - tryNativeToUint8Array(engine.address, MATCHING_ENGINE_NAME), - ); - expect(transactionResult.wormhole.message.body).has.property("fill"); - expect(transactionResult.circleMessage).is.not.undefined; - } - - expect(transactionResult.fastMessage).is.undefined; - - // Validate state and balance changes. - const balanceAfter = await usdc.balanceOf(highestBidder.address); - const initialBidderAfter = await usdc.balanceOf(auctionInfo.initialBidder); - const balanceLiquidatorAfter = await usdc.balanceOf(liquidator.address); - const initAuctionFee = await fromTokenRouter.getInitialAuctionFee(); - - expect(balanceAfter.sub(balanceBefore).toString()).to.eql( - ethers.BigNumber.from(auctionInfo.bidPrice) - .add(ethers.BigNumber.from(auctionInfo.securityDeposit)) - .sub(ethers.BigNumber.from(penalty).add(ethers.BigNumber.from(reward))) - .toString(), - ); - expect(balanceLiquidatorAfter.sub(balanceLiquidatorBefore).toString()).to.eql( - penalty.toString(), - ); - expect(initialBidderAfter.sub(initialBidderBefore).eq(initAuctionFee)).is.true; - - // Auction status should be complete (2). - const auctionStatus = await engine - .liveAuctionInfo(auctionId) - .then((info) => info.status); - expect(auctionStatus).to.eql(2); - - // Fetch and store the vaa for redeeming the fill. - const signedVaa = await guardianNetwork.observeEvm( - engineProvider, - MATCHING_ENGINE_NAME, - receipt, - ); - - let orderResponse: OrderResponse; - if (toChainName == MATCHING_ENGINE_NAME) { - orderResponse = { - encodedWormholeMessage: signedVaa, - circleBridgeMessage: Buffer.from(""), - circleAttestation: Buffer.from(""), - }; - } else { - const circleBridgeMessage = transactionResult.circleMessage!; - const circleAttestation = - circleAttester.createAttestation(circleBridgeMessage); - - orderResponse = { - encodedWormholeMessage: signedVaa, - circleBridgeMessage, - circleAttestation, - }; - } - - localVariables.set("fastOrderResponse", orderResponse); - localVariables.set("reward", reward); - }); - - it(`To Network -- Redeem Fill`, async () => { - const auctionId = localVariables.get("auctionId") as Uint8Array; - const orderResponse = localVariables.get("fastOrderResponse") as OrderResponse; - const reward = localVariables.get("reward") as string; - expect(localVariables.delete("reward")).is.true; - expect(localVariables.delete("fastOrderResponse")).is.true; - - const usdc = IERC20__factory.connect(toEnv.tokenAddress, toProvider); - const balanceBefore = await usdc.balanceOf(toWallet.address); - - const receipt = await toTokenRouter - .redeemFill(orderResponse) - .then((tx) => mineWait(toProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - - // Validate balance changes. - const [bidPrice, amount] = await engine - .liveAuctionInfo(auctionId) - .then((info) => [ - ethers.BigNumber.from(info.bidPrice), - ethers.BigNumber.from(info.amount), - ]); - const initAuctionFee = await fromTokenRouter.getInitialAuctionFee(); - const balanceAfter = await usdc.balanceOf(toWallet.address); - - // Add the reward, since the fast auction wasn't executed during - // the grace period. - expect(balanceAfter.sub(balanceBefore).toString()).to.eql( - amount.sub(bidPrice).sub(initAuctionFee).add(reward).toString(), - ); - }); - - it(`Matching Engine -- Execute Slow Vaa And Redeem`, async () => { - const auctionId = localVariables.get("auctionId") as Uint8Array; - const fastVaa = localVariables.get("fastVaa") as Uint8Array; - const params = localVariables.get("redeemParameters") as OrderResponse; - expect(localVariables.delete("redeemParameters")).is.true; - expect(localVariables.delete("fastVaa")).is.true; - expect(localVariables.delete("auctionId")).is.true; - - // Fetch balance of player four since they were the highest bidder. - const usdc = IERC20__factory.connect(engineEnv.tokenAddress, engineProvider); - const balanceBefore = await usdc.balanceOf(highestBidder.address); - const expectedAmount = await engine - .liveAuctionInfo(auctionId) - .then((info) => info.amount); - - const receipt = await engine - .executeSlowOrderAndRedeem(fastVaa, params) - .then((tx) => mineWait(engineProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - - const balanceAfter = await usdc.balanceOf(highestBidder.address); - expect(balanceAfter.sub(balanceBefore).toString()).to.eql( - expectedAmount.toString(), - ); - }); - }); - - describe(`No Auction`, () => { - before(`From Network -- Mint USDC`, async () => { - if (fromEnv.chainId == MATCHING_ENGINE_CHAIN) { - console.log("Skipfrom outbound tests from Matching Engine."); - this.ctx.skip(); - } - - const usdc = IERC20__factory.connect(fromEnv.tokenAddress, fromWallet); - - await burnAllUsdc(usdc); - - await mintNativeUsdc( - IERC20__factory.connect(fromEnv.tokenAddress, fromProvider), - fromWallet.address, - TEST_AMOUNT, - ); - }); - - after(`Burn USDC`, async () => { - const usdc = IERC20__factory.connect(fromEnv.tokenAddress, fromWallet); - await burnAllUsdc(usdc); - }); - - it(`From Network -- Place Fast Market Order`, async () => { - const amountIn = await (async () => { - if (fromEnv.chainType == ChainType.Evm) { - const usdc = IERC20__factory.connect(fromEnv.tokenAddress, fromWallet); - const amount = await usdc.balanceOf(fromWallet.address); - await usdc - .approve(fromTokenRouter.address, amount) - .then((tx) => mineWait(fromProvider, tx)); - - return BigInt(amount.toString()); - } else { - throw new Error("Unsupported chain"); - } - })(); - localVariables.set("amountIn", amountIn); - - const targetChain = toChainId(toChainName); - const minAmountOut = BigInt(0); - const deadline = 0; - const receipt = await fromTokenRouter - .placeFastMarketOrder( - amountIn, - targetChain, - Buffer.from(tryNativeToUint8Array(toWallet.address, toChainName)), - Buffer.from("All your base are belong to us."), - FEE_AMOUNT, - deadline, - minAmountOut, - fromWallet.address, - ) - .then((tx) => mineWait(fromProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - const transactionResult = await fromTokenRouter.getTransactionResults( - receipt.transactionHash, - ); - expect(transactionResult.wormhole.emitterAddress).to.eql( - tryNativeToUint8Array(fromEnv.tokenRouterAddress, fromChainName), - ); - expect(transactionResult.wormhole.message.body).has.property( - "slowOrderResponse", - ); - expect(transactionResult.circleMessage).is.not.undefined; - expect(transactionResult.fastMessage).is.not.undefined; - - const signedVaas = await guardianNetwork.observeManyEvm( - fromProvider, - fromChainName, - receipt, - ); - expect(signedVaas.length).to.eql(2); - - // The first message is the slow CCTP transfer. - const [slowOrderResponse, fastVaa] = signedVaas; - - const circleBridgeMessage = transactionResult.circleMessage!; - const circleAttestation = circleAttester.createAttestation(circleBridgeMessage); - - const redeemParameters: OrderResponse = { - encodedWormholeMessage: slowOrderResponse, - circleBridgeMessage, - circleAttestation, - }; - localVariables.set("redeemParameters", redeemParameters); - localVariables.set("fastVaa", fastVaa); - }); - - it(`Matching Engine -- Execute Slow Vaa And Redeem`, async () => { - const fastVaa = localVariables.get("fastVaa") as Uint8Array; - const params = localVariables.get("redeemParameters") as OrderResponse; - expect(localVariables.delete("redeemParameters")).is.true; - expect(localVariables.delete("fastVaa")).is.true; - - // NOTE: Imagine that several minutes have passed, and no auction has been started :). - - // Parse the slow VAA for the baseFee and amount - const baseFee = MessageDecoder.decode( - deserialize("Uint8Array", params.encodedWormholeMessage).payload, - ).body.slowOrderResponse!.baseFee; - - // Use player one as the relayer. - const usdc = IERC20__factory.connect(engineEnv.tokenAddress, engineProvider); - const feeRecipientBefore = await usdc.balanceOf(engineEnv.feeRecipient!); - - const receipt = await engine - .connect(initialBidder) - .executeSlowOrderAndRedeem(fastVaa, params) - .then((tx) => mineWait(engineProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - - // Balance check. - const feeRecipientAfter = await usdc.balanceOf(engineEnv.feeRecipient!); - expect(feeRecipientAfter.sub(feeRecipientBefore).toString()).to.eql( - baseFee.toString(), - ); - - const transactionResult = await engine.getTransactionResults( - receipt.transactionHash, - ); - - if (toChainName == MATCHING_ENGINE_NAME) { - expect(transactionResult.wormhole.emitterAddress).to.eql( - tryNativeToUint8Array(engine.address, MATCHING_ENGINE_NAME), - ); - expect(transactionResult.wormhole.message.body).has.property("fastFill"); - expect(transactionResult.circleMessage).is.undefined; - } else { - expect(transactionResult.wormhole.emitterAddress).to.eql( - tryNativeToUint8Array(engine.address, MATCHING_ENGINE_NAME), - ); - expect(transactionResult.wormhole.message.body).has.property("fill"); - expect(transactionResult.circleMessage).is.not.undefined; - } - - expect(transactionResult.fastMessage).is.undefined; - - // Fetch and store the vaa for redeeming the fill. - const signedVaa = await guardianNetwork.observeEvm( - engineProvider, - MATCHING_ENGINE_NAME, - receipt, - ); - - let orderResponse: OrderResponse; - if (toChainName == MATCHING_ENGINE_NAME) { - orderResponse = { - encodedWormholeMessage: signedVaa, - circleBridgeMessage: Buffer.from(""), - circleAttestation: Buffer.from(""), - }; - } else { - const circleBridgeMessage = transactionResult.circleMessage!; - const circleAttestation = - circleAttester.createAttestation(circleBridgeMessage); - - orderResponse = { - encodedWormholeMessage: signedVaa, - circleBridgeMessage, - circleAttestation, - }; - } - - // Confirm that the auction was market as complete. - const auctionId = keccak256(deserialize("Uint8Array", fastVaa).hash); - const auctionStatus = await engine - .liveAuctionInfo(auctionId) - .then((info) => info.status); - expect(auctionStatus).to.eql(2); - - localVariables.set("fastOrderResponse", orderResponse); - localVariables.set("baseFee", baseFee); - }); - - it(`To Network -- Redeem Fill`, async () => { - const orderResponse = localVariables.get("fastOrderResponse") as OrderResponse; - const baseFee = localVariables.get("baseFee") as string; - expect(localVariables.delete("fastOrderResponse")).is.true; - expect(localVariables.delete("baseFee")).is.true; - - const usdc = IERC20__factory.connect(toEnv.tokenAddress, toProvider); - const balanceBefore = await usdc.balanceOf(toWallet.address); - - const receipt = await toTokenRouter - .redeemFill(orderResponse) - .then((tx) => mineWait(toProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - - // Validate balance changes. - const balanceAfter = await usdc.balanceOf(toWallet.address); - - expect(balanceAfter.sub(balanceBefore).toString()).to.eql( - TEST_AMOUNT.sub(baseFee).toString(), - ); - }); - }); - - describe(`No Auction - Deadline Exceeded`, () => { - before(`From Network -- Mint USDC`, async () => { - if (fromEnv.chainId == MATCHING_ENGINE_CHAIN) { - console.log("Skipfrom outbound tests from Matching Engine."); - this.ctx.skip(); - } - - const usdc = IERC20__factory.connect(fromEnv.tokenAddress, fromWallet); - - await burnAllUsdc(usdc); - - await mintNativeUsdc( - IERC20__factory.connect(fromEnv.tokenAddress, fromProvider), - fromWallet.address, - TEST_AMOUNT, - ); - }); - - after(`Burn USDC`, async () => { - const usdc = IERC20__factory.connect(fromEnv.tokenAddress, fromWallet); - await burnAllUsdc(usdc); - }); - - it(`From Network -- Place Fast Market Order`, async () => { - const amountIn = await (async () => { - if (fromEnv.chainType == ChainType.Evm) { - const usdc = IERC20__factory.connect(fromEnv.tokenAddress, fromWallet); - const amount = await usdc.balanceOf(fromWallet.address); - await usdc - .approve(fromTokenRouter.address, amount) - .then((tx) => mineWait(fromProvider, tx)); - - return BigInt(amount.toString()); - } else { - throw new Error("Unsupported chain"); - } - })(); - localVariables.set("amountIn", amountIn); - - const targetChain = toChainId(toChainName); - const minAmountOut = BigInt(0); - - // Set the deadline to the current block timestamp. - const currentBlock = await engineProvider.getBlockNumber(); - const deadline = (await engineProvider.getBlock(currentBlock)).timestamp; - - const receipt = await fromTokenRouter - .placeFastMarketOrder( - amountIn, - targetChain, - Buffer.from(tryNativeToUint8Array(toWallet.address, toChainName)), - Buffer.from("All your base are belong to us."), - FEE_AMOUNT, - deadline!, - minAmountOut, - fromWallet.address, - ) - .then((tx) => mineWait(fromProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - const transactionResult = await fromTokenRouter.getTransactionResults( - receipt.transactionHash, - ); - expect(transactionResult.wormhole.emitterAddress).to.eql( - tryNativeToUint8Array(fromEnv.tokenRouterAddress, fromChainName), - ); - expect(transactionResult.wormhole.message.body).has.property( - "slowOrderResponse", - ); - expect(transactionResult.circleMessage).is.not.undefined; - expect(transactionResult.fastMessage).is.not.undefined; - - const signedVaas = await guardianNetwork.observeManyEvm( - fromProvider, - fromChainName, - receipt, - ); - expect(signedVaas.length).to.eql(2); - - // The first message is the slow CCTP transfer. - const [slowOrderResponse, fastVaa] = signedVaas; - - const circleBridgeMessage = transactionResult.circleMessage!; - const circleAttestation = circleAttester.createAttestation(circleBridgeMessage); - - const redeemParameters: OrderResponse = { - encodedWormholeMessage: slowOrderResponse, - circleBridgeMessage, - circleAttestation, - }; - localVariables.set("redeemParameters", redeemParameters); - localVariables.set("fastVaa", fastVaa); - }); - - it(`Matching Engine -- Attempt to Start Auction After Deadline`, async () => { - const fastVaa = localVariables.get("fastVaa") as Uint8Array; - - // Parse the vaa, we will need the hash for later. - const parsedFastVaa = deserialize("Uint8Array", fastVaa); - localVariables.set("auctionId", keccak256(parsedFastVaa.hash)); - const fastOrder = MessageDecoder.decode(parsedFastVaa.payload).body - .fastMarketOrder; - - if (fastOrder === undefined) { - throw new Error("Fast order undefined"); - } - - // Security deposit amount of the initial bid. - const initialDeposit = fastOrder.amountIn + fastOrder.maxFee; - - // Prepare usdc for the auction. - const usdc = IERC20__factory.connect(engineEnv.tokenAddress, initialBidder); - await mintNativeUsdc(usdc, initialBidder.address, initialDeposit); - await usdc.approve(engine.address, initialDeposit); - - let failedGracefully = false; - const receipt = await engine - .connect(initialBidder) - .placeInitialBid(fastVaa, fastOrder.maxFee) - .then((tx) => mineWait(engineProvider, tx)) - .catch((err) => { - const error = errorDecoder(err); - if (error.selector == "ErrDeadlineExceeded") { - failedGracefully = true; - } - }); - - expect(failedGracefully).is.true; - }); - - it(`Matching Engine -- Execute Slow Vaa And Redeem`, async () => { - const fastVaa = localVariables.get("fastVaa") as Uint8Array; - const params = localVariables.get("redeemParameters") as OrderResponse; - expect(localVariables.delete("redeemParameters")).is.true; - expect(localVariables.delete("fastVaa")).is.true; - - // NOTE: Imagine that several minutes have passed, and no auction has been started :). - - // Parse the slow VAA for the baseFee and amount - const baseFee = MessageDecoder.decode( - deserialize("Uint8Array", params.encodedWormholeMessage).payload, - ).body.slowOrderResponse!.baseFee; - - // Use player one as the relayer. - const usdc = IERC20__factory.connect(engineEnv.tokenAddress, engineProvider); - const feeRecipientBefore = await usdc.balanceOf(engineEnv.feeRecipient!); - - const receipt = await engine - .connect(initialBidder) - .executeSlowOrderAndRedeem(fastVaa, params) - .then((tx) => mineWait(engineProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - - // Balance check. - const feeRecipientAfter = await usdc.balanceOf(engineEnv.feeRecipient!); - expect(feeRecipientAfter.sub(feeRecipientBefore).toString()).to.eql( - baseFee.toString(), - ); - - const transactionResult = await engine.getTransactionResults( - receipt.transactionHash, - ); - - if (toChainName == MATCHING_ENGINE_NAME) { - expect(transactionResult.wormhole.emitterAddress).to.eql( - tryNativeToUint8Array(engine.address, MATCHING_ENGINE_NAME), - ); - expect(transactionResult.wormhole.message.body).has.property("fastFill"); - expect(transactionResult.circleMessage).is.undefined; - } else { - expect(transactionResult.wormhole.emitterAddress).to.eql( - tryNativeToUint8Array(engine.address, MATCHING_ENGINE_NAME), - ); - expect(transactionResult.wormhole.message.body).has.property("fill"); - expect(transactionResult.circleMessage).is.not.undefined; - } - - expect(transactionResult.fastMessage).is.undefined; - - // Fetch and store the vaa for redeeming the fill. - const signedVaa = await guardianNetwork.observeEvm( - engineProvider, - MATCHING_ENGINE_NAME, - receipt, - ); - - let orderResponse: OrderResponse; - if (toChainName == MATCHING_ENGINE_NAME) { - orderResponse = { - encodedWormholeMessage: signedVaa, - circleBridgeMessage: Buffer.from(""), - circleAttestation: Buffer.from(""), - }; - } else { - const circleBridgeMessage = transactionResult.circleMessage!; - const circleAttestation = - circleAttester.createAttestation(circleBridgeMessage); - - orderResponse = { - encodedWormholeMessage: signedVaa, - circleBridgeMessage, - circleAttestation, - }; - } - - // Confirm that the auction was market as complete. - const auctionId = keccak256(deserialize("Uint8Array", fastVaa).hash); - const auctionStatus = await engine - .liveAuctionInfo(auctionId) - .then((info) => info.status); - expect(auctionStatus).to.eql(2); - - localVariables.set("fastOrderResponse", orderResponse); - localVariables.set("baseFee", baseFee); - }); - - it(`To Network -- Redeem Fill`, async () => { - const orderResponse = localVariables.get("fastOrderResponse") as OrderResponse; - const baseFee = localVariables.get("baseFee") as string; - expect(localVariables.delete("fastOrderResponse")).is.true; - expect(localVariables.delete("baseFee")).is.true; - - const usdc = IERC20__factory.connect(toEnv.tokenAddress, toProvider); - const balanceBefore = await usdc.balanceOf(toWallet.address); - - const receipt = await toTokenRouter - .redeemFill(orderResponse) - .then((tx) => mineWait(toProvider, tx)) - .catch((err) => { - console.log(err); - console.log(errorDecoder(err)); - throw err; - }); - - // Validate balance changes. - const balanceAfter = await usdc.balanceOf(toWallet.address); - - expect(balanceAfter.sub(balanceBefore).toString()).to.eql( - TEST_AMOUNT.sub(baseFee).toString(), - ); - }); - }); - }); - } -}); diff --git a/evm/ts/tests/run_integration_test.sh b/evm/ts/tests/run_integration_test.sh index 279bef826..aae93dbfb 100644 --- a/evm/ts/tests/run_integration_test.sh +++ b/evm/ts/tests/run_integration_test.sh @@ -25,17 +25,11 @@ anvil --port 8548 \ --no-mining \ --fork-url $ETHEREUM_RPC > $LOGS/ethereum.log & -# Base (CCTP). -anvil --port 8549 \ - -m "myth like bonus scare over problem client lizard pioneer submit female collect" \ - --no-mining \ - --fork-url $BASE_RPC > $LOGS/base.log & - # Chill. sleep 2 # Double-check number of anvil instances. -if [ "$( pgrep anvil | wc -l )" -ne 3 ]; then +if [ "$( pgrep anvil | wc -l )" -ne 2 ]; then echo "Not all anvil instances are running. Try again." pkill anvil exit 1 diff --git a/package-lock.json b/package-lock.json index 2dbddc59e..a9cf504d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,9 +24,9 @@ "license": "Apache-2.0", "dependencies": { "@wormhole-foundation/example-liquidity-layer-definitions": "0.0.1", - "@wormhole-foundation/sdk-base": "^0.10.9", - "@wormhole-foundation/sdk-definitions": "^0.10.9", - "@wormhole-foundation/sdk-evm": "^0.10.9", + "@wormhole-foundation/sdk-base": "^1.4.4", + "@wormhole-foundation/sdk-definitions": "^1.4.4", + "@wormhole-foundation/sdk-evm": "^1.4.4", "ethers-v5": "npm:ethers@^5.7.2" }, "devDependencies": { @@ -1144,9 +1144,9 @@ } }, "node_modules/@solana/web3.js": { - "version": "1.95.3", - "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.95.3.tgz", - "integrity": "sha512-O6rPUN0w2fkNqx/Z3QJMB9L225Ex10PRDH8bTaIUPZXMPV0QP8ZpPvjQnXK+upUczlRgzHzd6SjKIha1p+I6og==", + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.0.tgz", + "integrity": "sha512-nz3Q5OeyGFpFCR+erX2f6JPt3sKhzhYcSycBCSPkWjzSVDh/Rr1FqTVMRe58FKO16/ivTUcuJjeS5MyBvpkbzA==", "dependencies": { "@babel/runtime": "^7.25.0", "@noble/curves": "^1.4.2", @@ -1362,20 +1362,21 @@ "link": true }, "node_modules/@wormhole-foundation/sdk-base": { - "version": "0.10.9", - "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-base/-/sdk-base-0.10.9.tgz", - "integrity": "sha512-E56Z7FK1swrHvBvDOgWZBLDcyijpGB27dw10ZAZgesHksTBCIS4ehJY9b2qulo19R3fxRW/reKYzAmjxkpI+sg==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-base/-/sdk-base-1.4.4.tgz", + "integrity": "sha512-i6Hm46FjBj3bamivSw5UWEAvIRsy63Oww7AaZpmt2CXyeGJgj+UM20f5+Wd+jBaRKmQRzkEiWqFNKuf6HZmFPg==", "dependencies": { - "@scure/base": "^1.1.3" + "@scure/base": "^1.1.3", + "binary-layout": "^1.0.3" } }, "node_modules/@wormhole-foundation/sdk-connect": { - "version": "0.10.9", - "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-connect/-/sdk-connect-0.10.9.tgz", - "integrity": "sha512-UCneSFMDho3p3rUFoxpDV+9zutJWcQJJ78RLLpjya0EivNy2AMTFWbP0sQdx+3kHw0MIJM/JtsUoUhPZZKeD/w==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-connect/-/sdk-connect-1.4.4.tgz", + "integrity": "sha512-YDBDgsglmp9IeyxieTQ3SWDwOaPqR5+FtKhuQ4gXef8AgzJgrhg5yVtFRS1L6E+SV+zMbtwKvY2qywVSfLjYnQ==", "dependencies": { - "@wormhole-foundation/sdk-base": "0.10.9", - "@wormhole-foundation/sdk-definitions": "0.10.9", + "@wormhole-foundation/sdk-base": "1.4.4", + "@wormhole-foundation/sdk-definitions": "1.4.4", "axios": "^1.4.0" }, "engines": { @@ -1383,21 +1384,21 @@ } }, "node_modules/@wormhole-foundation/sdk-definitions": { - "version": "0.10.9", - "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-definitions/-/sdk-definitions-0.10.9.tgz", - "integrity": "sha512-9lbMpvcaBL9a2eoyfJ5gauFREO0hqYw+Nplc3L6qzckB/2Sc0nE0vYDRyL+OwaRT4BUffmWOaUukBEDqbc1sGQ==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-definitions/-/sdk-definitions-1.4.4.tgz", + "integrity": "sha512-bD8J3Y0dAGgx0k2IgpKlZoRqRw0/WiAebZnMwVsgGfg3W1ZIk0XkB2BP3lMmmLu6zMMjBjPCqTn6O+xPnz/MbA==", "dependencies": { "@noble/curves": "^1.4.0", "@noble/hashes": "^1.3.1", - "@wormhole-foundation/sdk-base": "0.10.9" + "@wormhole-foundation/sdk-base": "1.4.4" } }, "node_modules/@wormhole-foundation/sdk-evm": { - "version": "0.10.9", - "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-evm/-/sdk-evm-0.10.9.tgz", - "integrity": "sha512-AM66hZHMAvggv9GwOdyep5AOT0M6JTJ415c+ksmdSw7egyVGwAXWl0khfJE1BHQDDAIsmJaTtPINQwdaki+4Yw==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-evm/-/sdk-evm-1.4.4.tgz", + "integrity": "sha512-6Lhp/jqahi2ejEyCnuXSlAGS38ay1puvxqdz2ApltCKKo4lL+S3iXE+Pl8YHiDz+F6eXZeIbxki0SiPEraLB3g==", "dependencies": { - "@wormhole-foundation/sdk-connect": "0.10.9", + "@wormhole-foundation/sdk-connect": "1.4.4", "ethers": "^6.5.1" }, "engines": { @@ -1489,15 +1490,15 @@ } }, "node_modules/@wormhole-foundation/sdk-solana": { - "version": "0.10.9", - "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-solana/-/sdk-solana-0.10.9.tgz", - "integrity": "sha512-+dW7jBhTb8sgEcJF7Y2BkfM2QR7OaiL/6m25ungkDt7wFuPIIVGi4NM0Szngg+YyMs910PYdR1lcXd3Ijl/Nrw==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-solana/-/sdk-solana-1.4.4.tgz", + "integrity": "sha512-6Sr8Py+qewXnfVdafgCxN6MFtA8QwhKh5PQi9Zvi4GlJMM1qHxSEy5uLwHyORTVGghpZmOFweYhkDQl073GzDA==", "dependencies": { "@coral-xyz/anchor": "0.29.0", "@coral-xyz/borsh": "0.29.0", "@solana/spl-token": "0.3.9", - "@solana/web3.js": "^1.95.2", - "@wormhole-foundation/sdk-connect": "0.10.9", + "@solana/web3.js": "^1.95.8", + "@wormhole-foundation/sdk-connect": "1.4.4", "rpc-websockets": "^7.10.0" }, "engines": { @@ -1505,15 +1506,15 @@ } }, "node_modules/@wormhole-foundation/sdk-solana-core": { - "version": "0.10.9", - "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-solana-core/-/sdk-solana-core-0.10.9.tgz", - "integrity": "sha512-M+ZZpiZRwTTlm+bn1ZPYecUlcDI+OUwgX8bgwmgcQSADxXJkYtOFPsAB2R8eOcAmQirhkMK4Mjv//+IHrfaTBw==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-solana-core/-/sdk-solana-core-1.4.4.tgz", + "integrity": "sha512-ACo+Gak4P7xLcSZyH9koAO55CAkpBX62osZMgU6KtB8JnEP0jiUtWj6SNo1eiT5+3KNmcCZQr4VDd0ka+E6kSw==", "dependencies": { "@coral-xyz/anchor": "0.29.0", "@coral-xyz/borsh": "0.29.0", - "@solana/web3.js": "^1.95.2", - "@wormhole-foundation/sdk-connect": "0.10.9", - "@wormhole-foundation/sdk-solana": "0.10.9" + "@solana/web3.js": "^1.95.8", + "@wormhole-foundation/sdk-connect": "1.4.4", + "@wormhole-foundation/sdk-solana": "1.4.4" }, "engines": { "node": ">=16" @@ -1743,6 +1744,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/binary-layout": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/binary-layout/-/binary-layout-1.0.3.tgz", + "integrity": "sha512-kpXCSOko4wbQaQswZk4IPcjVZwN77TKZgjMacdoX54EvUHAn/CzJclCt25SUmpXfzFrGovoq3LkPJkMy10bZxQ==" + }, "node_modules/bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -3887,9 +3893,9 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" }, "node_modules/type-detect": { "version": "4.0.8", @@ -4213,11 +4219,11 @@ "@solana/web3.js": "^1.95.3", "@types/node-fetch": "^2.6.11", "@wormhole-foundation/example-liquidity-layer-definitions": "0.0.1", - "@wormhole-foundation/sdk-base": "^0.10.9", - "@wormhole-foundation/sdk-definitions": "^0.10.9", - "@wormhole-foundation/sdk-evm": "^0.10.9", - "@wormhole-foundation/sdk-solana": "^0.10.9", - "@wormhole-foundation/sdk-solana-core": "^0.10.9", + "@wormhole-foundation/sdk-base": "^1.4.4", + "@wormhole-foundation/sdk-definitions": "^1.4.4", + "@wormhole-foundation/sdk-evm": "^1.4.4", + "@wormhole-foundation/sdk-solana": "^1.4.4", + "@wormhole-foundation/sdk-solana-core": "^1.4.4", "anchor-0.29.0": "npm:@coral-xyz/anchor@^0.29.0", "bn.js": "^5.2.1", "dotenv": "^16.4.1", @@ -4540,9 +4546,9 @@ "@solana/spl-token": "^0.4.6", "@wormhole-foundation/example-liquidity-layer-evm": "0.0.1", "@wormhole-foundation/example-liquidity-layer-solana": "0.0.1", - "@wormhole-foundation/sdk-base": "^0.10.9", - "@wormhole-foundation/sdk-definitions": "^0.10.9", - "@wormhole-foundation/sdk-solana": "^0.10.9" + "@wormhole-foundation/sdk-base": "^1.4.4", + "@wormhole-foundation/sdk-definitions": "^1.4.4", + "@wormhole-foundation/sdk-solana": "^1.4.4" } }, "solver/node_modules/@solana/spl-token": { @@ -4568,8 +4574,8 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "@wormhole-foundation/sdk-base": "^0.10.9", - "@wormhole-foundation/sdk-definitions": "^0.10.9" + "@wormhole-foundation/sdk-base": "^1.4.4", + "@wormhole-foundation/sdk-definitions": "^1.4.4" }, "devDependencies": { "@types/chai": "^4.3.4", diff --git a/solana/package.json b/solana/package.json index 1f2feb981..5e4b5190c 100644 --- a/solana/package.json +++ b/solana/package.json @@ -37,11 +37,11 @@ "@solana/web3.js": "^1.95.3", "@types/node-fetch": "^2.6.11", "@wormhole-foundation/example-liquidity-layer-definitions": "0.0.1", - "@wormhole-foundation/sdk-base": "^0.10.9", - "@wormhole-foundation/sdk-definitions": "^0.10.9", - "@wormhole-foundation/sdk-evm": "^0.10.9", - "@wormhole-foundation/sdk-solana": "^0.10.9", - "@wormhole-foundation/sdk-solana-core": "^0.10.9", + "@wormhole-foundation/sdk-base": "^1.4.4", + "@wormhole-foundation/sdk-definitions": "^1.4.4", + "@wormhole-foundation/sdk-evm": "^1.4.4", + "@wormhole-foundation/sdk-solana": "^1.4.4", + "@wormhole-foundation/sdk-solana-core": "^1.4.4", "anchor-0.29.0": "npm:@coral-xyz/anchor@^0.29.0", "bn.js": "^5.2.1", "dotenv": "^16.4.1", diff --git a/solver/package.json b/solver/package.json index 5c7803bbf..41826013c 100644 --- a/solver/package.json +++ b/solver/package.json @@ -16,8 +16,8 @@ "@solana/spl-token": "^0.4.6", "@wormhole-foundation/example-liquidity-layer-evm": "0.0.1", "@wormhole-foundation/example-liquidity-layer-solana": "0.0.1", - "@wormhole-foundation/sdk-base": "^0.10.9", - "@wormhole-foundation/sdk-definitions": "^0.10.9", - "@wormhole-foundation/sdk-solana": "^0.10.9" + "@wormhole-foundation/sdk-base": "^1.4.4", + "@wormhole-foundation/sdk-definitions": "^1.4.4", + "@wormhole-foundation/sdk-solana": "^1.4.4" } } diff --git a/universal/ts/package.json b/universal/ts/package.json index 12a4457e9..3db63701c 100644 --- a/universal/ts/package.json +++ b/universal/ts/package.json @@ -19,8 +19,8 @@ "clean": "rm -rf node_modules && rm -rf dist" }, "dependencies": { - "@wormhole-foundation/sdk-base": "^0.10.9", - "@wormhole-foundation/sdk-definitions": "^0.10.9" + "@wormhole-foundation/sdk-base": "^1.4.4", + "@wormhole-foundation/sdk-definitions": "^1.4.4" }, "devDependencies": { "@types/chai": "^4.3.4", diff --git a/universal/ts/src/payloads.ts b/universal/ts/src/payloads.ts index 26c7ae054..aec107b83 100644 --- a/universal/ts/src/payloads.ts +++ b/universal/ts/src/payloads.ts @@ -1,7 +1,7 @@ import { Layout, LayoutToType, - NamedLayoutItem, + // NamedLayoutItem, RoArray, column, constMap, @@ -60,14 +60,14 @@ const switchCase =

(p: P) => // prettier-ignore export const payloadLayoutSwitch = { - name: "data", + // name: "data", binary: "switch", idSize: 1, layouts: [ - switchCase("Fill"), + switchCase("Fill"), switchCase("SlowOrderResponse") ], -} as const satisfies NamedLayoutItem; +} as const satisfies Layout; export type Fill = PayloadType<"Fill">; export type SlowOrderResponse = PayloadType<"SlowOrderResponse">;