|
1 | 1 | import * as anchor from "@coral-xyz/anchor"; |
2 | 2 | import * as crypto from "crypto"; |
3 | 3 | import { BN } from "@coral-xyz/anchor"; |
4 | | -import { Keypair, PublicKey } from "@solana/web3.js"; |
| 4 | +import { |
| 5 | + AddressLookupTableProgram, |
| 6 | + ComputeBudgetProgram, |
| 7 | + Keypair, |
| 8 | + PublicKey, |
| 9 | + TransactionMessage, |
| 10 | + VersionedTransaction, |
| 11 | +} from "@solana/web3.js"; |
5 | 12 | import { assert } from "chai"; |
6 | 13 | import { common } from "./SvmSpoke.common"; |
7 | 14 | import { MerkleTree } from "@uma/common/dist/MerkleTree"; |
@@ -612,7 +619,10 @@ describe("svm_spoke.bundle", () => { |
612 | 619 | it("Execute Max Refunds", async () => { |
613 | 620 | const relayerRefundLeaves: RelayerRefundLeafType[] = []; |
614 | 621 |
|
615 | | - const numberOfRefunds = 5; |
| 622 | + // Higher refund count hits message size limit due to refund accounts also being present in calldata. This could be |
| 623 | + // resolved by feeding calldata from a buffer account. |
| 624 | + const numberOfRefunds = 21; |
| 625 | + const maxExtendedAccounts = 30; // Maximum number of accounts that can be added to ALT in a single transaction. |
616 | 626 |
|
617 | 627 | const refundAccounts: anchor.web3.PublicKey[] = []; |
618 | 628 | const refundAmounts: BN[] = []; |
@@ -655,25 +665,95 @@ describe("svm_spoke.bundle", () => { |
655 | 665 | .accounts({ state, rootBundle, signer: owner }) |
656 | 666 | .rpc(); |
657 | 667 |
|
658 | | - const remainingAccounts = refundAccounts.map((account) => ({ pubkey: account, isWritable: true, isSigner: false })); |
659 | | - |
660 | 668 | // Verify valid leaf |
661 | 669 | const proofAsNumbers = proof.map((p) => Array.from(p)); |
662 | 670 |
|
663 | | - await program.methods |
| 671 | + // We will be using Address Lookup Table (ALT), so to test maximum refunds we better add, not only refund accounts, |
| 672 | + // but also all static accounts. |
| 673 | + const staticAccounts = { |
| 674 | + state: state, |
| 675 | + rootBundle: rootBundle, |
| 676 | + signer: owner, |
| 677 | + vault: vault, |
| 678 | + tokenProgram: TOKEN_PROGRAM_ID, |
| 679 | + mint: mint, |
| 680 | + transferLiability, |
| 681 | + systemProgram: anchor.web3.SystemProgram.programId, |
| 682 | + // Appended by Acnhor `event_cpi` macro: |
| 683 | + eventAuthority: PublicKey.findProgramAddressSync([Buffer.from("__event_authority")], program.programId)[0], |
| 684 | + program: program.programId, |
| 685 | + }; |
| 686 | + |
| 687 | + const remainingAccounts = refundAccounts.map((account) => ({ pubkey: account, isWritable: true, isSigner: false })); |
| 688 | + |
| 689 | + // Consolidate all accounts (static and remaining) into a single array for the ALT. |
| 690 | + const allAccounts = [...Object.values(staticAccounts), ...refundAccounts]; |
| 691 | + |
| 692 | + // Create instructions for creating and extending the ALT. |
| 693 | + const [lookupTableInstruction, lookupTableAddress] = await AddressLookupTableProgram.createLookupTable({ |
| 694 | + authority: payer.publicKey, |
| 695 | + payer: payer.publicKey, |
| 696 | + recentSlot: await connection.getSlot(), |
| 697 | + }); |
| 698 | + |
| 699 | + // Submit the ALT creation transaction |
| 700 | + await anchor.web3.sendAndConfirmTransaction( |
| 701 | + connection, |
| 702 | + new anchor.web3.Transaction().add(lookupTableInstruction), |
| 703 | + [payer], |
| 704 | + { |
| 705 | + skipPreflight: true, // Avoids recent slot mismatch in simulation. |
| 706 | + } |
| 707 | + ); |
| 708 | + |
| 709 | + // Extend the ALT with all accounts making sure not to exceed the maximum number of accounts per transaction. |
| 710 | + for (let i = 0; i < allAccounts.length; i += maxExtendedAccounts) { |
| 711 | + const extendInstruction = AddressLookupTableProgram.extendLookupTable({ |
| 712 | + lookupTable: lookupTableAddress, |
| 713 | + authority: payer.publicKey, |
| 714 | + payer: payer.publicKey, |
| 715 | + addresses: allAccounts.slice(i, i + maxExtendedAccounts), |
| 716 | + }); |
| 717 | + |
| 718 | + await anchor.web3.sendAndConfirmTransaction( |
| 719 | + connection, |
| 720 | + new anchor.web3.Transaction().add(extendInstruction), |
| 721 | + [payer], |
| 722 | + { |
| 723 | + skipPreflight: true, // Avoids recent slot mismatch in simulation. |
| 724 | + } |
| 725 | + ); |
| 726 | + } |
| 727 | + |
| 728 | + // Avoids invalid ALT index as ALT might not be active yet on the following tx. |
| 729 | + await new Promise((resolve) => setTimeout(resolve, 500)); |
| 730 | + |
| 731 | + // Fetch the AddressLookupTableAccount |
| 732 | + const lookupTableAccount = (await connection.getAddressLookupTable(lookupTableAddress)).value; |
| 733 | + assert(lookupTableAccount !== null, "AddressLookupTableAccount not fetched"); |
| 734 | + |
| 735 | + // Build the instruction to execute relayer refund leaf |
| 736 | + const executeInstruction = await program.methods |
664 | 737 | .executeRelayerRefundLeaf(stateAccountData.rootBundleId, leaf, proofAsNumbers) |
665 | | - .accounts({ |
666 | | - state: state, |
667 | | - rootBundle: rootBundle, |
668 | | - signer: owner, |
669 | | - vault: vault, |
670 | | - tokenProgram: TOKEN_PROGRAM_ID, |
671 | | - mint: mint, |
672 | | - transferLiability, |
673 | | - systemProgram: anchor.web3.SystemProgram.programId, |
674 | | - }) |
| 738 | + .accounts(staticAccounts) |
675 | 739 | .remainingAccounts(remainingAccounts) |
676 | | - .rpc(); |
| 740 | + .instruction(); |
| 741 | + |
| 742 | + // Build the instruction to increase the CU limit as the default 200k is not sufficient. |
| 743 | + const computeBudgetInstruction = ComputeBudgetProgram.setComputeUnitLimit({ units: 500_000 }); |
| 744 | + |
| 745 | + // Create the versioned transaction |
| 746 | + const versionedTx = new VersionedTransaction( |
| 747 | + new TransactionMessage({ |
| 748 | + payerKey: payer.publicKey, |
| 749 | + recentBlockhash: (await connection.getLatestBlockhash()).blockhash, |
| 750 | + instructions: [computeBudgetInstruction, executeInstruction], |
| 751 | + }).compileToV0Message([lookupTableAccount]) |
| 752 | + ); |
| 753 | + |
| 754 | + // Sign and submit the versioned transaction. |
| 755 | + versionedTx.sign([payer]); |
| 756 | + await connection.sendTransaction(versionedTx); |
677 | 757 | }); |
678 | 758 |
|
679 | 759 | it("Increments pending amount to HubPool", async () => { |
|
0 commit comments