@glamsystems/glam-cli 0.1.33 → 0.1.35
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 +284 -51
- package/package.json +2 -2
package/main.js
CHANGED
|
@@ -275,12 +275,15 @@ class StateModel extends StateIdlModel {
|
|
|
275
275
|
// @ts-ignore
|
|
276
276
|
const value = Object.values(param.value)[0].val;
|
|
277
277
|
// Ledger is a mint param but we store it on the state model
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
278
|
+
if (name === "ledger") {
|
|
279
|
+
stateModel["ledger"] = value;
|
|
280
|
+
}
|
|
281
|
+
else if (name === "redemptionNotifyAndSettle") {
|
|
282
|
+
mintIdlModel["notifyAndSettle"] = value;
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
mintIdlModel[name] = value;
|
|
282
286
|
}
|
|
283
|
-
mintIdlModel[name] = value;
|
|
284
287
|
});
|
|
285
288
|
if (openfundsMetadataAccount) {
|
|
286
289
|
const mintOpenfundsFields = {};
|
|
@@ -763,7 +766,7 @@ const blockhash_1 = __webpack_require__(20);
|
|
|
763
766
|
const glamPDAs_1 = __webpack_require__(21);
|
|
764
767
|
const DEFAULT_PRIORITY_FEE = 10000; // microLamports
|
|
765
768
|
const LOOKUP_TABLES = [
|
|
766
|
-
new web3_js_1.PublicKey("284iwGtA9X9aLy3KsyV8uT2pXLARhYbiSi5SiM2g47M2"), // kamino
|
|
769
|
+
new web3_js_1.PublicKey("284iwGtA9X9aLy3KsyV8uT2pXLARhYbiSi5SiM2g47M2"), // kamino lending
|
|
767
770
|
new web3_js_1.PublicKey("D9cnvzswDikQDf53k4HpQ3KJ9y1Fv3HGGDFYMXnK5T6c"), // drift
|
|
768
771
|
new web3_js_1.PublicKey("EiWSskK5HXnBTptiS5DH6gpAJRVNQ3cAhTKBGaiaysAb"), // drift
|
|
769
772
|
];
|
|
@@ -1353,6 +1356,7 @@ exports.BaseClient = BaseClient;
|
|
|
1353
1356
|
|
|
1354
1357
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
1355
1358
|
exports.setsAreEqual = exports.getSimulationResult = exports.parseMeteoraPosition = exports.fetchMeteoraPositions = exports.getStakeAccountsWithStates = exports.findStakeAccounts = void 0;
|
|
1359
|
+
exports.getProgramAccountsV2 = getProgramAccountsV2;
|
|
1356
1360
|
exports.getTokenAccountsByOwner = getTokenAccountsByOwner;
|
|
1357
1361
|
exports.getSolAndTokenBalances = getSolAndTokenBalances;
|
|
1358
1362
|
exports.parseProgramLogs = parseProgramLogs;
|
|
@@ -1362,6 +1366,78 @@ const dlmm_1 = __webpack_require__(15);
|
|
|
1362
1366
|
const anchor_1 = __webpack_require__(4);
|
|
1363
1367
|
const glamExports_1 = __webpack_require__(3);
|
|
1364
1368
|
const spl_token_1 = __webpack_require__(8);
|
|
1369
|
+
// Example response from Helius:
|
|
1370
|
+
// {
|
|
1371
|
+
// "jsonrpc": "2.0",
|
|
1372
|
+
// "id": "1",
|
|
1373
|
+
// "result": {
|
|
1374
|
+
// "accounts": [
|
|
1375
|
+
// {
|
|
1376
|
+
// "pubkey": "CxELquR1gPP8wHe33gZ4QxqGB3sZ9RSwsJ2KshVewkFY",
|
|
1377
|
+
// "account": {
|
|
1378
|
+
// "lamports": 15298080,
|
|
1379
|
+
// "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
|
|
1380
|
+
// "data": [
|
|
1381
|
+
// "2R9jLfiAQ9bgdcw6h8s44439",
|
|
1382
|
+
// "base64"
|
|
1383
|
+
// ],
|
|
1384
|
+
// "executable": false,
|
|
1385
|
+
// "rentEpoch": 28,
|
|
1386
|
+
// "space": 165
|
|
1387
|
+
// }
|
|
1388
|
+
// }
|
|
1389
|
+
// ],
|
|
1390
|
+
// "paginationKey": "8WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
|
|
1391
|
+
// "totalResults": 25000
|
|
1392
|
+
// }
|
|
1393
|
+
// }
|
|
1394
|
+
async function getProgramAccountsV2(programId, limit = 100, filters) {
|
|
1395
|
+
const heliusApiKey = process.env.NEXT_PUBLIC_HELIUS_API_KEY || process.env.HELIUS_API_KEY;
|
|
1396
|
+
let allAccounts = [];
|
|
1397
|
+
let paginationKey = null;
|
|
1398
|
+
let encoding = "base64";
|
|
1399
|
+
do {
|
|
1400
|
+
const response = await fetch(`https://mainnet.helius-rpc.com/?api-key=${heliusApiKey}`, {
|
|
1401
|
+
method: "POST",
|
|
1402
|
+
headers: { "Content-Type": "application/json" },
|
|
1403
|
+
body: JSON.stringify({
|
|
1404
|
+
jsonrpc: "2.0",
|
|
1405
|
+
id: "1",
|
|
1406
|
+
method: "getProgramAccountsV2",
|
|
1407
|
+
params: [
|
|
1408
|
+
programId.toBase58(),
|
|
1409
|
+
{
|
|
1410
|
+
encoding,
|
|
1411
|
+
filters,
|
|
1412
|
+
limit,
|
|
1413
|
+
...(paginationKey && { paginationKey }),
|
|
1414
|
+
},
|
|
1415
|
+
],
|
|
1416
|
+
}),
|
|
1417
|
+
});
|
|
1418
|
+
const data = await response.json();
|
|
1419
|
+
data.result.accounts.forEach(({ pubkey, account }) => {
|
|
1420
|
+
const [acountData, encoding] = account.data;
|
|
1421
|
+
let decodedData;
|
|
1422
|
+
if (encoding === "base64") {
|
|
1423
|
+
decodedData = Buffer.from(acountData, "base64");
|
|
1424
|
+
}
|
|
1425
|
+
if (!decodedData) {
|
|
1426
|
+
throw new Error("Failed to decode base64 account data");
|
|
1427
|
+
}
|
|
1428
|
+
allAccounts.push({
|
|
1429
|
+
pubkey: new web3_js_1.PublicKey(pubkey),
|
|
1430
|
+
account: {
|
|
1431
|
+
...account,
|
|
1432
|
+
owner: new web3_js_1.PublicKey(account.owner),
|
|
1433
|
+
data: decodedData,
|
|
1434
|
+
},
|
|
1435
|
+
});
|
|
1436
|
+
});
|
|
1437
|
+
paginationKey = data.result.paginationKey;
|
|
1438
|
+
} while (paginationKey);
|
|
1439
|
+
return allAccounts;
|
|
1440
|
+
}
|
|
1365
1441
|
/**
|
|
1366
1442
|
* Fetches all the token accounts owned by the specified pubkey.
|
|
1367
1443
|
*/
|
|
@@ -5823,7 +5899,6 @@ class MintClient {
|
|
|
5823
5899
|
});
|
|
5824
5900
|
}
|
|
5825
5901
|
async update(mintModel, txOptions = {}) {
|
|
5826
|
-
// @ts-ignore
|
|
5827
5902
|
const tx = await this.base.program.methods
|
|
5828
5903
|
.updateMint(0, new models_1.MintIdlModel(mintModel))
|
|
5829
5904
|
.accounts({
|
|
@@ -5856,6 +5931,19 @@ class MintClient {
|
|
|
5856
5931
|
const vTx = await this.base.intoVersionedTransaction(tx, txOptions);
|
|
5857
5932
|
return await this.base.sendAndConfirm(vTx);
|
|
5858
5933
|
}
|
|
5934
|
+
async setPermissionlessFulfill(enabled, txOptions = {}) {
|
|
5935
|
+
const stateModel = await this.base.fetchStateModel();
|
|
5936
|
+
const notifyAndSettle = stateModel.mints?.[0]?.notifyAndSettle;
|
|
5937
|
+
if (!notifyAndSettle) {
|
|
5938
|
+
throw new Error("Mint does not have notifyAndSettle configured.");
|
|
5939
|
+
}
|
|
5940
|
+
return await this.update({
|
|
5941
|
+
notifyAndSettle: {
|
|
5942
|
+
...notifyAndSettle,
|
|
5943
|
+
permissionlessFulfillment: enabled,
|
|
5944
|
+
},
|
|
5945
|
+
}, txOptions);
|
|
5946
|
+
}
|
|
5859
5947
|
async closeMintIx() {
|
|
5860
5948
|
return await this.base.program.methods
|
|
5861
5949
|
.closeMint(0)
|
|
@@ -6087,6 +6175,7 @@ const borsh = tslib_1.__importStar(__webpack_require__(25));
|
|
|
6087
6175
|
const spl_token_1 = __webpack_require__(8);
|
|
6088
6176
|
const constants_1 = __webpack_require__(10);
|
|
6089
6177
|
const kaminoLayouts_1 = __webpack_require__(36);
|
|
6178
|
+
const helpers_1 = __webpack_require__(14);
|
|
6090
6179
|
const DEFAULT_OBLIGATION_ARGS = { tag: 0, id: 0 };
|
|
6091
6180
|
const EVENT_AUTHORITY = new web3_js_1.PublicKey("24tHwQyJJ9akVXxnvkekGfAoeUJXXS7mE6kQNioNySsK");
|
|
6092
6181
|
class KaminoLendingClient {
|
|
@@ -6496,7 +6585,6 @@ class KaminoLendingClient {
|
|
|
6496
6585
|
const vault = this.base.vaultPda;
|
|
6497
6586
|
const userMetadata = this.getUserMetadataPda(vault);
|
|
6498
6587
|
const lookupTable = new web3_js_1.PublicKey(0); // FIXME: create lookup table
|
|
6499
|
-
// @ts-ignore
|
|
6500
6588
|
const tx = await this.base.program.methods
|
|
6501
6589
|
.kaminoLendingInitUserMetadata(lookupTable)
|
|
6502
6590
|
.accounts({
|
|
@@ -6553,7 +6641,7 @@ class KaminoLendingClient {
|
|
|
6553
6641
|
const obligationFarmAccount = await this.base.provider.connection.getAccountInfo(obligationFarm);
|
|
6554
6642
|
if (!obligationFarmAccount) {
|
|
6555
6643
|
preInstructions.push(await this.base.program.methods
|
|
6556
|
-
.kaminoLendingInitObligationFarmsForReserve(0) //
|
|
6644
|
+
.kaminoLendingInitObligationFarmsForReserve(0) // 0 - collateral farm
|
|
6557
6645
|
.accounts({
|
|
6558
6646
|
glamState: this.base.statePda,
|
|
6559
6647
|
glamSigner,
|
|
@@ -6591,7 +6679,8 @@ class KaminoLendingClient {
|
|
|
6591
6679
|
postInstructions.push(...ixs); // farms must be refreshed after deposit
|
|
6592
6680
|
}
|
|
6593
6681
|
// If deposit asset is WSOL, wrap SOL first in case vault doesn't have enough wSOL
|
|
6594
|
-
const
|
|
6682
|
+
const { tokenProgram } = await this.base.fetchMintAndTokenProgram(asset);
|
|
6683
|
+
const userSourceLiquidity = this.base.getVaultAta(asset, tokenProgram);
|
|
6595
6684
|
if (asset.equals(constants_1.WSOL)) {
|
|
6596
6685
|
const wrapSolIxs = await this.base.maybeWrapSol(amount);
|
|
6597
6686
|
preInstructions.unshift(...wrapSolIxs);
|
|
@@ -6609,7 +6698,6 @@ class KaminoLendingClient {
|
|
|
6609
6698
|
postInstructions.push(closeIx);
|
|
6610
6699
|
}
|
|
6611
6700
|
}
|
|
6612
|
-
// @ts-ignore
|
|
6613
6701
|
const tx = await this.base.program.methods
|
|
6614
6702
|
.kaminoLendingDepositReserveLiquidityAndObligationCollateralV2(amount)
|
|
6615
6703
|
.accounts({
|
|
@@ -6626,7 +6714,7 @@ class KaminoLendingClient {
|
|
|
6626
6714
|
userSourceLiquidity,
|
|
6627
6715
|
placeholderUserDestinationCollateral: constants_1.KAMINO_LENDING_PROGRAM,
|
|
6628
6716
|
collateralTokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
6629
|
-
liquidityTokenProgram:
|
|
6717
|
+
liquidityTokenProgram: tokenProgram,
|
|
6630
6718
|
instructionSysvarAccount: web3_js_1.SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
6631
6719
|
obligationFarmUserState: obligationFarm,
|
|
6632
6720
|
reserveFarmState: depositReserve.farmCollateral,
|
|
@@ -6652,7 +6740,7 @@ class KaminoLendingClient {
|
|
|
6652
6740
|
const obligationFarmAccount = await this.base.provider.connection.getAccountInfo(obligationFarm);
|
|
6653
6741
|
if (!obligationFarmAccount) {
|
|
6654
6742
|
preInstructions.push(await this.base.program.methods
|
|
6655
|
-
.kaminoLendingInitObligationFarmsForReserve(0) //
|
|
6743
|
+
.kaminoLendingInitObligationFarmsForReserve(0) // 0 - collateral farm
|
|
6656
6744
|
.accounts({
|
|
6657
6745
|
glamState: this.base.statePda,
|
|
6658
6746
|
glamSigner,
|
|
@@ -6690,8 +6778,9 @@ class KaminoLendingClient {
|
|
|
6690
6778
|
postInstructions.push(...ixs); // farms must be refreshed after withdraw
|
|
6691
6779
|
}
|
|
6692
6780
|
// Create asset ATA in case it doesn't exist. Add it to the beginning of preInstructions
|
|
6693
|
-
const
|
|
6694
|
-
const
|
|
6781
|
+
const { tokenProgram } = await this.base.fetchMintAndTokenProgram(asset);
|
|
6782
|
+
const userDestinationLiquidity = this.base.getVaultAta(asset, tokenProgram);
|
|
6783
|
+
const createAtaIx = (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(glamSigner, userDestinationLiquidity, vault, asset, tokenProgram);
|
|
6695
6784
|
preInstructions.unshift(createAtaIx);
|
|
6696
6785
|
const withdrawIx = await this.base.program.methods
|
|
6697
6786
|
.kaminoLendingWithdrawObligationCollateralAndRedeemReserveCollateralV2(amount)
|
|
@@ -6709,12 +6798,19 @@ class KaminoLendingClient {
|
|
|
6709
6798
|
userDestinationLiquidity,
|
|
6710
6799
|
placeholderUserDestinationCollateral: null,
|
|
6711
6800
|
collateralTokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
6712
|
-
liquidityTokenProgram:
|
|
6801
|
+
liquidityTokenProgram: tokenProgram,
|
|
6713
6802
|
instructionSysvarAccount: web3_js_1.SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
6714
6803
|
obligationFarmUserState: obligationFarm,
|
|
6715
6804
|
reserveFarmState: withdrawReserve.farmCollateral,
|
|
6716
6805
|
farmsProgram: constants_1.KAMINO_FARM_PROGRAM,
|
|
6717
6806
|
})
|
|
6807
|
+
.remainingAccounts([
|
|
6808
|
+
{
|
|
6809
|
+
pubkey: web3_js_1.SystemProgram.programId,
|
|
6810
|
+
isSigner: false,
|
|
6811
|
+
isWritable: false,
|
|
6812
|
+
},
|
|
6813
|
+
])
|
|
6718
6814
|
.instruction();
|
|
6719
6815
|
// The final instructions in the tx:
|
|
6720
6816
|
// - refreshReserve * N
|
|
@@ -6741,7 +6837,7 @@ class KaminoLendingClient {
|
|
|
6741
6837
|
const obligationFarmAccount = await this.base.provider.connection.getAccountInfo(obligationFarm);
|
|
6742
6838
|
if (!obligationFarmAccount) {
|
|
6743
6839
|
preInstructions.push(await this.base.program.methods
|
|
6744
|
-
.kaminoLendingInitObligationFarmsForReserve(
|
|
6840
|
+
.kaminoLendingInitObligationFarmsForReserve(1) // 1 - debt farm
|
|
6745
6841
|
.accounts({
|
|
6746
6842
|
glamState: this.base.statePda,
|
|
6747
6843
|
glamSigner,
|
|
@@ -6784,8 +6880,9 @@ class KaminoLendingClient {
|
|
|
6784
6880
|
}
|
|
6785
6881
|
*/
|
|
6786
6882
|
// Create asset ATA in case it doesn't exist. Add it to the beginning of preInstructions
|
|
6787
|
-
const
|
|
6788
|
-
const
|
|
6883
|
+
const { tokenProgram } = await this.base.fetchMintAndTokenProgram(asset);
|
|
6884
|
+
const userDestinationLiquidity = this.base.getVaultAta(asset, tokenProgram);
|
|
6885
|
+
const createAtaIx = (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(glamSigner, userDestinationLiquidity, vault, asset, tokenProgram);
|
|
6789
6886
|
preInstructions.unshift(createAtaIx);
|
|
6790
6887
|
const borrowIx = await this.base.program.methods
|
|
6791
6888
|
.kaminoLendingBorrowObligationLiquidityV2(amount)
|
|
@@ -6802,7 +6899,7 @@ class KaminoLendingClient {
|
|
|
6802
6899
|
userDestinationLiquidity,
|
|
6803
6900
|
referrerTokenState: null,
|
|
6804
6901
|
instructionSysvarAccount: web3_js_1.SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
6805
|
-
tokenProgram
|
|
6902
|
+
tokenProgram,
|
|
6806
6903
|
obligationFarmUserState: obligationFarm,
|
|
6807
6904
|
reserveFarmState: borrowReserve.farmDebt,
|
|
6808
6905
|
farmsProgram: constants_1.KAMINO_FARM_PROGRAM,
|
|
@@ -6830,7 +6927,7 @@ class KaminoLendingClient {
|
|
|
6830
6927
|
const obligationFarmAccount = await this.base.provider.connection.getAccountInfo(obligationFarm);
|
|
6831
6928
|
if (!obligationFarmAccount) {
|
|
6832
6929
|
preInstructions.push(await this.base.program.methods
|
|
6833
|
-
.kaminoLendingInitObligationFarmsForReserve(
|
|
6930
|
+
.kaminoLendingInitObligationFarmsForReserve(1) // 1 - debt farm
|
|
6834
6931
|
.accounts({
|
|
6835
6932
|
glamState: this.base.statePda,
|
|
6836
6933
|
glamSigner,
|
|
@@ -6862,6 +6959,7 @@ class KaminoLendingClient {
|
|
|
6862
6959
|
obligation,
|
|
6863
6960
|
reserves: reservesInUse,
|
|
6864
6961
|
}));
|
|
6962
|
+
const { tokenProgram } = await this.base.fetchMintAndTokenProgram(asset);
|
|
6865
6963
|
const repayIx = await this.base.program.methods
|
|
6866
6964
|
.kaminoLendingRepayObligationLiquidityV2(amount)
|
|
6867
6965
|
.accounts({
|
|
@@ -6873,9 +6971,9 @@ class KaminoLendingClient {
|
|
|
6873
6971
|
repayReserve: repayReserve.address,
|
|
6874
6972
|
reserveLiquidityMint: asset,
|
|
6875
6973
|
reserveDestinationLiquidity: repayReserve.liquiditySupplyVault,
|
|
6876
|
-
userSourceLiquidity: this.base.getVaultAta(asset),
|
|
6974
|
+
userSourceLiquidity: this.base.getVaultAta(asset, tokenProgram),
|
|
6877
6975
|
instructionSysvarAccount: web3_js_1.SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
6878
|
-
tokenProgram
|
|
6976
|
+
tokenProgram,
|
|
6879
6977
|
obligationFarmUserState: obligationFarm,
|
|
6880
6978
|
reserveFarmState: repayReserve.farmDebt,
|
|
6881
6979
|
farmsProgram: constants_1.KAMINO_FARM_PROGRAM,
|
|
@@ -6898,19 +6996,30 @@ class KaminoFarmClient {
|
|
|
6898
6996
|
this.farmVaultsAuthority = (farm) => web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("authority"), farm.toBuffer()], constants_1.KAMINO_FARM_PROGRAM)[0];
|
|
6899
6997
|
this.rewardsTreasuryVault = (globalConfig, mint) => web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("tvault"), globalConfig.toBuffer(), mint.toBuffer()], constants_1.KAMINO_FARM_PROGRAM)[0];
|
|
6900
6998
|
}
|
|
6901
|
-
async
|
|
6902
|
-
const accounts = await
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6999
|
+
async findAndParseUserStates(owner) {
|
|
7000
|
+
const accounts = await (0, helpers_1.getProgramAccountsV2)(constants_1.KAMINO_FARM_PROGRAM, 10, [
|
|
7001
|
+
{ dataSize: 920 },
|
|
7002
|
+
{ memcmp: { offset: 48, bytes: owner.toBase58() } },
|
|
7003
|
+
]);
|
|
7004
|
+
return accounts.map(({ pubkey, account }) => {
|
|
7005
|
+
// farmState: [16, 48]
|
|
7006
|
+
// owner: [48, 80]
|
|
7007
|
+
// isFarmDelegated + padding: [80, 88]
|
|
7008
|
+
// rewardsTallyScaled: [88, 248]
|
|
7009
|
+
// unclaimedRewards[0..10]: [248, 328]
|
|
7010
|
+
const farmState = new web3_js_1.PublicKey(account.data.subarray(16, 48));
|
|
7011
|
+
const rewardsOffset = 248;
|
|
7012
|
+
const numRewards = 10;
|
|
7013
|
+
const rewardSize = 8;
|
|
7014
|
+
const rewardsData = account.data.subarray(rewardsOffset, rewardsOffset + numRewards * rewardSize);
|
|
7015
|
+
const unclaimedRewards = Array.from({ length: numRewards }, (_, i) => {
|
|
7016
|
+
const rewardData = rewardsData.subarray(i * rewardSize, (i + 1) * rewardSize);
|
|
7017
|
+
return new anchor_1.BN(rewardData, "le");
|
|
7018
|
+
});
|
|
6911
7019
|
return {
|
|
6912
|
-
|
|
7020
|
+
userState: pubkey,
|
|
6913
7021
|
farmState,
|
|
7022
|
+
unclaimedRewards,
|
|
6914
7023
|
};
|
|
6915
7024
|
});
|
|
6916
7025
|
}
|
|
@@ -6965,22 +7074,25 @@ class KaminoFarmClient {
|
|
|
6965
7074
|
}
|
|
6966
7075
|
async harvestTx(txOptions = {}) {
|
|
6967
7076
|
const glamSigner = txOptions.signer || this.base.getSigner();
|
|
6968
|
-
const
|
|
6969
|
-
const farmStates = await this.findAndParseFarmStates(vault);
|
|
7077
|
+
const farmStates = await this.findAndParseUserStates(this.base.vaultPda);
|
|
6970
7078
|
const parsedFarms = await this.fetchAndParseFarms(farmStates.map((f) => f.farmState));
|
|
6971
7079
|
const tx = new web3_js_1.Transaction();
|
|
6972
|
-
|
|
7080
|
+
console.log("Building transaction to harvest the following rewards:");
|
|
7081
|
+
for (const { userState, farmState, unclaimedRewards } of farmStates) {
|
|
6973
7082
|
const { globalConfig, rewards } = parsedFarms.get(farmState.toBase58());
|
|
6974
7083
|
for (const { index, mint, tokenProgram, rewardsVault } of rewards) {
|
|
6975
|
-
|
|
7084
|
+
if (unclaimedRewards[index].eq(new anchor_1.BN(0))) {
|
|
7085
|
+
continue;
|
|
7086
|
+
}
|
|
7087
|
+
console.log(`userState: ${userState}, farmState: ${farmState}, unclaimedReward: ${unclaimedRewards[index]}, token: ${mint}`);
|
|
6976
7088
|
const vaultAta = this.base.getVaultAta(mint, tokenProgram);
|
|
6977
|
-
const createAtaIx = (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(glamSigner, vaultAta,
|
|
7089
|
+
const createAtaIx = (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(glamSigner, vaultAta, this.base.vaultPda, mint, tokenProgram);
|
|
6978
7090
|
const harvestIx = await this.base.program.methods
|
|
6979
7091
|
.kaminoFarmHarvestReward(new anchor_1.BN(index))
|
|
6980
7092
|
.accounts({
|
|
6981
7093
|
glamState: this.base.statePda,
|
|
6982
7094
|
glamSigner,
|
|
6983
|
-
userState
|
|
7095
|
+
userState,
|
|
6984
7096
|
farmState,
|
|
6985
7097
|
globalConfig,
|
|
6986
7098
|
rewardMint: mint,
|
|
@@ -6995,6 +7107,9 @@ class KaminoFarmClient {
|
|
|
6995
7107
|
tx.add(createAtaIx, harvestIx);
|
|
6996
7108
|
}
|
|
6997
7109
|
}
|
|
7110
|
+
if (tx.instructions.length === 0) {
|
|
7111
|
+
throw new Error("No rewards to harvest");
|
|
7112
|
+
}
|
|
6998
7113
|
const vTx = await this.base.intoVersionedTransaction(tx, txOptions);
|
|
6999
7114
|
return vTx;
|
|
7000
7115
|
}
|
|
@@ -7495,16 +7610,48 @@ class InvestClient {
|
|
|
7495
7610
|
constructor(base) {
|
|
7496
7611
|
this.base = base;
|
|
7497
7612
|
}
|
|
7613
|
+
/**
|
|
7614
|
+
* Subscribe to a tokenized vault
|
|
7615
|
+
*
|
|
7616
|
+
* @param asset Deposit asset
|
|
7617
|
+
* @param amount
|
|
7618
|
+
* @param mintId
|
|
7619
|
+
* @param queued by default false, set to true to subscribe in queued mode
|
|
7620
|
+
* @param txOptions
|
|
7621
|
+
* @returns
|
|
7622
|
+
*/
|
|
7498
7623
|
async subscribe(asset, amount, mintId = 0, queued = false, txOptions = {}) {
|
|
7499
7624
|
const tx = await (queued
|
|
7500
7625
|
? this.queuedSubscribeTx(asset, amount, mintId, txOptions)
|
|
7501
7626
|
: this.subscribeTx(asset, amount, mintId, txOptions));
|
|
7502
7627
|
return await this.base.sendAndConfirm(tx);
|
|
7503
7628
|
}
|
|
7629
|
+
/**
|
|
7630
|
+
* Request to redeem share tokens of a tokenized vault in queued mode
|
|
7631
|
+
*
|
|
7632
|
+
* @param amount
|
|
7633
|
+
* @param mintId
|
|
7634
|
+
* @param txOptions
|
|
7635
|
+
* @returns
|
|
7636
|
+
*/
|
|
7504
7637
|
async queuedRedeem(amount, mintId = 0, txOptions = {}) {
|
|
7505
7638
|
const tx = await this.queuedRedeemTx(amount, mintId, txOptions);
|
|
7506
7639
|
return await this.base.sendAndConfirm(tx);
|
|
7507
7640
|
}
|
|
7641
|
+
/**
|
|
7642
|
+
* Redeem share tokens of a tokenized vault instantly. Preconditions:
|
|
7643
|
+
* 1. The vault must allow permissionless fulfillment
|
|
7644
|
+
* 2. The vault must have sufficient liquidity
|
|
7645
|
+
*
|
|
7646
|
+
* @param amount
|
|
7647
|
+
* @param mintId
|
|
7648
|
+
* @param txOptions
|
|
7649
|
+
* @returns
|
|
7650
|
+
*/
|
|
7651
|
+
async instantRedeem(amount, mintId = 0, txOptions = {}) {
|
|
7652
|
+
const tx = await this.instantRedeemTx(amount, mintId, txOptions);
|
|
7653
|
+
return await this.base.sendAndConfirm(tx);
|
|
7654
|
+
}
|
|
7508
7655
|
async fulfill(mintId = 0, txOptions = {}) {
|
|
7509
7656
|
const tx = await this.fulfillTx(mintId, txOptions);
|
|
7510
7657
|
return await this.base.sendAndConfirm(tx);
|
|
@@ -7554,7 +7701,6 @@ class InvestClient {
|
|
|
7554
7701
|
signerPolicy = (0, glamPDAs_1.getAccountPolicyPda)(this.base.getMintAta(signer));
|
|
7555
7702
|
console.log(`signerPolicy: ${signerPolicy} for signer ${signer} and token account ${mintTo}`);
|
|
7556
7703
|
}
|
|
7557
|
-
// @ts-ignore
|
|
7558
7704
|
const tx = await this.base.program.methods
|
|
7559
7705
|
.subscribe(0, amount)
|
|
7560
7706
|
.accounts({
|
|
@@ -7608,6 +7754,67 @@ class InvestClient {
|
|
|
7608
7754
|
.transaction();
|
|
7609
7755
|
return await this.base.intoVersionedTransaction(tx, txOptions);
|
|
7610
7756
|
}
|
|
7757
|
+
async instantRedeemTx(amount, mintId = 0, txOptions = {}) {
|
|
7758
|
+
if (mintId !== 0) {
|
|
7759
|
+
throw new Error("mintId must be 0");
|
|
7760
|
+
}
|
|
7761
|
+
// Instant redemption flow is realized by enqueueing a redemption, fulfilling it, and then claiming the tokens in a single transaction.
|
|
7762
|
+
const preInstructions = txOptions.preInstructions || [];
|
|
7763
|
+
const signer = txOptions.signer || this.base.getSigner();
|
|
7764
|
+
const glamMint = this.base.mintPda;
|
|
7765
|
+
const stateModel = await this.base.fetchStateModel();
|
|
7766
|
+
const baseAsset = stateModel.baseAsset;
|
|
7767
|
+
const signerAta = this.base.getAta(baseAsset, signer);
|
|
7768
|
+
const fulfillIx = await this.base.program.methods
|
|
7769
|
+
.fulfill(mintId)
|
|
7770
|
+
.accounts({
|
|
7771
|
+
glamState: this.base.statePda,
|
|
7772
|
+
glamMint,
|
|
7773
|
+
signer,
|
|
7774
|
+
asset: baseAsset,
|
|
7775
|
+
depositTokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
7776
|
+
})
|
|
7777
|
+
.instruction();
|
|
7778
|
+
preInstructions.push((0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(signer, signerAta, signer, baseAsset));
|
|
7779
|
+
const claimIx = await this.base.program.methods
|
|
7780
|
+
.claim(0)
|
|
7781
|
+
.accounts({
|
|
7782
|
+
glamState: this.base.statePda,
|
|
7783
|
+
signer,
|
|
7784
|
+
tokenMint: baseAsset,
|
|
7785
|
+
claimTokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
7786
|
+
})
|
|
7787
|
+
.instruction();
|
|
7788
|
+
const remainingAccounts = [];
|
|
7789
|
+
if (await this.base.isLockupEnabled()) {
|
|
7790
|
+
const extraMetasAccount = this.base.extraMetasPda;
|
|
7791
|
+
const signerPolicy = (0, glamPDAs_1.getAccountPolicyPda)(this.base.getMintAta(signer));
|
|
7792
|
+
const escrow = this.base.escrowPda;
|
|
7793
|
+
const escrowPolicy = (0, glamPDAs_1.getAccountPolicyPda)(this.base.getMintAta(escrow));
|
|
7794
|
+
remainingAccounts.push(...[
|
|
7795
|
+
extraMetasAccount,
|
|
7796
|
+
signerPolicy,
|
|
7797
|
+
escrowPolicy,
|
|
7798
|
+
constants_1.TRANSFER_HOOK_PROGRAM,
|
|
7799
|
+
]);
|
|
7800
|
+
}
|
|
7801
|
+
const tx = await this.base.program.methods
|
|
7802
|
+
.queuedRedeem(0, amount)
|
|
7803
|
+
.accounts({
|
|
7804
|
+
glamState: this.base.statePda,
|
|
7805
|
+
glamMint,
|
|
7806
|
+
signer,
|
|
7807
|
+
})
|
|
7808
|
+
.remainingAccounts(remainingAccounts.map((pubkey) => ({
|
|
7809
|
+
pubkey,
|
|
7810
|
+
isSigner: false,
|
|
7811
|
+
isWritable: false,
|
|
7812
|
+
})))
|
|
7813
|
+
.preInstructions(preInstructions)
|
|
7814
|
+
.postInstructions([fulfillIx, claimIx])
|
|
7815
|
+
.transaction();
|
|
7816
|
+
return await this.base.intoVersionedTransaction(tx, txOptions);
|
|
7817
|
+
}
|
|
7611
7818
|
async queuedRedeemTx(amount, mintId = 0, txOptions = {}) {
|
|
7612
7819
|
if (mintId !== 0) {
|
|
7613
7820
|
throw new Error("mintId must be 0");
|
|
@@ -8512,6 +8719,7 @@ class CliConfig {
|
|
|
8512
8719
|
}
|
|
8513
8720
|
process.env.ANCHOR_PROVIDER_URL = cliConfig.json_rpc_url;
|
|
8514
8721
|
process.env.ANCHOR_WALLET = cliConfig.keypair_path;
|
|
8722
|
+
process.env.HELIUS_API_KEY = cliConfig.priority_fee?.helius_api_key;
|
|
8515
8723
|
return cliConfig;
|
|
8516
8724
|
}
|
|
8517
8725
|
catch (err) {
|
|
@@ -10074,17 +10282,28 @@ function installInvestCommands(tokenized, glamClient, cliConfig, txOptions) {
|
|
|
10074
10282
|
});
|
|
10075
10283
|
tokenized
|
|
10076
10284
|
.command("redeem <amount>")
|
|
10285
|
+
.option("-i, --instant", "Redeem share tokens instantly", false)
|
|
10286
|
+
.option("-y, --yes", "Skip confirmation prompt", false)
|
|
10077
10287
|
.description("Request to redeem share tokens")
|
|
10078
|
-
.
|
|
10079
|
-
.action(async (amount, options) => {
|
|
10288
|
+
.action(async (amount, { instant, yes }) => {
|
|
10080
10289
|
const amountBN = new anchor_1.BN(parseFloat(amount) * web3_js_1.LAMPORTS_PER_SOL);
|
|
10081
|
-
|
|
10082
|
-
(await (0, utils_1.confirmOperation)(`Confirm queued redemption of ${amount} shares?`));
|
|
10290
|
+
yes ||
|
|
10291
|
+
(await (0, utils_1.confirmOperation)(`Confirm ${instant ? "instant" : "queued"} redemption of ${amount} shares?`));
|
|
10083
10292
|
try {
|
|
10084
|
-
|
|
10085
|
-
|
|
10086
|
-
|
|
10087
|
-
|
|
10293
|
+
let txSig;
|
|
10294
|
+
if (instant) {
|
|
10295
|
+
const preInstructions = await glamClient.price.priceVaultIxs(glam_sdk_1.PriceDenom.SOL);
|
|
10296
|
+
const lookupTables = glamClient.price.lookupTables;
|
|
10297
|
+
txSig = await glamClient.invest.instantRedeem(amountBN, 0, {
|
|
10298
|
+
...txOptions,
|
|
10299
|
+
preInstructions,
|
|
10300
|
+
lookupTables,
|
|
10301
|
+
});
|
|
10302
|
+
}
|
|
10303
|
+
else {
|
|
10304
|
+
txSig = await glamClient.invest.queuedRedeem(amountBN, 0, txOptions);
|
|
10305
|
+
}
|
|
10306
|
+
console.log(`${glamClient.signer} ${instant ? "instantly" : "queued"} redeemed:`, txSig);
|
|
10088
10307
|
}
|
|
10089
10308
|
catch (e) {
|
|
10090
10309
|
console.error((0, utils_1.parseTxError)(e));
|
|
@@ -10123,6 +10342,20 @@ function installInvestCommands(tokenized, glamClient, cliConfig, txOptions) {
|
|
|
10123
10342
|
throw e;
|
|
10124
10343
|
}
|
|
10125
10344
|
});
|
|
10345
|
+
tokenized
|
|
10346
|
+
.command("set-permissionless-fulfill")
|
|
10347
|
+
.argument("<enabled>", "Enable or disable permissionless fulfillment", (v) => v === "true" || v === "1", false)
|
|
10348
|
+
.description("Enable or disable permissionless fulfillment")
|
|
10349
|
+
.action(async (enabled) => {
|
|
10350
|
+
try {
|
|
10351
|
+
const txSig = await glamClient.mint.setPermissionlessFulfill(enabled);
|
|
10352
|
+
console.log(`Permissionless fulfillment set to ${enabled}:`, txSig);
|
|
10353
|
+
}
|
|
10354
|
+
catch (e) {
|
|
10355
|
+
console.error((0, utils_1.parseTxError)(e));
|
|
10356
|
+
process.exit(1);
|
|
10357
|
+
}
|
|
10358
|
+
});
|
|
10126
10359
|
}
|
|
10127
10360
|
|
|
10128
10361
|
|
|
@@ -10141,7 +10374,7 @@ function installAltCommands(alt, glamClient, cliConfig, txOptions = {}) {
|
|
|
10141
10374
|
.description("Create address lookup table (ALT) for the active GLAM")
|
|
10142
10375
|
.action(async () => {
|
|
10143
10376
|
try {
|
|
10144
|
-
const response = await fetch(`https://
|
|
10377
|
+
const response = await fetch(`https://api.glam.systems/v0/lut/vault/create?state=${glamClient.statePda}&payer=${glamClient.getSigner()}`);
|
|
10145
10378
|
const data = await response.json();
|
|
10146
10379
|
const table = data.tables[0];
|
|
10147
10380
|
const b64Txs = data.tx;
|
|
@@ -10633,7 +10866,7 @@ program
|
|
|
10633
10866
|
.hook("preSubcommand", async (thisCommand, actionCommand) => {
|
|
10634
10867
|
await (0, idl_1.idlCheck)(glamClient);
|
|
10635
10868
|
})
|
|
10636
|
-
.version("0.1.
|
|
10869
|
+
.version("0.1.35");
|
|
10637
10870
|
program
|
|
10638
10871
|
.command("env")
|
|
10639
10872
|
.description("Display current environment setup")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glamsystems/glam-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.35",
|
|
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": "0.1.
|
|
24
|
+
"@glamsystems/glam-sdk": "0.1.35",
|
|
25
25
|
"commander": "^11.1.0",
|
|
26
26
|
"inquirer": "^8.2.6",
|
|
27
27
|
"@switchboard-xyz/common": "^3.0.0"
|