@glamsystems/glam-cli 1.0.3-alpha.3 → 1.0.3-alpha.5
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/main.js +131 -63
- package/package.json +2 -2
package/main.js
CHANGED
|
@@ -3773,15 +3773,14 @@ class BaseClient {
|
|
|
3773
3773
|
}).compileToV0Message(lookupTableAccounts));
|
|
3774
3774
|
}
|
|
3775
3775
|
async sendAndConfirm(tx, additionalSigners = []) {
|
|
3776
|
-
const connection = this.provider.connection;
|
|
3777
3776
|
// Mainnet only: use dedicated connection for sending transactions if available
|
|
3778
3777
|
const txConnection = this.cluster === clientConfig_1.ClusterNetwork.Mainnet
|
|
3779
3778
|
? new web3_js_1.Connection(process.env?.NEXT_PUBLIC_TX_RPC ||
|
|
3780
|
-
process.env
|
|
3781
|
-
connection.rpcEndpoint, {
|
|
3782
|
-
commitment:
|
|
3779
|
+
process.env?.TX_RPC ||
|
|
3780
|
+
this.connection.rpcEndpoint, {
|
|
3781
|
+
commitment: this.connection.commitment,
|
|
3783
3782
|
})
|
|
3784
|
-
: connection;
|
|
3783
|
+
: this.connection;
|
|
3785
3784
|
// This is just a convenient method so that in tests we can send legacy
|
|
3786
3785
|
// txs, for example transfer SOL, create ATA, etc.
|
|
3787
3786
|
if (tx instanceof web3_js_1.Transaction) {
|
|
@@ -3789,38 +3788,59 @@ class BaseClient {
|
|
|
3789
3788
|
skipPreflight: true,
|
|
3790
3789
|
});
|
|
3791
3790
|
}
|
|
3792
|
-
let serializedTx;
|
|
3793
3791
|
// Anchor provider.sendAndConfirm forces a signature with the wallet, which we don't want
|
|
3794
3792
|
// https://github.com/coral-xyz/anchor/blob/v0.30.0/ts/packages/anchor/src/provider.ts#L159
|
|
3795
|
-
const
|
|
3796
|
-
const signedTx = await wallet.signTransaction(tx);
|
|
3793
|
+
const signedTx = await this.wallet.signTransaction(tx);
|
|
3797
3794
|
if (additionalSigners && additionalSigners.length > 0) {
|
|
3798
3795
|
signedTx.sign(additionalSigners);
|
|
3799
3796
|
}
|
|
3800
|
-
serializedTx = signedTx.serialize();
|
|
3797
|
+
const serializedTx = signedTx.serialize();
|
|
3798
|
+
// skip simulation since we just did it to compute CUs
|
|
3799
|
+
// however this means that we need to reconstruct the error, if
|
|
3800
|
+
// the tx fails onchain execution.
|
|
3801
3801
|
const txSig = await txConnection.sendRawTransaction(serializedTx, {
|
|
3802
|
-
// skip simulation since we just did it to compute CUs
|
|
3803
|
-
// however this means that we need to reconstruct the error, if
|
|
3804
|
-
// the tx fails on chain execution.
|
|
3805
3802
|
skipPreflight: true,
|
|
3806
3803
|
});
|
|
3807
3804
|
if (process.env.NODE_ENV === "development") {
|
|
3808
3805
|
console.log("Confirming tx:", txSig);
|
|
3809
3806
|
}
|
|
3810
|
-
const
|
|
3811
|
-
const res = await connection.confirmTransaction({
|
|
3812
|
-
...latestBlockhash,
|
|
3813
|
-
signature: txSig,
|
|
3814
|
-
});
|
|
3807
|
+
const res = await this.confirmTransaction(txSig);
|
|
3815
3808
|
// if the tx fails, throw an error including logs
|
|
3816
3809
|
if (res.value.err) {
|
|
3817
|
-
const errTx = await connection.getTransaction(txSig, {
|
|
3810
|
+
const errTx = await this.connection.getTransaction(txSig, {
|
|
3818
3811
|
maxSupportedTransactionVersion: 0,
|
|
3819
3812
|
});
|
|
3820
3813
|
throw new error_1.GlamError((0, transaction_1.parseProgramLogs)(errTx?.meta?.logMessages), errTx?.meta?.err || undefined, errTx?.meta?.logMessages || []);
|
|
3821
3814
|
}
|
|
3822
3815
|
return txSig;
|
|
3823
3816
|
}
|
|
3817
|
+
async confirmTransaction(txSig) {
|
|
3818
|
+
const useWebSocket = !(process.env?.NEXT_PUBLIC_WEBSOCKET_DISABLED ||
|
|
3819
|
+
process.env?.WEBSOCKET_DISABLED);
|
|
3820
|
+
if (useWebSocket) {
|
|
3821
|
+
const latestBlockhash = await this.blockhashWithCache.get();
|
|
3822
|
+
return await this.connection.confirmTransaction({
|
|
3823
|
+
...latestBlockhash,
|
|
3824
|
+
signature: txSig,
|
|
3825
|
+
});
|
|
3826
|
+
}
|
|
3827
|
+
if (process.env.NODE_ENV === "development") {
|
|
3828
|
+
console.warn("WebSocket disabled, falling back to polling signature status");
|
|
3829
|
+
}
|
|
3830
|
+
const maxRetries = 60;
|
|
3831
|
+
const retryDelayMs = 1000;
|
|
3832
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
3833
|
+
const status = await this.connection.getSignatureStatus(txSig);
|
|
3834
|
+
if (status?.value?.confirmationStatus === "confirmed" ||
|
|
3835
|
+
status?.value?.confirmationStatus === "finalized" ||
|
|
3836
|
+
status?.value?.err) {
|
|
3837
|
+
return { value: { err: status.value.err } };
|
|
3838
|
+
}
|
|
3839
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
3840
|
+
}
|
|
3841
|
+
const expiry = (maxRetries * retryDelayMs) / 1000;
|
|
3842
|
+
throw new Error(`Transaction confirmation timeout after ${expiry} seconds.`);
|
|
3843
|
+
}
|
|
3824
3844
|
get connection() {
|
|
3825
3845
|
return this.provider.connection;
|
|
3826
3846
|
}
|
|
@@ -8461,7 +8481,7 @@ class PriceClient {
|
|
|
8461
8481
|
.map((v) => Array.from(v.pkValues()))
|
|
8462
8482
|
.flat();
|
|
8463
8483
|
// Dedupe keys and fetch all accounts in a single RPC call
|
|
8464
|
-
const pubkeys = Array.from(new utils_1.PkSet(tokenPubkeys.concat(...driftUsers, ...driftSpotMarkets, ...kaminoObligations, ...kaminoReserves)));
|
|
8484
|
+
const pubkeys = Array.from(new utils_1.PkSet(tokenPubkeys.concat(...driftUsers, ...driftSpotMarkets, ...kaminoObligations, ...kaminoReserves, web3_js_1.SYSVAR_CLOCK_PUBKEY)));
|
|
8465
8485
|
const { context: { slot }, value: accountsInfo, } = await this.base.provider.connection.getMultipleAccountsInfoAndContext(pubkeys, commitment);
|
|
8466
8486
|
// Build a map of pubkey to account data for quick lookup
|
|
8467
8487
|
const accountsDataMap = new utils_1.PkMap();
|
|
@@ -8489,7 +8509,9 @@ class PriceClient {
|
|
|
8489
8509
|
const tokenHoldings = this.getTokenHoldings(tokenPubkeys, accountsDataMap, tokenPricesMap);
|
|
8490
8510
|
const driftSpotHoldings = this.getDriftSpotHoldings(driftPubkeys.pkKeys(), driftSpotMarketsMap, accountsDataMap, tokenPricesMap);
|
|
8491
8511
|
const kaminoLendHoldings = this.getKaminoLendHoldings(kaminoPubkeys.pkKeys(), kaminoReservesMap, accountsDataMap, tokenPricesMap);
|
|
8492
|
-
const timestamp =
|
|
8512
|
+
const timestamp = accountsDataMap
|
|
8513
|
+
.get(web3_js_1.SYSVAR_CLOCK_PUBKEY)
|
|
8514
|
+
.readUInt32LE(32);
|
|
8493
8515
|
const ret = new VaultHoldings(this.base.statePda, this.base.vaultPda, priceBaseAssetMint, slot, timestamp, commitment);
|
|
8494
8516
|
tokenHoldings.forEach((holding) => ret.add(holding));
|
|
8495
8517
|
driftSpotHoldings.forEach((holding) => ret.add(holding));
|
|
@@ -10448,9 +10470,17 @@ class CctpClient {
|
|
|
10448
10470
|
];
|
|
10449
10471
|
}
|
|
10450
10472
|
async buildReceiveMessageIx(sourceDomain, messageObj) {
|
|
10451
|
-
const { message, attestation, eventNonce, decodedMessage
|
|
10473
|
+
const { message, attestation, eventNonce, decodedMessage, status } = messageObj;
|
|
10474
|
+
if (status !== "complete") {
|
|
10475
|
+
throw new Error(`Attestation status is ${status}, expected "complete"`);
|
|
10476
|
+
}
|
|
10477
|
+
if (!decodedMessage ||
|
|
10478
|
+
!decodedMessage?.decodedMessageBody ||
|
|
10479
|
+
!decodedMessage?.decodedMessageBody?.burnToken) {
|
|
10480
|
+
throw new Error("Invalid message object: missing burnToken in decodedMessage");
|
|
10481
|
+
}
|
|
10452
10482
|
// message, attestation, eventNonce, burnToken are hex strings
|
|
10453
|
-
const pdas = await this.getReceiveMessagePdas(constants_1.MESSAGE_TRANSMITTER_V2, constants_1.TOKEN_MESSENGER_MINTER_V2, constants_1.USDC, burnToken, sourceDomain.toString(), eventNonce);
|
|
10483
|
+
const pdas = await this.getReceiveMessagePdas(constants_1.MESSAGE_TRANSMITTER_V2, constants_1.TOKEN_MESSENGER_MINTER_V2, constants_1.USDC, decodedMessage.decodedMessageBody.burnToken, sourceDomain.toString(), eventNonce);
|
|
10454
10484
|
// raw ix data: [discriminator][message][attestation]
|
|
10455
10485
|
const messageBuffer = Buffer.from(message.replace("0x", ""), "hex");
|
|
10456
10486
|
const attestationBuffer = Buffer.from(attestation.replace("0x", ""), "hex");
|
|
@@ -10654,7 +10684,14 @@ class CctpClient {
|
|
|
10654
10684
|
queryParams.set("transactionHash", txHash);
|
|
10655
10685
|
}
|
|
10656
10686
|
const resonse = await fetch(`https://iris-api.circle.com/v2/messages/${sourceDomain}?${queryParams}`);
|
|
10687
|
+
if (resonse.status !== 200) {
|
|
10688
|
+
const { error } = await resonse.json();
|
|
10689
|
+
throw new Error(`Failed to fetch messages from Circle API: ${resonse.status} ${error}`);
|
|
10690
|
+
}
|
|
10657
10691
|
const { messages } = await resonse.json();
|
|
10692
|
+
if (!(messages instanceof Array)) {
|
|
10693
|
+
throw new Error("Invalid response from Circle API: messages not found");
|
|
10694
|
+
}
|
|
10658
10695
|
return messages;
|
|
10659
10696
|
}
|
|
10660
10697
|
/**
|
|
@@ -10826,6 +10863,7 @@ class CliConfig {
|
|
|
10826
10863
|
this.cluster = config.cluster || "";
|
|
10827
10864
|
this.json_rpc_url = config.json_rpc_url || "";
|
|
10828
10865
|
this.tx_rpc_url = config.tx_rpc_url || "";
|
|
10866
|
+
this.websocket_disabled = config.websocket_disabled || false;
|
|
10829
10867
|
this.keypair_path = config.keypair_path || "";
|
|
10830
10868
|
this.glam_api = config.glam_api;
|
|
10831
10869
|
this.priority_fee = config.priority_fee;
|
|
@@ -10873,6 +10911,9 @@ class CliConfig {
|
|
|
10873
10911
|
if (cliConfig.tx_rpc_url) {
|
|
10874
10912
|
process.env.TX_RPC = cliConfig.tx_rpc_url;
|
|
10875
10913
|
}
|
|
10914
|
+
if (cliConfig.websocket_disabled) {
|
|
10915
|
+
process.env.WEBSOCKET_DISABLED = "1";
|
|
10916
|
+
}
|
|
10876
10917
|
if (cliConfig.glam_api) {
|
|
10877
10918
|
process.env.GLAM_API = cliConfig.glam_api || "https://api.glam.systems";
|
|
10878
10919
|
}
|
|
@@ -13043,37 +13084,6 @@ function installVaultCommands(program, context) {
|
|
|
13043
13084
|
process.exit(1);
|
|
13044
13085
|
}
|
|
13045
13086
|
});
|
|
13046
|
-
program
|
|
13047
|
-
.command("add-asset")
|
|
13048
|
-
.argument("<asset>", "Asset mint public key", utils_1.validatePublicKey)
|
|
13049
|
-
.description("Add a new asset to allowlist")
|
|
13050
|
-
.action(async (asset) => {
|
|
13051
|
-
const stateModel = await context.glamClient.fetchStateModel();
|
|
13052
|
-
const assetsSet = new Set([...stateModel.assets, asset].map((a) => a.toBase58()));
|
|
13053
|
-
const assets = Array.from(assetsSet).map((a) => new web3_js_1.PublicKey(a));
|
|
13054
|
-
const txSig = await context.glamClient.state.update({ assets }, context.txOptions);
|
|
13055
|
-
console.log(`Added asset ${asset}: ${txSig}`);
|
|
13056
|
-
});
|
|
13057
|
-
program
|
|
13058
|
-
.command("delete-asset")
|
|
13059
|
-
.argument("<asset>", "Asset mint public key", utils_1.validatePublicKey)
|
|
13060
|
-
.description("Delete an asset from allowlist")
|
|
13061
|
-
.action(async (asset) => {
|
|
13062
|
-
const stateModel = await context.glamClient.fetchStateModel();
|
|
13063
|
-
if (asset.equals(stateModel.baseAssetMint)) {
|
|
13064
|
-
console.error("Base asset cannot be deleted from allowlist");
|
|
13065
|
-
process.exit(1);
|
|
13066
|
-
}
|
|
13067
|
-
const assetsSet = new Set(stateModel.assets.map((a) => a.toBase58()));
|
|
13068
|
-
let removed = assetsSet.delete(asset.toBase58());
|
|
13069
|
-
if (!removed) {
|
|
13070
|
-
console.error("Asset not found in allowlist, nothing to delete");
|
|
13071
|
-
process.exit(1);
|
|
13072
|
-
}
|
|
13073
|
-
const assets = Array.from(assetsSet).map((a) => new web3_js_1.PublicKey(a));
|
|
13074
|
-
const txSig = await context.glamClient.state.update({ assets }, context.txOptions);
|
|
13075
|
-
console.log(`Deleted asset ${asset}: ${txSig}`);
|
|
13076
|
-
});
|
|
13077
13087
|
program
|
|
13078
13088
|
.command("set-enabled <enabled>")
|
|
13079
13089
|
.description("Set GLAM state enabled or disabled")
|
|
@@ -13295,6 +13305,58 @@ function installVaultCommands(program, context) {
|
|
|
13295
13305
|
}
|
|
13296
13306
|
});
|
|
13297
13307
|
});
|
|
13308
|
+
program
|
|
13309
|
+
.command("asset-allowlist")
|
|
13310
|
+
.description("Get asset allowlist and corresponding token account")
|
|
13311
|
+
.action(async () => {
|
|
13312
|
+
const state = await context.glamClient.fetchStateAccount();
|
|
13313
|
+
const mints = await (0, glam_sdk_1.fetchMintsAndTokenPrograms)(context.glamClient.connection, state.assets);
|
|
13314
|
+
const data = mints.map(({ mint: { address, decimals }, tokenProgram }) => {
|
|
13315
|
+
const tokenAccount = context.glamClient.getVaultAta(address, tokenProgram);
|
|
13316
|
+
return {
|
|
13317
|
+
assetMint: address,
|
|
13318
|
+
decimals,
|
|
13319
|
+
tokenAccount,
|
|
13320
|
+
tokenProgram,
|
|
13321
|
+
};
|
|
13322
|
+
});
|
|
13323
|
+
console.log(JSON.stringify(data, null, 2));
|
|
13324
|
+
});
|
|
13325
|
+
program
|
|
13326
|
+
.command("add-asset")
|
|
13327
|
+
.argument("<asset>", "Asset mint public key", utils_1.validatePublicKey)
|
|
13328
|
+
.description("Add a new asset to allowlist")
|
|
13329
|
+
.action(async (asset) => {
|
|
13330
|
+
const state = await context.glamClient.fetchStateAccount();
|
|
13331
|
+
const assetsSet = new glam_sdk_1.PkSet(state.assets);
|
|
13332
|
+
if (assetsSet.has(asset)) {
|
|
13333
|
+
console.error(`Asset ${asset} already allowlisted`);
|
|
13334
|
+
process.exit(1);
|
|
13335
|
+
}
|
|
13336
|
+
const assets = Array.from(assetsSet.add(asset));
|
|
13337
|
+
const txSig = await context.glamClient.state.update({ assets }, context.txOptions);
|
|
13338
|
+
console.log(`Allowlisted asset ${asset}: ${txSig}`);
|
|
13339
|
+
});
|
|
13340
|
+
program
|
|
13341
|
+
.command("delete-asset")
|
|
13342
|
+
.argument("<asset>", "Asset mint public key", utils_1.validatePublicKey)
|
|
13343
|
+
.description("Delete an asset from allowlist")
|
|
13344
|
+
.action(async (asset) => {
|
|
13345
|
+
const state = await context.glamClient.fetchStateAccount();
|
|
13346
|
+
if (asset.equals(state.baseAssetMint)) {
|
|
13347
|
+
console.error("Base asset should not be deleted from allowlist");
|
|
13348
|
+
process.exit(1);
|
|
13349
|
+
}
|
|
13350
|
+
const assetsSet = new glam_sdk_1.PkSet(state.assets);
|
|
13351
|
+
let removed = assetsSet.delete(asset);
|
|
13352
|
+
if (!removed) {
|
|
13353
|
+
console.error(`${asset} not found in allowlist, nothing to delete`);
|
|
13354
|
+
process.exit(1);
|
|
13355
|
+
}
|
|
13356
|
+
const assets = Array.from(assetsSet);
|
|
13357
|
+
const txSig = await context.glamClient.state.update({ assets }, context.txOptions);
|
|
13358
|
+
console.log(`Deleted asset ${asset} from allowlist: ${txSig}`);
|
|
13359
|
+
});
|
|
13298
13360
|
program
|
|
13299
13361
|
.command("holdings")
|
|
13300
13362
|
.description("Get vault holdings")
|
|
@@ -13642,15 +13704,21 @@ function installCctpCommands(program, context) {
|
|
|
13642
13704
|
.option("-n, --nonce <nonce>", "Nonce hex string (start with 0x)")
|
|
13643
13705
|
.description("Receive USDC from an EVM chain. Either txHash or nonce is required.")
|
|
13644
13706
|
.action(async (sourceDomain, { txHash, nonce }) => {
|
|
13645
|
-
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
|
|
13707
|
+
try {
|
|
13708
|
+
await context.glamClient.cctp.receiveUsdc(sourceDomain, {
|
|
13709
|
+
txHash,
|
|
13710
|
+
nonce,
|
|
13711
|
+
}, {
|
|
13712
|
+
...context.txOptions,
|
|
13713
|
+
lookupTables: [
|
|
13714
|
+
new web3_js_1.PublicKey("qj4EYgsGpnRdt9rvQW3wWZR8JVaKPg9rG9EB8DNgfz8"), // CCTP lookup table
|
|
13715
|
+
],
|
|
13716
|
+
});
|
|
13717
|
+
}
|
|
13718
|
+
catch (e) {
|
|
13719
|
+
console.error((0, utils_1.parseTxError)(e));
|
|
13720
|
+
process.exit(1);
|
|
13721
|
+
}
|
|
13654
13722
|
});
|
|
13655
13723
|
program
|
|
13656
13724
|
.command("list")
|
|
@@ -14082,7 +14150,7 @@ program
|
|
|
14082
14150
|
initialize(config, skipSimulation);
|
|
14083
14151
|
await (0, idl_1.idlCheck)(context.glamClient);
|
|
14084
14152
|
})
|
|
14085
|
-
.version("1.0.3-alpha.
|
|
14153
|
+
.version("1.0.3-alpha.5");
|
|
14086
14154
|
program
|
|
14087
14155
|
.command("env")
|
|
14088
14156
|
.description("Display current environment setup")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glamsystems/glam-cli",
|
|
3
|
-
"version": "1.0.3-alpha.
|
|
3
|
+
"version": "1.0.3-alpha.5",
|
|
4
4
|
"description": "CLI for interacting with the GLAM Protocol",
|
|
5
5
|
"main": "./main.js",
|
|
6
6
|
"bin": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"node": ">=20.18.0"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@glamsystems/glam-sdk": "1.0.3-alpha.
|
|
24
|
+
"@glamsystems/glam-sdk": "1.0.3-alpha.5",
|
|
25
25
|
"@switchboard-xyz/common": "^3.0.0",
|
|
26
26
|
"commander": "^11.1.0",
|
|
27
27
|
"decimal.js": "^10.6.0",
|