@pythnetwork/pyth-solana-receiver 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -0
- package/lib/PythSolanaReceiver.d.ts +168 -15
- package/lib/PythSolanaReceiver.d.ts.map +1 -1
- package/lib/PythSolanaReceiver.js +206 -37
- package/lib/address.d.ts +25 -3
- package/lib/address.d.ts.map +1 -1
- package/lib/address.js +29 -7
- package/lib/compute_budget.d.ts +9 -0
- package/lib/compute_budget.d.ts.map +1 -1
- package/lib/compute_budget.js +9 -0
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/vaa.d.ts +50 -9
- package/lib/vaa.d.ts.map +1 -1
- package/lib/vaa.js +51 -7
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Pyth Solana Receiver JS SDK
|
|
2
|
+
|
|
3
|
+
This is a Javascript SDK to interact with the Pyth Solana Receiver contract whose code lives [here](/target_chains/solana).
|
|
4
|
+
|
|
5
|
+
## Pull model
|
|
6
|
+
|
|
7
|
+
The Pyth Solana Receiver allows users to consume Pyth price updates on a pull basis. This means that the user is responsible for submitting the price data on-chain whenever they want to interact with an app that requires a price update.
|
|
8
|
+
|
|
9
|
+
Price updates get posted into price update accounts, owned by the Receiver contract. Once an update has been posted to a price update account, it can be used by anyone by simply passing the price update account as one of the accounts in a Solana instruction.
|
|
10
|
+
Price update accounts can be closed by whoever wrote them to recover the rent.
|
|
11
|
+
|
|
12
|
+
## Example use
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { Connection, PublicKey } from "@solana/web3.js";
|
|
16
|
+
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
|
17
|
+
import { PythSolanaReceiver } from "@pythnetwork/pyth-solana-receiver";
|
|
18
|
+
import { MyFirstPythApp, IDL } from "./idl/my_first_pyth_app";
|
|
19
|
+
|
|
20
|
+
const SOL_PRICE_FEED_ID =
|
|
21
|
+
"0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d";
|
|
22
|
+
const ETH_PRICE_FEED_ID =
|
|
23
|
+
"0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace";
|
|
24
|
+
|
|
25
|
+
const priceServiceConnection = new PriceServiceConnection(
|
|
26
|
+
"https://hermes.pyth.network/",
|
|
27
|
+
{ priceFeedRequestConfig: { binary: true } }
|
|
28
|
+
);
|
|
29
|
+
const priceUpdateData = await priceServiceConnection.getLatestVaas([
|
|
30
|
+
SOL_PRICE_FEED_ID,
|
|
31
|
+
ETH_PRICE_FEED_ID,
|
|
32
|
+
]); // Fetch off-chain price update data
|
|
33
|
+
|
|
34
|
+
const myFirstPythApp = new Program<MyFirstPythApp>(
|
|
35
|
+
IDL as MyFirstPythApp,
|
|
36
|
+
MY_FIRST_PYTH_APP_PROGRAM_ID,
|
|
37
|
+
{}
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const transactionBuilder = pythSolanaReceiver.newTransactionBuilder({});
|
|
41
|
+
await transactionBuilder.addPostPriceUpdates(priceUpdateData);
|
|
42
|
+
await transactionBuilder.addPriceConsumerInstructions(
|
|
43
|
+
async (
|
|
44
|
+
getPriceUpdateAccount: (priceFeedId: string) => PublicKey
|
|
45
|
+
): Promise<InstructionWithEphemeralSigners[]> => {
|
|
46
|
+
return [
|
|
47
|
+
{
|
|
48
|
+
instruction: await myFirstPythApp.methods
|
|
49
|
+
.consume()
|
|
50
|
+
.accounts({
|
|
51
|
+
solPriceUpdate: getPriceUpdateAccount(SOL_PRICE_FEED_ID),
|
|
52
|
+
ethPriceUpdate: getPriceUpdateAccount(ETH_PRICE_FEED_ID),
|
|
53
|
+
})
|
|
54
|
+
.instruction(),
|
|
55
|
+
signers: [],
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
await pythSolanaReceiver.provider.sendAll(
|
|
61
|
+
await transactionBuilder.buildVersionedTransactions({
|
|
62
|
+
computeUnitPriceMicroLamports: 1000000,
|
|
63
|
+
})
|
|
64
|
+
);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Alternatively you can use the instruction builder methods from `PythSolanaReceiver` :
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { PublicKey } from "@solana/web3.js";
|
|
71
|
+
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
|
72
|
+
import { PythSolanaReceiver } from "@pythnetwork/pyth-solana-receiver";
|
|
73
|
+
import { MyFirstPythApp, IDL } from "./idl/my_first_pyth_app";
|
|
74
|
+
|
|
75
|
+
const SOL_PRICE_FEED_ID =
|
|
76
|
+
"0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d";
|
|
77
|
+
const ETH_PRICE_FEED_ID =
|
|
78
|
+
"0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace";
|
|
79
|
+
|
|
80
|
+
const priceServiceConnection = new PriceServiceConnection(
|
|
81
|
+
"https://hermes.pyth.network/",
|
|
82
|
+
{ priceFeedRequestConfig: { binary: true } }
|
|
83
|
+
);
|
|
84
|
+
const priceUpdateData = await priceServiceConnection.getLatestVaas([
|
|
85
|
+
SOL_PRICE_FEED_ID,
|
|
86
|
+
ETH_PRICE_FEED_ID,
|
|
87
|
+
]); // Fetch off-chain price update data
|
|
88
|
+
|
|
89
|
+
const pythSolanaReceiver = new PythSolanaReceiver({ connection, wallet });
|
|
90
|
+
const { postInstructions, closeInstructions, priceFeedIdToPriceUpdateAccount } =
|
|
91
|
+
await pythSolanaReceiver.buildPostPriceUpdateInstructions(priceUpdateData); // Get instructions to post the price update data and to close the accounts later
|
|
92
|
+
|
|
93
|
+
const myFirstPythApp = new Program<MyFirstPythApp>(
|
|
94
|
+
IDL as MyFirstPythApp,
|
|
95
|
+
MY_FIRST_PYTH_APP_PROGRAM_ID,
|
|
96
|
+
{}
|
|
97
|
+
);
|
|
98
|
+
const consumerInstruction: InstructionWithEphemeralSigners = {
|
|
99
|
+
instruction: await myFirstPythApp.methods
|
|
100
|
+
.consume()
|
|
101
|
+
.accounts({
|
|
102
|
+
solPriceUpdate: priceFeedIdToPriceUpdateAccount[SOL_PRICE_FEED_ID],
|
|
103
|
+
ethPriceUpdate: priceFeedIdToPriceUpdateAccount[ETH_PRICE_FEED_ID],
|
|
104
|
+
})
|
|
105
|
+
.instruction(),
|
|
106
|
+
signers: [],
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const transactions = pythSolanaReceiver.batchIntoVersionedTransactions(
|
|
110
|
+
[...postInstructions, consumerInstruction, ...closeInstructions],
|
|
111
|
+
{ computeUnitPriceMicroLamports: 1000000 }
|
|
112
|
+
); // Put all the instructions together
|
|
113
|
+
await pythSolanaReceiver.provider.sendAll(transactions);
|
|
114
|
+
```
|
|
@@ -1,13 +1,130 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { AnchorProvider, Program } from "@coral-xyz/anchor";
|
|
3
|
-
import { Connection, Signer, VersionedTransaction } from "@solana/web3.js";
|
|
3
|
+
import { Connection, Signer, Transaction, VersionedTransaction } from "@solana/web3.js";
|
|
4
4
|
import { PythSolanaReceiver as PythSolanaReceiverProgram } from "./idl/pyth_solana_receiver";
|
|
5
5
|
import { WormholeCoreBridgeSolana } from "./idl/wormhole_core_bridge_solana";
|
|
6
6
|
import { PublicKey } from "@solana/web3.js";
|
|
7
7
|
import { Wallet } from "@coral-xyz/anchor/dist/cjs/provider";
|
|
8
|
-
import { InstructionWithEphemeralSigners } from "@pythnetwork/solana-utils";
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import { TransactionBuilder, InstructionWithEphemeralSigners, PriorityFeeConfig } from "@pythnetwork/solana-utils";
|
|
9
|
+
/**
|
|
10
|
+
* Configuration for the PythTransactionBuilder
|
|
11
|
+
* @property closeUpdateAccounts (default: true) if true, the builder will add instructions to close the price update accounts and the encoded vaa accounts to recover the rent
|
|
12
|
+
*/
|
|
13
|
+
export type PythTransactionBuilderConfig = {
|
|
14
|
+
closeUpdateAccounts?: boolean;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A builder class to build transactions that:
|
|
18
|
+
* - Post price updates (fully or partially verified)
|
|
19
|
+
* - Consume price updates in a consumer program
|
|
20
|
+
* - (Optionally) Close price update and encoded vaa accounts to recover the rent (`closeUpdateAccounts` in `PythTransactionBuilderConfig`)
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const priceUpdateData = await priceServiceConnection.getLatestVaas([
|
|
25
|
+
* SOL_PRICE_FEED_ID,
|
|
26
|
+
* ETH_PRICE_FEED_ID,
|
|
27
|
+
* ]);
|
|
28
|
+
*
|
|
29
|
+
* const transactionBuilder = pythSolanaReceiver.newTransactionBuilder({});
|
|
30
|
+
* await transactionBuilder.addPostPriceUpdates(priceUpdateData);
|
|
31
|
+
* await transactionBuilder.addPriceConsumerInstructions(...)
|
|
32
|
+
*
|
|
33
|
+
* await pythSolanaReceiver.provider.sendAll(await transactionBuilder.buildVersionedTransactions({computeUnitPriceMicroLamports:1000000}))
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare class PythTransactionBuilder extends TransactionBuilder {
|
|
37
|
+
readonly pythSolanaReceiver: PythSolanaReceiver;
|
|
38
|
+
readonly closeInstructions: InstructionWithEphemeralSigners[];
|
|
39
|
+
readonly priceFeedIdToPriceUpdateAccount: Record<string, PublicKey>;
|
|
40
|
+
readonly closeUpdateAccounts: boolean;
|
|
41
|
+
constructor(pythSolanaReceiver: PythSolanaReceiver, config: PythTransactionBuilderConfig);
|
|
42
|
+
/**
|
|
43
|
+
* Add instructions to post price updates to the builder.
|
|
44
|
+
*
|
|
45
|
+
* @param priceUpdateDataArray the output of the `@pythnetwork/price-service-client`'s `PriceServiceConnection.getLatestVaas`. This is an array of verifiable price updates.
|
|
46
|
+
*/
|
|
47
|
+
addPostPriceUpdates(priceUpdateDataArray: string[]): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Add instructions to post partially verified price updates to the builder.
|
|
50
|
+
*
|
|
51
|
+
* @param priceUpdateDataArray the output of the `@pythnetwork/price-service-client`'s `PriceServiceConnection.getLatestVaas`. This is an array of verifiable price updates.
|
|
52
|
+
*
|
|
53
|
+
* Partially verified price updates are price updates where not all the guardian signatures have been verified. By default this methods checks `DEFAULT_REDUCED_GUARDIAN_SET_SIZE` signatures when posting the VAA.
|
|
54
|
+
* If you are a on-chain program developer, make sure you understand the risks of consuming partially verified price updates here: {@link https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/solana/pyth_solana_receiver_state/src/price_update.rs}.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const priceUpdateData = await priceServiceConnection.getLatestVaas([
|
|
59
|
+
* SOL_PRICE_FEED_ID,
|
|
60
|
+
* ETH_PRICE_FEED_ID,
|
|
61
|
+
* ]);
|
|
62
|
+
*
|
|
63
|
+
* const transactionBuilder = pythSolanaReceiver.newTransactionBuilder({});
|
|
64
|
+
* await transactionBuilder.addPostPartiallyVerifiedPriceUpdates(priceUpdateData);
|
|
65
|
+
* await transactionBuilder.addPriceConsumerInstructions(...)
|
|
66
|
+
* ...
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
addPostPartiallyVerifiedPriceUpdates(priceUpdateDataArray: string[]): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Add instructions that consume price updates to the builder.
|
|
72
|
+
*
|
|
73
|
+
* @param getInstructions a function that given a mapping of price feed IDs to price update accounts, generates a series of instructions. Price updates get posted to ephemeral accounts and this function allows the user to indicate which accounts in their instruction need to be "replaced" with each price update account.
|
|
74
|
+
* If multiple price updates for the same price feed id are posted with the same builder, the account corresponding to the last update to get posted will be used.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* ...
|
|
79
|
+
* await transactionBuilder.addPostPriceUpdates(priceUpdateData);
|
|
80
|
+
* await transactionBuilder.addPriceConsumerInstructions(
|
|
81
|
+
* async (
|
|
82
|
+
* getPriceUpdateAccount: ( priceFeedId: string) => PublicKey
|
|
83
|
+
* ): Promise<InstructionWithEphemeralSigners[]> => {
|
|
84
|
+
* return [
|
|
85
|
+
* {
|
|
86
|
+
* instruction: await myFirstPythApp.methods
|
|
87
|
+
* .consume()
|
|
88
|
+
* .accounts({
|
|
89
|
+
* solPriceUpdate: getPriceUpdateAccount(SOL_PRICE_FEED_ID),
|
|
90
|
+
* ethPriceUpdate: getPriceUpdateAccount(ETH_PRICE_FEED_ID),
|
|
91
|
+
* })
|
|
92
|
+
* .instruction(),
|
|
93
|
+
* signers: [],
|
|
94
|
+
* },
|
|
95
|
+
* ];
|
|
96
|
+
* }
|
|
97
|
+
* );
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
addPriceConsumerInstructions(getInstructions: (getPriceUpdateAccount: (priceFeedId: string) => PublicKey) => Promise<InstructionWithEphemeralSigners[]>): Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* Returns all the added instructions batched into versioned transactions, plus for each transaction the ephemeral signers that need to sign it
|
|
103
|
+
*/
|
|
104
|
+
buildVersionedTransactions(args: PriorityFeeConfig): Promise<{
|
|
105
|
+
tx: VersionedTransaction;
|
|
106
|
+
signers: Signer[];
|
|
107
|
+
}[]>;
|
|
108
|
+
/**
|
|
109
|
+
* Returns all the added instructions batched into transactions, plus for each transaction the ephemeral signers that need to sign it
|
|
110
|
+
*/
|
|
111
|
+
buildLegacyTransactions(args: PriorityFeeConfig): {
|
|
112
|
+
tx: Transaction;
|
|
113
|
+
signers: Signer[];
|
|
114
|
+
}[];
|
|
115
|
+
/**
|
|
116
|
+
* This method is used to retrieve the address of the price update account where the price update for a given price feed id will be posted.
|
|
117
|
+
* If multiple price updates for the same price feed id will be posted with the same builder, the address of the account corresponding to the last update to get posted will be returned.
|
|
118
|
+
* */
|
|
119
|
+
getPriceUpdateAccount(priceFeedId: string): PublicKey;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* A class to interact with the Pyth Solana Receiver program.
|
|
123
|
+
*
|
|
124
|
+
* This class provides helpful methods to build instructions to interact with the Pyth Solana Receiver program:
|
|
125
|
+
* - Post price updates (fully or partially verified)
|
|
126
|
+
* - Close price update and encoded vaa accounts to recover rent
|
|
127
|
+
*/
|
|
11
128
|
export declare class PythSolanaReceiver {
|
|
12
129
|
readonly connection: Connection;
|
|
13
130
|
readonly wallet: Wallet;
|
|
@@ -20,30 +137,66 @@ export declare class PythSolanaReceiver {
|
|
|
20
137
|
wormholeProgramId?: PublicKey;
|
|
21
138
|
receiverProgramId?: PublicKey;
|
|
22
139
|
});
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Get a new transaction builder to build transactions that interact with the Pyth Solana Receiver program and consume price updates
|
|
142
|
+
*/
|
|
143
|
+
newTransactionBuilder(config: PythTransactionBuilderConfig): PythTransactionBuilder;
|
|
144
|
+
/**
|
|
145
|
+
* Build a series of helper instructions that post price updates to the Pyth Solana Receiver program and another series to close the price update accounts.
|
|
146
|
+
*
|
|
147
|
+
* This function uses partially verified price updates. Partially verified price updates are price updates where not all the guardian signatures have been verified. By default this methods checks `DEFAULT_REDUCED_GUARDIAN_SET_SIZE` signatures when posting the VAA.
|
|
148
|
+
* If you are a on-chain program developer, make sure you understand the risks of consuming partially verified price updates here: {@link https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/solana/pyth_solana_receiver_state/src/price_update.rs}.
|
|
149
|
+
*
|
|
150
|
+
* @param priceUpdateDataArray the output of the `@pythnetwork/price-service-client`'s `PriceServiceConnection.getLatestVaas`. This is an array of verifiable price updates.
|
|
151
|
+
* @returns `postInstructions`: the instructions to post the price updates, these should be called before consuming the price updates
|
|
152
|
+
* @returns `priceFeedIdToPriceUpdateAccount`: this is a map of price feed IDs to Solana address. Given a price feed ID, you can use this map to find the account where `postInstructions` will post the price update.
|
|
153
|
+
* @returns `closeInstructions`: the instructions to close the price update accounts, these should be called after consuming the price updates
|
|
154
|
+
*/
|
|
31
155
|
buildPostPriceUpdateAtomicInstructions(priceUpdateDataArray: string[]): Promise<{
|
|
32
156
|
postInstructions: InstructionWithEphemeralSigners[];
|
|
33
157
|
priceFeedIdToPriceUpdateAccount: Record<string, PublicKey>;
|
|
34
|
-
|
|
158
|
+
closeInstructions: InstructionWithEphemeralSigners[];
|
|
35
159
|
}>;
|
|
160
|
+
/**
|
|
161
|
+
* Build a series of helper instructions that post a VAA in an encoded VAA account. This function is bespoke for posting Pyth VAAs and might not work for other usecases.
|
|
162
|
+
*
|
|
163
|
+
* @param vaa a Wormhole VAA
|
|
164
|
+
* @returns `postInstructions`: the instructions to post the VAA
|
|
165
|
+
* @returns `encodedVaaAddress`: the address of the encoded VAA account where the VAA will be posted
|
|
166
|
+
* @returns `closeInstructions`: the instructions to close the encoded VAA account
|
|
167
|
+
*/
|
|
36
168
|
buildPostEncodedVaaInstructions(vaa: Buffer): Promise<{
|
|
37
169
|
postInstructions: InstructionWithEphemeralSigners[];
|
|
38
170
|
encodedVaaAddress: PublicKey;
|
|
39
|
-
|
|
171
|
+
closeInstructions: InstructionWithEphemeralSigners[];
|
|
40
172
|
}>;
|
|
173
|
+
/**
|
|
174
|
+
* Build a series of helper instructions that post price updates to the Pyth Solana Receiver program and another series to close the encoded vaa accounts and the price update accounts.
|
|
175
|
+
*
|
|
176
|
+
* @param priceUpdateDataArray the output of the `@pythnetwork/price-service-client`'s `PriceServiceConnection.getLatestVaas`. This is an array of verifiable price updates.
|
|
177
|
+
* @returns `postInstructions`: the instructions to post the price updates, these should be called before consuming the price updates
|
|
178
|
+
* @returns `priceFeedIdToPriceUpdateAccount`: this is a map of price feed IDs to Solana address. Given a price feed ID, you can use this map to find the account where `postInstructions` will post the price update.
|
|
179
|
+
* @returns `closeInstructions`: the instructions to close the price update accounts, these should be called after consuming the price updates
|
|
180
|
+
*/
|
|
41
181
|
buildPostPriceUpdateInstructions(priceUpdateDataArray: string[]): Promise<{
|
|
42
182
|
postInstructions: InstructionWithEphemeralSigners[];
|
|
43
183
|
priceFeedIdToPriceUpdateAccount: Record<string, PublicKey>;
|
|
44
|
-
|
|
184
|
+
closeInstructions: InstructionWithEphemeralSigners[];
|
|
45
185
|
}>;
|
|
186
|
+
/**
|
|
187
|
+
* Build an instruction to close an encoded VAA account, recovering the rent.
|
|
188
|
+
*/
|
|
46
189
|
buildCloseEncodedVaaInstruction(encodedVaa: PublicKey): Promise<InstructionWithEphemeralSigners>;
|
|
190
|
+
/**
|
|
191
|
+
* Build an instruction to close a price update account, recovering the rent.
|
|
192
|
+
*/
|
|
47
193
|
buildClosePriceUpdateInstruction(priceUpdateAccount: PublicKey): Promise<InstructionWithEphemeralSigners>;
|
|
194
|
+
/**
|
|
195
|
+
* Returns a set of versioned transactions that contain the provided instructions in the same order and with efficient batching
|
|
196
|
+
*/
|
|
197
|
+
batchIntoVersionedTransactions(instructions: InstructionWithEphemeralSigners[], priorityFeeConfig: PriorityFeeConfig): Promise<{
|
|
198
|
+
tx: VersionedTransaction;
|
|
199
|
+
signers: Signer[];
|
|
200
|
+
}[]>;
|
|
48
201
|
}
|
|
49
202
|
//# sourceMappingURL=PythSolanaReceiver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PythSolanaReceiver.d.ts","sourceRoot":"","sources":["../src/PythSolanaReceiver.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,
|
|
1
|
+
{"version":3,"file":"PythSolanaReceiver.d.ts","sourceRoot":"","sources":["../src/PythSolanaReceiver.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PythSolanaReceiver = exports.
|
|
3
|
+
exports.PythSolanaReceiver = exports.PythTransactionBuilder = void 0;
|
|
4
4
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
5
5
|
const pyth_solana_receiver_1 = require("./idl/pyth_solana_receiver");
|
|
6
6
|
const wormhole_core_bridge_solana_1 = require("./idl/wormhole_core_bridge_solana");
|
|
@@ -10,7 +10,147 @@ const price_service_sdk_1 = require("@pythnetwork/price-service-sdk");
|
|
|
10
10
|
const compute_budget_1 = require("./compute_budget");
|
|
11
11
|
const vaa_1 = require("./vaa");
|
|
12
12
|
const solana_utils_1 = require("@pythnetwork/solana-utils");
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* A builder class to build transactions that:
|
|
15
|
+
* - Post price updates (fully or partially verified)
|
|
16
|
+
* - Consume price updates in a consumer program
|
|
17
|
+
* - (Optionally) Close price update and encoded vaa accounts to recover the rent (`closeUpdateAccounts` in `PythTransactionBuilderConfig`)
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const priceUpdateData = await priceServiceConnection.getLatestVaas([
|
|
22
|
+
* SOL_PRICE_FEED_ID,
|
|
23
|
+
* ETH_PRICE_FEED_ID,
|
|
24
|
+
* ]);
|
|
25
|
+
*
|
|
26
|
+
* const transactionBuilder = pythSolanaReceiver.newTransactionBuilder({});
|
|
27
|
+
* await transactionBuilder.addPostPriceUpdates(priceUpdateData);
|
|
28
|
+
* await transactionBuilder.addPriceConsumerInstructions(...)
|
|
29
|
+
*
|
|
30
|
+
* await pythSolanaReceiver.provider.sendAll(await transactionBuilder.buildVersionedTransactions({computeUnitPriceMicroLamports:1000000}))
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
class PythTransactionBuilder extends solana_utils_1.TransactionBuilder {
|
|
34
|
+
pythSolanaReceiver;
|
|
35
|
+
closeInstructions;
|
|
36
|
+
priceFeedIdToPriceUpdateAccount;
|
|
37
|
+
closeUpdateAccounts;
|
|
38
|
+
constructor(pythSolanaReceiver, config) {
|
|
39
|
+
super(pythSolanaReceiver.wallet.publicKey, pythSolanaReceiver.connection);
|
|
40
|
+
this.pythSolanaReceiver = pythSolanaReceiver;
|
|
41
|
+
this.closeInstructions = [];
|
|
42
|
+
this.priceFeedIdToPriceUpdateAccount = {};
|
|
43
|
+
this.closeUpdateAccounts = config.closeUpdateAccounts ?? true;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Add instructions to post price updates to the builder.
|
|
47
|
+
*
|
|
48
|
+
* @param priceUpdateDataArray the output of the `@pythnetwork/price-service-client`'s `PriceServiceConnection.getLatestVaas`. This is an array of verifiable price updates.
|
|
49
|
+
*/
|
|
50
|
+
async addPostPriceUpdates(priceUpdateDataArray) {
|
|
51
|
+
const { postInstructions, priceFeedIdToPriceUpdateAccount, closeInstructions, } = await this.pythSolanaReceiver.buildPostPriceUpdateInstructions(priceUpdateDataArray);
|
|
52
|
+
this.closeInstructions.push(...closeInstructions);
|
|
53
|
+
Object.assign(this.priceFeedIdToPriceUpdateAccount, priceFeedIdToPriceUpdateAccount);
|
|
54
|
+
this.addInstructions(postInstructions);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Add instructions to post partially verified price updates to the builder.
|
|
58
|
+
*
|
|
59
|
+
* @param priceUpdateDataArray the output of the `@pythnetwork/price-service-client`'s `PriceServiceConnection.getLatestVaas`. This is an array of verifiable price updates.
|
|
60
|
+
*
|
|
61
|
+
* Partially verified price updates are price updates where not all the guardian signatures have been verified. By default this methods checks `DEFAULT_REDUCED_GUARDIAN_SET_SIZE` signatures when posting the VAA.
|
|
62
|
+
* If you are a on-chain program developer, make sure you understand the risks of consuming partially verified price updates here: {@link https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/solana/pyth_solana_receiver_state/src/price_update.rs}.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const priceUpdateData = await priceServiceConnection.getLatestVaas([
|
|
67
|
+
* SOL_PRICE_FEED_ID,
|
|
68
|
+
* ETH_PRICE_FEED_ID,
|
|
69
|
+
* ]);
|
|
70
|
+
*
|
|
71
|
+
* const transactionBuilder = pythSolanaReceiver.newTransactionBuilder({});
|
|
72
|
+
* await transactionBuilder.addPostPartiallyVerifiedPriceUpdates(priceUpdateData);
|
|
73
|
+
* await transactionBuilder.addPriceConsumerInstructions(...)
|
|
74
|
+
* ...
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
async addPostPartiallyVerifiedPriceUpdates(priceUpdateDataArray) {
|
|
78
|
+
const { postInstructions, priceFeedIdToPriceUpdateAccount, closeInstructions, } = await this.pythSolanaReceiver.buildPostPriceUpdateAtomicInstructions(priceUpdateDataArray);
|
|
79
|
+
this.closeInstructions.push(...closeInstructions);
|
|
80
|
+
Object.assign(this.priceFeedIdToPriceUpdateAccount, priceFeedIdToPriceUpdateAccount);
|
|
81
|
+
this.addInstructions(postInstructions);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Add instructions that consume price updates to the builder.
|
|
85
|
+
*
|
|
86
|
+
* @param getInstructions a function that given a mapping of price feed IDs to price update accounts, generates a series of instructions. Price updates get posted to ephemeral accounts and this function allows the user to indicate which accounts in their instruction need to be "replaced" with each price update account.
|
|
87
|
+
* If multiple price updates for the same price feed id are posted with the same builder, the account corresponding to the last update to get posted will be used.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* ...
|
|
92
|
+
* await transactionBuilder.addPostPriceUpdates(priceUpdateData);
|
|
93
|
+
* await transactionBuilder.addPriceConsumerInstructions(
|
|
94
|
+
* async (
|
|
95
|
+
* getPriceUpdateAccount: ( priceFeedId: string) => PublicKey
|
|
96
|
+
* ): Promise<InstructionWithEphemeralSigners[]> => {
|
|
97
|
+
* return [
|
|
98
|
+
* {
|
|
99
|
+
* instruction: await myFirstPythApp.methods
|
|
100
|
+
* .consume()
|
|
101
|
+
* .accounts({
|
|
102
|
+
* solPriceUpdate: getPriceUpdateAccount(SOL_PRICE_FEED_ID),
|
|
103
|
+
* ethPriceUpdate: getPriceUpdateAccount(ETH_PRICE_FEED_ID),
|
|
104
|
+
* })
|
|
105
|
+
* .instruction(),
|
|
106
|
+
* signers: [],
|
|
107
|
+
* },
|
|
108
|
+
* ];
|
|
109
|
+
* }
|
|
110
|
+
* );
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
async addPriceConsumerInstructions(getInstructions) {
|
|
114
|
+
this.addInstructions(await getInstructions(this.getPriceUpdateAccount.bind(this)));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Returns all the added instructions batched into versioned transactions, plus for each transaction the ephemeral signers that need to sign it
|
|
118
|
+
*/
|
|
119
|
+
async buildVersionedTransactions(args) {
|
|
120
|
+
if (this.closeUpdateAccounts) {
|
|
121
|
+
this.addInstructions(this.closeInstructions);
|
|
122
|
+
}
|
|
123
|
+
return super.buildVersionedTransactions(args);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Returns all the added instructions batched into transactions, plus for each transaction the ephemeral signers that need to sign it
|
|
127
|
+
*/
|
|
128
|
+
buildLegacyTransactions(args) {
|
|
129
|
+
if (this.closeUpdateAccounts) {
|
|
130
|
+
this.addInstructions(this.closeInstructions);
|
|
131
|
+
}
|
|
132
|
+
return super.buildLegacyTransactions(args);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* This method is used to retrieve the address of the price update account where the price update for a given price feed id will be posted.
|
|
136
|
+
* If multiple price updates for the same price feed id will be posted with the same builder, the address of the account corresponding to the last update to get posted will be returned.
|
|
137
|
+
* */
|
|
138
|
+
getPriceUpdateAccount(priceFeedId) {
|
|
139
|
+
const priceUpdateAccount = this.priceFeedIdToPriceUpdateAccount[priceFeedId];
|
|
140
|
+
if (!priceUpdateAccount) {
|
|
141
|
+
throw new Error(`No price update account found for the price feed ID ${priceFeedId}. Make sure to call addPostPriceUpdates or addPostPartiallyVerifiedPriceUpdates before calling this function.`);
|
|
142
|
+
}
|
|
143
|
+
return priceUpdateAccount;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
exports.PythTransactionBuilder = PythTransactionBuilder;
|
|
147
|
+
/**
|
|
148
|
+
* A class to interact with the Pyth Solana Receiver program.
|
|
149
|
+
*
|
|
150
|
+
* This class provides helpful methods to build instructions to interact with the Pyth Solana Receiver program:
|
|
151
|
+
* - Post price updates (fully or partially verified)
|
|
152
|
+
* - Close price update and encoded vaa accounts to recover rent
|
|
153
|
+
*/
|
|
14
154
|
class PythSolanaReceiver {
|
|
15
155
|
connection;
|
|
16
156
|
wallet;
|
|
@@ -26,26 +166,27 @@ class PythSolanaReceiver {
|
|
|
26
166
|
this.receiver = new anchor_1.Program(pyth_solana_receiver_1.IDL, receiverProgramId, this.provider);
|
|
27
167
|
this.wormhole = new anchor_1.Program(wormhole_core_bridge_solana_1.IDL, wormholeProgramId, this.provider);
|
|
28
168
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
...cleanupInstructions,
|
|
35
|
-
], priorityFeeConfig ?? {});
|
|
36
|
-
}
|
|
37
|
-
async withPartiallyVerifiedPriceUpdate(priceUpdateDataArray, getInstructions, priorityFeeConfig) {
|
|
38
|
-
const { postInstructions, priceFeedIdToPriceUpdateAccount, cleanupInstructions, } = await this.buildPostPriceUpdateAtomicInstructions(priceUpdateDataArray);
|
|
39
|
-
return solana_utils_1.TransactionBuilder.batchIntoVersionedTransactions(this.wallet.publicKey, this.connection, [
|
|
40
|
-
...postInstructions,
|
|
41
|
-
...(await getInstructions(priceFeedIdToPriceUpdateAccount)),
|
|
42
|
-
...cleanupInstructions,
|
|
43
|
-
], priorityFeeConfig ?? {});
|
|
169
|
+
/**
|
|
170
|
+
* Get a new transaction builder to build transactions that interact with the Pyth Solana Receiver program and consume price updates
|
|
171
|
+
*/
|
|
172
|
+
newTransactionBuilder(config) {
|
|
173
|
+
return new PythTransactionBuilder(this, config);
|
|
44
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Build a series of helper instructions that post price updates to the Pyth Solana Receiver program and another series to close the price update accounts.
|
|
177
|
+
*
|
|
178
|
+
* This function uses partially verified price updates. Partially verified price updates are price updates where not all the guardian signatures have been verified. By default this methods checks `DEFAULT_REDUCED_GUARDIAN_SET_SIZE` signatures when posting the VAA.
|
|
179
|
+
* If you are a on-chain program developer, make sure you understand the risks of consuming partially verified price updates here: {@link https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/solana/pyth_solana_receiver_state/src/price_update.rs}.
|
|
180
|
+
*
|
|
181
|
+
* @param priceUpdateDataArray the output of the `@pythnetwork/price-service-client`'s `PriceServiceConnection.getLatestVaas`. This is an array of verifiable price updates.
|
|
182
|
+
* @returns `postInstructions`: the instructions to post the price updates, these should be called before consuming the price updates
|
|
183
|
+
* @returns `priceFeedIdToPriceUpdateAccount`: this is a map of price feed IDs to Solana address. Given a price feed ID, you can use this map to find the account where `postInstructions` will post the price update.
|
|
184
|
+
* @returns `closeInstructions`: the instructions to close the price update accounts, these should be called after consuming the price updates
|
|
185
|
+
*/
|
|
45
186
|
async buildPostPriceUpdateAtomicInstructions(priceUpdateDataArray) {
|
|
46
187
|
const postInstructions = [];
|
|
47
188
|
const priceFeedIdToPriceUpdateAccount = {};
|
|
48
|
-
const
|
|
189
|
+
const closeInstructions = [];
|
|
49
190
|
for (const priceUpdateData of priceUpdateDataArray) {
|
|
50
191
|
const accumulatorUpdateData = (0, price_service_sdk_1.parseAccumulatorUpdateData)(Buffer.from(priceUpdateData, "base64"));
|
|
51
192
|
const guardianSetIndex = (0, vaa_1.getGuardianSetIndex)(accumulatorUpdateData.vaa);
|
|
@@ -57,31 +198,39 @@ class PythSolanaReceiver {
|
|
|
57
198
|
.postUpdateAtomic({
|
|
58
199
|
vaa: trimmedVaa,
|
|
59
200
|
merklePriceUpdate: update,
|
|
60
|
-
treasuryId:
|
|
201
|
+
treasuryId: address_1.DEFAULT_TREASURY_ID,
|
|
61
202
|
})
|
|
62
203
|
.accounts({
|
|
63
204
|
priceUpdateAccount: priceUpdateKeypair.publicKey,
|
|
64
|
-
treasury: (0, address_1.getTreasuryPda)(
|
|
65
|
-
config: (0, address_1.getConfigPda)(),
|
|
66
|
-
guardianSet: (0, address_1.getGuardianSetPda)(guardianSetIndex),
|
|
205
|
+
treasury: (0, address_1.getTreasuryPda)(address_1.DEFAULT_TREASURY_ID, this.receiver.programId),
|
|
206
|
+
config: (0, address_1.getConfigPda)(this.receiver.programId),
|
|
207
|
+
guardianSet: (0, address_1.getGuardianSetPda)(guardianSetIndex, this.wormhole.programId),
|
|
67
208
|
})
|
|
68
209
|
.instruction(),
|
|
69
210
|
signers: [priceUpdateKeypair],
|
|
70
211
|
computeUnits: compute_budget_1.POST_UPDATE_ATOMIC_COMPUTE_BUDGET,
|
|
71
212
|
});
|
|
72
213
|
priceFeedIdToPriceUpdateAccount["0x" + (0, price_service_sdk_1.parsePriceFeedMessage)(update.message).feedId.toString("hex")] = priceUpdateKeypair.publicKey;
|
|
73
|
-
|
|
214
|
+
closeInstructions.push(await this.buildClosePriceUpdateInstruction(priceUpdateKeypair.publicKey));
|
|
74
215
|
}
|
|
75
216
|
}
|
|
76
217
|
return {
|
|
77
218
|
postInstructions,
|
|
78
219
|
priceFeedIdToPriceUpdateAccount,
|
|
79
|
-
|
|
220
|
+
closeInstructions,
|
|
80
221
|
};
|
|
81
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Build a series of helper instructions that post a VAA in an encoded VAA account. This function is bespoke for posting Pyth VAAs and might not work for other usecases.
|
|
225
|
+
*
|
|
226
|
+
* @param vaa a Wormhole VAA
|
|
227
|
+
* @returns `postInstructions`: the instructions to post the VAA
|
|
228
|
+
* @returns `encodedVaaAddress`: the address of the encoded VAA account where the VAA will be posted
|
|
229
|
+
* @returns `closeInstructions`: the instructions to close the encoded VAA account
|
|
230
|
+
*/
|
|
82
231
|
async buildPostEncodedVaaInstructions(vaa) {
|
|
83
232
|
const postInstructions = [];
|
|
84
|
-
const
|
|
233
|
+
const closeInstructions = [];
|
|
85
234
|
const encodedVaaKeypair = new web3_js_1.Keypair();
|
|
86
235
|
const guardianSetIndex = (0, vaa_1.getGuardianSetIndex)(vaa);
|
|
87
236
|
postInstructions.push(await (0, vaa_1.buildEncodedVaaCreateInstruction)(this.wormhole, vaa, encodedVaaKeypair));
|
|
@@ -94,62 +243,73 @@ class PythSolanaReceiver {
|
|
|
94
243
|
.instruction(),
|
|
95
244
|
signers: [],
|
|
96
245
|
});
|
|
97
|
-
postInstructions.push(...(await (0, vaa_1.
|
|
246
|
+
postInstructions.push(...(await (0, vaa_1.buildWriteEncodedVaaWithSplitInstructions)(this.wormhole, vaa, encodedVaaKeypair.publicKey)));
|
|
98
247
|
postInstructions.push({
|
|
99
248
|
instruction: await this.wormhole.methods
|
|
100
249
|
.verifyEncodedVaaV1()
|
|
101
250
|
.accounts({
|
|
102
|
-
guardianSet: (0, address_1.getGuardianSetPda)(guardianSetIndex),
|
|
251
|
+
guardianSet: (0, address_1.getGuardianSetPda)(guardianSetIndex, this.wormhole.programId),
|
|
103
252
|
draftVaa: encodedVaaKeypair.publicKey,
|
|
104
253
|
})
|
|
105
254
|
.instruction(),
|
|
106
255
|
signers: [],
|
|
107
256
|
computeUnits: compute_budget_1.VERIFY_ENCODED_VAA_COMPUTE_BUDGET,
|
|
108
257
|
});
|
|
109
|
-
|
|
258
|
+
closeInstructions.push(await this.buildCloseEncodedVaaInstruction(encodedVaaKeypair.publicKey));
|
|
110
259
|
return {
|
|
111
260
|
postInstructions,
|
|
112
261
|
encodedVaaAddress: encodedVaaKeypair.publicKey,
|
|
113
|
-
|
|
262
|
+
closeInstructions,
|
|
114
263
|
};
|
|
115
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* Build a series of helper instructions that post price updates to the Pyth Solana Receiver program and another series to close the encoded vaa accounts and the price update accounts.
|
|
267
|
+
*
|
|
268
|
+
* @param priceUpdateDataArray the output of the `@pythnetwork/price-service-client`'s `PriceServiceConnection.getLatestVaas`. This is an array of verifiable price updates.
|
|
269
|
+
* @returns `postInstructions`: the instructions to post the price updates, these should be called before consuming the price updates
|
|
270
|
+
* @returns `priceFeedIdToPriceUpdateAccount`: this is a map of price feed IDs to Solana address. Given a price feed ID, you can use this map to find the account where `postInstructions` will post the price update.
|
|
271
|
+
* @returns `closeInstructions`: the instructions to close the price update accounts, these should be called after consuming the price updates
|
|
272
|
+
*/
|
|
116
273
|
async buildPostPriceUpdateInstructions(priceUpdateDataArray) {
|
|
117
274
|
const postInstructions = [];
|
|
118
275
|
const priceFeedIdToPriceUpdateAccount = {};
|
|
119
|
-
const
|
|
276
|
+
const closeInstructions = [];
|
|
120
277
|
for (const priceUpdateData of priceUpdateDataArray) {
|
|
121
278
|
const accumulatorUpdateData = (0, price_service_sdk_1.parseAccumulatorUpdateData)(Buffer.from(priceUpdateData, "base64"));
|
|
122
|
-
const { postInstructions: postEncodedVaaInstructions, encodedVaaAddress: encodedVaa,
|
|
279
|
+
const { postInstructions: postEncodedVaaInstructions, encodedVaaAddress: encodedVaa, closeInstructions: postEncodedVaacloseInstructions, } = await this.buildPostEncodedVaaInstructions(accumulatorUpdateData.vaa);
|
|
123
280
|
postInstructions.push(...postEncodedVaaInstructions);
|
|
124
|
-
|
|
281
|
+
closeInstructions.push(...postEncodedVaacloseInstructions);
|
|
125
282
|
for (const update of accumulatorUpdateData.updates) {
|
|
126
283
|
const priceUpdateKeypair = new web3_js_1.Keypair();
|
|
127
284
|
postInstructions.push({
|
|
128
285
|
instruction: await this.receiver.methods
|
|
129
286
|
.postUpdate({
|
|
130
287
|
merklePriceUpdate: update,
|
|
131
|
-
treasuryId:
|
|
288
|
+
treasuryId: address_1.DEFAULT_TREASURY_ID,
|
|
132
289
|
})
|
|
133
290
|
.accounts({
|
|
134
291
|
encodedVaa,
|
|
135
292
|
priceUpdateAccount: priceUpdateKeypair.publicKey,
|
|
136
|
-
treasury: (0, address_1.getTreasuryPda)(
|
|
137
|
-
config: (0, address_1.getConfigPda)(),
|
|
293
|
+
treasury: (0, address_1.getTreasuryPda)(address_1.DEFAULT_TREASURY_ID, this.receiver.programId),
|
|
294
|
+
config: (0, address_1.getConfigPda)(this.receiver.programId),
|
|
138
295
|
})
|
|
139
296
|
.instruction(),
|
|
140
297
|
signers: [priceUpdateKeypair],
|
|
141
298
|
computeUnits: compute_budget_1.POST_UPDATE_COMPUTE_BUDGET,
|
|
142
299
|
});
|
|
143
300
|
priceFeedIdToPriceUpdateAccount["0x" + (0, price_service_sdk_1.parsePriceFeedMessage)(update.message).feedId.toString("hex")] = priceUpdateKeypair.publicKey;
|
|
144
|
-
|
|
301
|
+
closeInstructions.push(await this.buildClosePriceUpdateInstruction(priceUpdateKeypair.publicKey));
|
|
145
302
|
}
|
|
146
303
|
}
|
|
147
304
|
return {
|
|
148
305
|
postInstructions,
|
|
149
306
|
priceFeedIdToPriceUpdateAccount,
|
|
150
|
-
|
|
307
|
+
closeInstructions,
|
|
151
308
|
};
|
|
152
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* Build an instruction to close an encoded VAA account, recovering the rent.
|
|
312
|
+
*/
|
|
153
313
|
async buildCloseEncodedVaaInstruction(encodedVaa) {
|
|
154
314
|
const instruction = await this.wormhole.methods
|
|
155
315
|
.closeEncodedVaa()
|
|
@@ -157,6 +317,9 @@ class PythSolanaReceiver {
|
|
|
157
317
|
.instruction();
|
|
158
318
|
return { instruction, signers: [] };
|
|
159
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* Build an instruction to close a price update account, recovering the rent.
|
|
322
|
+
*/
|
|
160
323
|
async buildClosePriceUpdateInstruction(priceUpdateAccount) {
|
|
161
324
|
const instruction = await this.receiver.methods
|
|
162
325
|
.reclaimRent()
|
|
@@ -164,5 +327,11 @@ class PythSolanaReceiver {
|
|
|
164
327
|
.instruction();
|
|
165
328
|
return { instruction, signers: [] };
|
|
166
329
|
}
|
|
330
|
+
/**
|
|
331
|
+
* Returns a set of versioned transactions that contain the provided instructions in the same order and with efficient batching
|
|
332
|
+
*/
|
|
333
|
+
async batchIntoVersionedTransactions(instructions, priorityFeeConfig) {
|
|
334
|
+
return solana_utils_1.TransactionBuilder.batchIntoVersionedTransactions(this.wallet.publicKey, this.connection, instructions, priorityFeeConfig);
|
|
335
|
+
}
|
|
167
336
|
}
|
|
168
337
|
exports.PythSolanaReceiver = PythSolanaReceiver;
|
package/lib/address.d.ts
CHANGED
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
import { PublicKey } from "@solana/web3.js";
|
|
2
|
+
/**
|
|
3
|
+
* The default Pyth Solana Receiver program ID.
|
|
4
|
+
* The program is deployed at this address on all SVM networks.
|
|
5
|
+
*/
|
|
2
6
|
export declare const DEFAULT_RECEIVER_PROGRAM_ID: PublicKey;
|
|
7
|
+
/**
|
|
8
|
+
* The default Wormhole program ID.
|
|
9
|
+
* The program is deployed at this address on all SVM networks.
|
|
10
|
+
*/
|
|
3
11
|
export declare const DEFAULT_WORMHOLE_PROGRAM_ID: PublicKey;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Returns the address of a guardian set account from the Wormhole program.
|
|
14
|
+
*/
|
|
15
|
+
export declare const getGuardianSetPda: (guardianSetIndex: number, wormholeProgramId: PublicKey) => PublicKey;
|
|
16
|
+
/**
|
|
17
|
+
* The Pyth Solana Receiver has one treasury account for each u8 `treasuryId`.
|
|
18
|
+
* This is meant to avoid write-locks on the treasury account by load-balancing the writes across multiple accounts.
|
|
19
|
+
*/
|
|
20
|
+
export declare const DEFAULT_TREASURY_ID = 0;
|
|
21
|
+
/**
|
|
22
|
+
* Returns the address of a treasury account from the Pyth Solana Receiver program.
|
|
23
|
+
*/
|
|
24
|
+
export declare const getTreasuryPda: (treasuryId: number, receiverProgramId: PublicKey) => PublicKey;
|
|
25
|
+
/**
|
|
26
|
+
* Returns the address of the config account from the Pyth Solana Receiver program.
|
|
27
|
+
*/
|
|
28
|
+
export declare const getConfigPda: (receiverProgramId: PublicKey) => PublicKey;
|
|
7
29
|
//# sourceMappingURL=address.d.ts.map
|
package/lib/address.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,eAAO,MAAM,2BAA2B,WAEvC,CAAC;AACF,eAAO,MAAM,2BAA2B,WAEvC,CAAC;AAEF,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;GAGG;AACH,eAAO,MAAM,2BAA2B,WAEvC,CAAC;AACF;;;GAGG;AACH,eAAO,MAAM,2BAA2B,WAEvC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,qBACV,MAAM,qBACL,SAAS,cAQ7B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;GAEG;AACH,eAAO,MAAM,cAAc,eACb,MAAM,qBACC,SAAS,cAM7B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,sBAAuB,SAAS,cAKxD,CAAC"}
|
package/lib/address.js
CHANGED
|
@@ -1,20 +1,42 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getConfigPda = exports.getTreasuryPda = exports.getGuardianSetPda = exports.DEFAULT_WORMHOLE_PROGRAM_ID = exports.DEFAULT_RECEIVER_PROGRAM_ID = void 0;
|
|
3
|
+
exports.getConfigPda = exports.getTreasuryPda = exports.DEFAULT_TREASURY_ID = exports.getGuardianSetPda = exports.DEFAULT_WORMHOLE_PROGRAM_ID = exports.DEFAULT_RECEIVER_PROGRAM_ID = void 0;
|
|
4
4
|
const web3_js_1 = require("@solana/web3.js");
|
|
5
|
+
/**
|
|
6
|
+
* The default Pyth Solana Receiver program ID.
|
|
7
|
+
* The program is deployed at this address on all SVM networks.
|
|
8
|
+
*/
|
|
5
9
|
exports.DEFAULT_RECEIVER_PROGRAM_ID = new web3_js_1.PublicKey("rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ");
|
|
10
|
+
/**
|
|
11
|
+
* The default Wormhole program ID.
|
|
12
|
+
* The program is deployed at this address on all SVM networks.
|
|
13
|
+
*/
|
|
6
14
|
exports.DEFAULT_WORMHOLE_PROGRAM_ID = new web3_js_1.PublicKey("HDwcJBJXjL9FpJ7UBsYBtaDjsBUhuLCUYoz3zr8SWWaQ");
|
|
7
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Returns the address of a guardian set account from the Wormhole program.
|
|
17
|
+
*/
|
|
18
|
+
const getGuardianSetPda = (guardianSetIndex, wormholeProgramId) => {
|
|
8
19
|
const guardianSetIndexBuf = Buffer.alloc(4);
|
|
9
20
|
guardianSetIndexBuf.writeUInt32BE(guardianSetIndex, 0);
|
|
10
|
-
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("GuardianSet"), guardianSetIndexBuf],
|
|
21
|
+
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("GuardianSet"), guardianSetIndexBuf], wormholeProgramId)[0];
|
|
11
22
|
};
|
|
12
23
|
exports.getGuardianSetPda = getGuardianSetPda;
|
|
13
|
-
|
|
14
|
-
|
|
24
|
+
/**
|
|
25
|
+
* The Pyth Solana Receiver has one treasury account for each u8 `treasuryId`.
|
|
26
|
+
* This is meant to avoid write-locks on the treasury account by load-balancing the writes across multiple accounts.
|
|
27
|
+
*/
|
|
28
|
+
exports.DEFAULT_TREASURY_ID = 0;
|
|
29
|
+
/**
|
|
30
|
+
* Returns the address of a treasury account from the Pyth Solana Receiver program.
|
|
31
|
+
*/
|
|
32
|
+
const getTreasuryPda = (treasuryId, receiverProgramId) => {
|
|
33
|
+
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("treasury"), Buffer.from([treasuryId])], receiverProgramId)[0];
|
|
15
34
|
};
|
|
16
35
|
exports.getTreasuryPda = getTreasuryPda;
|
|
17
|
-
|
|
18
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Returns the address of the config account from the Pyth Solana Receiver program.
|
|
38
|
+
*/
|
|
39
|
+
const getConfigPda = (receiverProgramId) => {
|
|
40
|
+
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("config")], receiverProgramId)[0];
|
|
19
41
|
};
|
|
20
42
|
exports.getConfigPda = getConfigPda;
|
package/lib/compute_budget.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A hard-coded budget for the compute units required for the `verifyEncodedVaa` instruction in the Wormhole program.
|
|
3
|
+
*/
|
|
1
4
|
export declare const VERIFY_ENCODED_VAA_COMPUTE_BUDGET = 400000;
|
|
5
|
+
/**
|
|
6
|
+
* A hard-coded budget for the compute units required for the `postUpdateAtomic` instruction in the Pyth Solana Receiver program.
|
|
7
|
+
*/
|
|
2
8
|
export declare const POST_UPDATE_ATOMIC_COMPUTE_BUDGET = 400000;
|
|
9
|
+
/**
|
|
10
|
+
* A hard-coded budget for the compute units required for the `postUpdate` instruction in the Pyth Solana Receiver program.
|
|
11
|
+
*/
|
|
3
12
|
export declare const POST_UPDATE_COMPUTE_BUDGET = 200000;
|
|
4
13
|
//# sourceMappingURL=compute_budget.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compute_budget.d.ts","sourceRoot":"","sources":["../src/compute_budget.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iCAAiC,SAAS,CAAC;AACxD,eAAO,MAAM,iCAAiC,SAAS,CAAC;AACxD,eAAO,MAAM,0BAA0B,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"compute_budget.d.ts","sourceRoot":"","sources":["../src/compute_budget.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,iCAAiC,SAAS,CAAC;AACxD;;GAEG;AACH,eAAO,MAAM,iCAAiC,SAAS,CAAC;AACxD;;GAEG;AACH,eAAO,MAAM,0BAA0B,SAAS,CAAC"}
|
package/lib/compute_budget.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.POST_UPDATE_COMPUTE_BUDGET = exports.POST_UPDATE_ATOMIC_COMPUTE_BUDGET = exports.VERIFY_ENCODED_VAA_COMPUTE_BUDGET = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* A hard-coded budget for the compute units required for the `verifyEncodedVaa` instruction in the Wormhole program.
|
|
6
|
+
*/
|
|
4
7
|
exports.VERIFY_ENCODED_VAA_COMPUTE_BUDGET = 400000;
|
|
8
|
+
/**
|
|
9
|
+
* A hard-coded budget for the compute units required for the `postUpdateAtomic` instruction in the Pyth Solana Receiver program.
|
|
10
|
+
*/
|
|
5
11
|
exports.POST_UPDATE_ATOMIC_COMPUTE_BUDGET = 400000;
|
|
12
|
+
/**
|
|
13
|
+
* A hard-coded budget for the compute units required for the `postUpdate` instruction in the Pyth Solana Receiver program.
|
|
14
|
+
*/
|
|
6
15
|
exports.POST_UPDATE_COMPUTE_BUDGET = 200000;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { PythSolanaReceiver } from "./PythSolanaReceiver";
|
|
2
|
-
export { TransactionBuilder } from "@pythnetwork/solana-utils";
|
|
1
|
+
export { PythSolanaReceiver, PythTransactionBuilder, } from "./PythSolanaReceiver";
|
|
2
|
+
export { TransactionBuilder, InstructionWithEphemeralSigners, } from "@pythnetwork/solana-utils";
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,kBAAkB,EAClB,+BAA+B,GAChC,MAAM,2BAA2B,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TransactionBuilder = exports.PythSolanaReceiver = void 0;
|
|
3
|
+
exports.TransactionBuilder = exports.PythTransactionBuilder = exports.PythSolanaReceiver = void 0;
|
|
4
4
|
var PythSolanaReceiver_1 = require("./PythSolanaReceiver");
|
|
5
5
|
Object.defineProperty(exports, "PythSolanaReceiver", { enumerable: true, get: function () { return PythSolanaReceiver_1.PythSolanaReceiver; } });
|
|
6
|
+
Object.defineProperty(exports, "PythTransactionBuilder", { enumerable: true, get: function () { return PythSolanaReceiver_1.PythTransactionBuilder; } });
|
|
6
7
|
var solana_utils_1 = require("@pythnetwork/solana-utils");
|
|
7
8
|
Object.defineProperty(exports, "TransactionBuilder", { enumerable: true, get: function () { return solana_utils_1.TransactionBuilder; } });
|
package/lib/vaa.d.ts
CHANGED
|
@@ -3,15 +3,56 @@ import { Keypair, PublicKey } from "@solana/web3.js";
|
|
|
3
3
|
import { WormholeCoreBridgeSolana } from "./idl/wormhole_core_bridge_solana";
|
|
4
4
|
import { Program } from "@coral-xyz/anchor";
|
|
5
5
|
import { InstructionWithEphemeralSigners } from "@pythnetwork/solana-utils";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export declare const DEFAULT_REDUCED_GUARDIAN_SET_SIZE = 5;
|
|
6
|
+
/**
|
|
7
|
+
* Get the index of the guardian set that signed a VAA
|
|
8
|
+
*/
|
|
10
9
|
export declare function getGuardianSetIndex(vaa: Buffer): number;
|
|
10
|
+
/**
|
|
11
|
+
* The default number of signatures to keep in a VAA when using `trimSignatures`.
|
|
12
|
+
* This number was chosen as the maximum number of signatures so that the VAA's contents can be posted in a single Solana transaction.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DEFAULT_REDUCED_GUARDIAN_SET_SIZE = 5;
|
|
15
|
+
/**
|
|
16
|
+
* The size of a guardian signature in a VAA.
|
|
17
|
+
*
|
|
18
|
+
* It is 66 bytes long, the first byte is the guardian index and the next 65 bytes are the signature (including a recovery id).
|
|
19
|
+
*/
|
|
20
|
+
export declare const VAA_SIGNATURE_SIZE = 66;
|
|
21
|
+
/**
|
|
22
|
+
* Trim the number of signatures of a VAA.
|
|
23
|
+
*
|
|
24
|
+
* @returns the same VAA as the input, but with `n` signatures instead of the original number of signatures.
|
|
25
|
+
*
|
|
26
|
+
* A Wormhole VAA typically has a number of signatures equal to two thirds of the number of guardians. However,
|
|
27
|
+
* this function is useful to make VAAs smaller to post their contents in a single Solana transaction.
|
|
28
|
+
*/
|
|
11
29
|
export declare function trimSignatures(vaa: Buffer, n?: number): Buffer;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
30
|
+
/**
|
|
31
|
+
* The start of the VAA bytes in an encoded VAA account. Before this offset, the account contains a header.
|
|
32
|
+
*/
|
|
33
|
+
export declare const VAA_START = 46;
|
|
34
|
+
/**
|
|
35
|
+
* Build an instruction to create an encoded VAA account.
|
|
36
|
+
*
|
|
37
|
+
* This is the first step to post a VAA to the Wormhole program.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildEncodedVaaCreateInstruction(wormhole: Program<WormholeCoreBridgeSolana>, vaa: Buffer, encodedVaaKeypair: Keypair): Promise<InstructionWithEphemeralSigners>;
|
|
40
|
+
/**
|
|
41
|
+
* Writing the VAA to to an encoded VAA account is done in 2 instructions.
|
|
42
|
+
*
|
|
43
|
+
* The first one writes the first `VAA_SPLIT_INDEX` bytes and the second one writes the rest.
|
|
44
|
+
*
|
|
45
|
+
* This number was chosen as the biggest number such that one can still call `createInstruction`, `initEncodedVaa` and `writeEncodedVaa` in a single Solana transaction.
|
|
46
|
+
* This way, the packing of the instructions to post an encoded vaa is more efficient.
|
|
47
|
+
*/
|
|
48
|
+
export declare const VAA_SPLIT_INDEX = 792;
|
|
49
|
+
/**
|
|
50
|
+
* Build a set of instructions to write a VAA to an encoded VAA account
|
|
51
|
+
* This functions returns 2 instructions and splits the VAA in an opinionated way, so that the whole process of posting a VAA can be efficiently packed in the 2 transactions:
|
|
52
|
+
*
|
|
53
|
+
* TX 1 : `createInstruction` + `initEncodedVaa` + `writeEncodedVaa_1`
|
|
54
|
+
*
|
|
55
|
+
* TX 2 : `writeEncodedVaa_2` + `verifyEncodedVaaV1`
|
|
56
|
+
*/
|
|
57
|
+
export declare function buildWriteEncodedVaaWithSplitInstructions(wormhole: Program<WormholeCoreBridgeSolana>, vaa: Buffer, draftVaa: PublicKey): Promise<InstructionWithEphemeralSigners[]>;
|
|
17
58
|
//# sourceMappingURL=vaa.d.ts.map
|
package/lib/vaa.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vaa.d.ts","sourceRoot":"","sources":["../src/vaa.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAC;AAE5E
|
|
1
|
+
{"version":3,"file":"vaa.d.ts","sourceRoot":"","sources":["../src/vaa.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAC;AAE5E;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,UAE9C;AAED;;;GAGG;AACH,eAAO,MAAM,iCAAiC,IAAI,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,CAAC,SAAoC,GACpC,MAAM,CAeR;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,KAAK,CAAC;AAE5B;;;;GAIG;AACH,wBAAsB,gCAAgC,CACpD,QAAQ,EAAE,OAAO,CAAC,wBAAwB,CAAC,EAC3C,GAAG,EAAE,MAAM,EACX,iBAAiB,EAAE,OAAO,GACzB,OAAO,CAAC,+BAA+B,CAAC,CAS1C;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC;;;;;;;GAOG;AACH,wBAAsB,yCAAyC,CAC7D,QAAQ,EAAE,OAAO,CAAC,wBAAwB,CAAC,EAC3C,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,SAAS,GAClB,OAAO,CAAC,+BAA+B,EAAE,CAAC,CA2B5C"}
|
package/lib/vaa.js
CHANGED
|
@@ -1,14 +1,32 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
exports.DEFAULT_REDUCED_GUARDIAN_SET_SIZE = 5;
|
|
3
|
+
exports.buildWriteEncodedVaaWithSplitInstructions = exports.VAA_SPLIT_INDEX = exports.buildEncodedVaaCreateInstruction = exports.VAA_START = exports.trimSignatures = exports.VAA_SIGNATURE_SIZE = exports.DEFAULT_REDUCED_GUARDIAN_SET_SIZE = exports.getGuardianSetIndex = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Get the index of the guardian set that signed a VAA
|
|
6
|
+
*/
|
|
8
7
|
function getGuardianSetIndex(vaa) {
|
|
9
8
|
return vaa.readUInt32BE(1);
|
|
10
9
|
}
|
|
11
10
|
exports.getGuardianSetIndex = getGuardianSetIndex;
|
|
11
|
+
/**
|
|
12
|
+
* The default number of signatures to keep in a VAA when using `trimSignatures`.
|
|
13
|
+
* This number was chosen as the maximum number of signatures so that the VAA's contents can be posted in a single Solana transaction.
|
|
14
|
+
*/
|
|
15
|
+
exports.DEFAULT_REDUCED_GUARDIAN_SET_SIZE = 5;
|
|
16
|
+
/**
|
|
17
|
+
* The size of a guardian signature in a VAA.
|
|
18
|
+
*
|
|
19
|
+
* It is 66 bytes long, the first byte is the guardian index and the next 65 bytes are the signature (including a recovery id).
|
|
20
|
+
*/
|
|
21
|
+
exports.VAA_SIGNATURE_SIZE = 66;
|
|
22
|
+
/**
|
|
23
|
+
* Trim the number of signatures of a VAA.
|
|
24
|
+
*
|
|
25
|
+
* @returns the same VAA as the input, but with `n` signatures instead of the original number of signatures.
|
|
26
|
+
*
|
|
27
|
+
* A Wormhole VAA typically has a number of signatures equal to two thirds of the number of guardians. However,
|
|
28
|
+
* this function is useful to make VAAs smaller to post their contents in a single Solana transaction.
|
|
29
|
+
*/
|
|
12
30
|
function trimSignatures(vaa, n = exports.DEFAULT_REDUCED_GUARDIAN_SET_SIZE) {
|
|
13
31
|
const currentNumSignatures = vaa[5];
|
|
14
32
|
if (n > currentNumSignatures) {
|
|
@@ -22,6 +40,15 @@ function trimSignatures(vaa, n = exports.DEFAULT_REDUCED_GUARDIAN_SET_SIZE) {
|
|
|
22
40
|
return trimmedVaa;
|
|
23
41
|
}
|
|
24
42
|
exports.trimSignatures = trimSignatures;
|
|
43
|
+
/**
|
|
44
|
+
* The start of the VAA bytes in an encoded VAA account. Before this offset, the account contains a header.
|
|
45
|
+
*/
|
|
46
|
+
exports.VAA_START = 46;
|
|
47
|
+
/**
|
|
48
|
+
* Build an instruction to create an encoded VAA account.
|
|
49
|
+
*
|
|
50
|
+
* This is the first step to post a VAA to the Wormhole program.
|
|
51
|
+
*/
|
|
25
52
|
async function buildEncodedVaaCreateInstruction(wormhole, vaa, encodedVaaKeypair) {
|
|
26
53
|
const encodedVaaSize = vaa.length + exports.VAA_START;
|
|
27
54
|
return {
|
|
@@ -30,7 +57,24 @@ async function buildEncodedVaaCreateInstruction(wormhole, vaa, encodedVaaKeypair
|
|
|
30
57
|
};
|
|
31
58
|
}
|
|
32
59
|
exports.buildEncodedVaaCreateInstruction = buildEncodedVaaCreateInstruction;
|
|
33
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Writing the VAA to to an encoded VAA account is done in 2 instructions.
|
|
62
|
+
*
|
|
63
|
+
* The first one writes the first `VAA_SPLIT_INDEX` bytes and the second one writes the rest.
|
|
64
|
+
*
|
|
65
|
+
* This number was chosen as the biggest number such that one can still call `createInstruction`, `initEncodedVaa` and `writeEncodedVaa` in a single Solana transaction.
|
|
66
|
+
* This way, the packing of the instructions to post an encoded vaa is more efficient.
|
|
67
|
+
*/
|
|
68
|
+
exports.VAA_SPLIT_INDEX = 792;
|
|
69
|
+
/**
|
|
70
|
+
* Build a set of instructions to write a VAA to an encoded VAA account
|
|
71
|
+
* This functions returns 2 instructions and splits the VAA in an opinionated way, so that the whole process of posting a VAA can be efficiently packed in the 2 transactions:
|
|
72
|
+
*
|
|
73
|
+
* TX 1 : `createInstruction` + `initEncodedVaa` + `writeEncodedVaa_1`
|
|
74
|
+
*
|
|
75
|
+
* TX 2 : `writeEncodedVaa_2` + `verifyEncodedVaaV1`
|
|
76
|
+
*/
|
|
77
|
+
async function buildWriteEncodedVaaWithSplitInstructions(wormhole, vaa, draftVaa) {
|
|
34
78
|
return [
|
|
35
79
|
{
|
|
36
80
|
instruction: await wormhole.methods
|
|
@@ -58,4 +102,4 @@ async function buildWriteEncodedVaaWithSplit(wormhole, vaa, draftVaa) {
|
|
|
58
102
|
},
|
|
59
103
|
];
|
|
60
104
|
}
|
|
61
|
-
exports.
|
|
105
|
+
exports.buildWriteEncodedVaaWithSplitInstructions = buildWriteEncodedVaaWithSplitInstructions;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pythnetwork/pyth-solana-receiver",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Pyth solana receiver SDK",
|
|
5
5
|
"homepage": "https://pyth.network",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"@pythnetwork/solana-utils": "*",
|
|
48
48
|
"@solana/web3.js": "^1.90.0"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "854f804d1828361909012497688516d9d84660e6"
|
|
51
51
|
}
|