@coral-xyz/soulbound
Version:
Node.js client for the soulbound protocol
638 lines • 31 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createStakeApi = void 0;
const anchor = __importStar(require("@coral-xyz/anchor"));
const anchor_1 = require("@coral-xyz/anchor");
const web3_js_1 = require("@solana/web3.js");
const spl_token_1 = require("@solana/spl-token");
const soulBoundAuthority_1 = require("./_idls/soulBoundAuthority");
const cardinalStakePool_1 = require("./_idls/cardinalStakePool");
const cardinalRewardDistributor_1 = require("./_idls/cardinalRewardDistributor");
const BN = anchor.BN;
function createStakeApi(PROVIDER) {
//
// Mainnet stake constants.
//
const STAKE_POOL = new web3_js_1.PublicKey("7xmGGtuNNvjKLDwbYWBYGPpAjRqftJnrTyzSRK92yku8");
//const STAKE_POOL_IDENTIFIER = new PublicKey(
//"E43L3VCJcDqN4pPhhPBiQjSr5A9cBJreTdMDVhWxXVCZ"
//);
const REWARD_DISTRIBUTOR = new web3_js_1.PublicKey("6DBnpqRm1szSz25dD1aWEmYzgGoMB59Y1GMv2gtWUSM4");
const GOLD_MINT = new web3_js_1.PublicKey("5QPAPkBvd2B7RQ6DBGvCxGdAcyWitdvRAP58CdvBiuf7");
//
// Program ids.
//
const SOUL_BOUND_PROGRAM_ID = new web3_js_1.PublicKey("7DkjPwuKxvz6Viiawtbmb4CqnMKP6eGb1WqYas1airUS");
const CARDINAL_REWARD_DISTRIBUTOR_PROGRAM_ID = new web3_js_1.PublicKey("H2yQahQ7eQH8HXXPtJSJn8MURRFEWVesTd8PsracXp1S");
const CARDINAL_STAKE_POOL_PROGRAM_ID = new web3_js_1.PublicKey("2gvBmibwtBnbkLExmgsijKy6hGXJneou8X6hkyWQvYnF");
const TOKEN_METADATA_PROGRAM_ID = new web3_js_1.PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
//
// Misc program constants.
//
const AUTHORIZATION_RULES_PROGRAM_ID = new web3_js_1.PublicKey("auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg");
const AUTHORIZATION_RULES = new web3_js_1.PublicKey("eBJLFYPxJmMGKuFwpDWkzxZeUrad92kZRC5BJLpzyT9");
//
// Stake program clients.
//
const SOUL_BOUND_PROGRAM = new anchor_1.Program(soulBoundAuthority_1.IDL, SOUL_BOUND_PROGRAM_ID, PROVIDER);
const REWARD_DISTRIBUTOR_PROGRAM = new anchor_1.Program(cardinalRewardDistributor_1.IDL, CARDINAL_REWARD_DISTRIBUTOR_PROGRAM_ID, PROVIDER);
const STAKE_POOL_PROGRAM = new anchor_1.Program(cardinalStakePool_1.IDL, CARDINAL_STAKE_POOL_PROGRAM_ID, PROVIDER);
function stake({ user, nft, stakePool = STAKE_POOL, rewardDistributor = REWARD_DISTRIBUTOR, stakePoolProgram = STAKE_POOL_PROGRAM, rewardDistributorProgram = REWARD_DISTRIBUTOR_PROGRAM, }) {
return __awaiter(this, void 0, void 0, function* () {
const tx = new web3_js_1.Transaction();
tx.add(web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
units: 1000000,
}));
tx.add(yield stakeInstruction({
user,
nft,
stakePool,
rewardDistributor,
stakePoolProgram,
rewardDistributorProgram,
}));
// @ts-ignore
return yield window.xnft.solana.send(tx);
});
}
function stakeInstruction({ user, nft, stakePool = STAKE_POOL, rewardDistributor = REWARD_DISTRIBUTOR, stakePoolProgram = STAKE_POOL_PROGRAM, rewardDistributorProgram = REWARD_DISTRIBUTOR_PROGRAM, }) {
return __awaiter(this, void 0, void 0, function* () {
const stakeEntry = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("stake-entry"),
stakePool.toBuffer(),
nft.mintAddress.toBuffer(),
getStakeSeed(1, user).toBuffer(),
], stakePoolProgram.programId)[0];
const rewardEntry = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("reward-entry"),
rewardDistributor.toBuffer(),
stakeEntry.toBuffer(),
], rewardDistributorProgram.programId)[0];
const ata = yield anchor.utils.token.associatedAddress({
mint: nft.mintAddress,
owner: user,
});
const tokenRecord = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("metadata"),
TOKEN_METADATA_PROGRAM_ID.toBuffer(),
nft.mintAddress.toBuffer(),
Buffer.from("token_record"),
ata.toBuffer(),
], TOKEN_METADATA_PROGRAM_ID)[0];
const masterEditionAddress = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("metadata"),
TOKEN_METADATA_PROGRAM_ID.toBuffer(),
nft.mintAddress.toBuffer(),
Buffer.from("edition"),
], TOKEN_METADATA_PROGRAM_ID)[0];
return yield stakePoolProgram.methods
.stakeProgrammable(new BN(1))
.accounts({
stakeEntry,
rewardEntry,
rewardDistributor,
stakePool,
originalMint: nft.mintAddress,
user,
userOriginalMintTokenAccount: ata,
userOriginalMintTokenRecord: tokenRecord,
mintMetadata: nft.metadataAddress,
mintEdition: masterEditionAddress,
authorizationRules: AUTHORIZATION_RULES,
sysvarInstructions: web3_js_1.SYSVAR_INSTRUCTIONS_PUBKEY,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
authorizationRulesProgram: AUTHORIZATION_RULES_PROGRAM_ID,
rewardDistributorProgram: rewardDistributorProgram.programId,
systemProgram: web3_js_1.SystemProgram.programId,
})
.instruction();
});
}
function unstake({ user, nft, stakePool = STAKE_POOL, stakePoolProgram = STAKE_POOL_PROGRAM, options, }) {
return __awaiter(this, void 0, void 0, function* () {
const tx = new web3_js_1.Transaction();
tx.add(...(yield claimAndUnstakeInstructions({
user,
nft,
stakePool,
stakePoolProgram,
})));
// @ts-ignore
return yield window.xnft.solana.send(tx, undefined, options);
});
}
function claimAndUnstakeInstructions({ user, nft, stakePool = STAKE_POOL, stakePoolProgram = STAKE_POOL_PROGRAM, }) {
return __awaiter(this, void 0, void 0, function* () {
const ixs = yield claimRewardInstruction({
user,
nft,
});
ixs.push(yield unstakeInstruction({
user,
nft,
stakePool,
stakePoolProgram,
}));
return ixs;
});
}
function unstakeInstruction({ user, nft, stakePool = STAKE_POOL, stakePoolProgram = STAKE_POOL_PROGRAM, }) {
return __awaiter(this, void 0, void 0, function* () {
const stakeEntry = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("stake-entry"),
stakePool.toBuffer(),
nft.mintAddress.toBuffer(),
getStakeSeed(1, user).toBuffer(),
], stakePoolProgram.programId)[0];
const ata = yield anchor.utils.token.associatedAddress({
mint: nft.mintAddress,
owner: user,
});
const tokenRecord = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("metadata"),
TOKEN_METADATA_PROGRAM_ID.toBuffer(),
nft.mintAddress.toBuffer(),
Buffer.from("token_record"),
ata.toBuffer(),
], TOKEN_METADATA_PROGRAM_ID)[0];
const masterEditionAddress = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("metadata"),
TOKEN_METADATA_PROGRAM_ID.toBuffer(),
nft.mintAddress.toBuffer(),
Buffer.from("edition"),
], TOKEN_METADATA_PROGRAM_ID)[0];
return yield stakePoolProgram.methods
.unstakeProgrammable()
.accounts({
stakeEntry,
stakePool,
originalMint: nft.mintAddress,
user,
userOriginalMintTokenAccount: ata,
userOriginalMintTokenRecord: tokenRecord,
mintMetadata: nft.metadataAddress,
mintEdition: masterEditionAddress,
authorizationRules: AUTHORIZATION_RULES,
sysvarInstructions: web3_js_1.SYSVAR_INSTRUCTIONS_PUBKEY,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
authorizationRulesProgram: AUTHORIZATION_RULES_PROGRAM_ID,
systemProgram: web3_js_1.SystemProgram.programId,
})
.instruction();
});
}
function isStaked({ user, nft, stakePool = STAKE_POOL, stakePoolProgram = STAKE_POOL_PROGRAM, }) {
return __awaiter(this, void 0, void 0, function* () {
try {
const stakeEntry = yield fetchStakeEntry({
user,
nft,
stakePool,
stakePoolProgram,
});
return stakeEntry.lastStaker.equals(user);
}
catch (err) {
// If throws, then the account probably doesn't exist.
return false;
}
});
}
const fetchStakeEntry = ({ user, nft, stakePool = STAKE_POOL, stakePoolProgram = STAKE_POOL_PROGRAM, }) => __awaiter(this, void 0, void 0, function* () {
const stakeEntry = yield stakeEntryAddress({
user,
nft,
stakePool,
stakePoolProgram,
});
return yield stakePoolProgram.account.stakeEntry.fetch(stakeEntry);
});
const stakeEntryAddress = ({ user, nft, stakePool = STAKE_POOL, stakePoolProgram = STAKE_POOL_PROGRAM, }) => __awaiter(this, void 0, void 0, function* () {
const stakeEntry = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("stake-entry"),
stakePool.toBuffer(),
nft.mintAddress.toBuffer(),
getStakeSeed(1, user).toBuffer(),
], stakePoolProgram.programId)[0];
return stakeEntry;
});
const fetchRewardEntry = ({ user, nft, stakePool = STAKE_POOL, rewardDistributor = REWARD_DISTRIBUTOR, stakePoolProgram = STAKE_POOL_PROGRAM, rewardDistributorProgram = REWARD_DISTRIBUTOR_PROGRAM, }) => __awaiter(this, void 0, void 0, function* () {
const stakeEntry = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("stake-entry"),
stakePool.toBuffer(),
nft.mintAddress.toBuffer(),
getStakeSeed(1, user).toBuffer(),
], stakePoolProgram.programId)[0];
const rewardEntry = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("reward-entry"),
rewardDistributor.toBuffer(),
stakeEntry.toBuffer(),
], rewardDistributorProgram.programId)[0];
const rewardEntryAccount = yield rewardDistributorProgram.account.rewardEntry.fetch(rewardEntry);
return rewardEntryAccount;
});
const rewardEntryAddress = ({ user, nft, stakePool = STAKE_POOL, rewardDistributor = REWARD_DISTRIBUTOR, stakePoolProgram = STAKE_POOL_PROGRAM, rewardDistributorProgram = REWARD_DISTRIBUTOR_PROGRAM, }) => __awaiter(this, void 0, void 0, function* () {
const stakeEntry = yield stakeEntryAddress({
user,
nft,
stakePool,
stakePoolProgram,
});
const rewardEntry = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("reward-entry"),
rewardDistributor.toBuffer(),
stakeEntry.toBuffer(),
], rewardDistributorProgram.programId)[0];
return rewardEntry;
});
function claimRewardInstruction({ user, nft, stakePool = STAKE_POOL, rewardDistributor = REWARD_DISTRIBUTOR, goldMint = GOLD_MINT, soulboundProgram = SOUL_BOUND_PROGRAM, stakePoolProgram = STAKE_POOL_PROGRAM, rewardDistributorProgram = REWARD_DISTRIBUTOR_PROGRAM, }) {
return __awaiter(this, void 0, void 0, function* () {
const [sbaUser] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("sba-scoped-user"), user.toBuffer()], soulboundProgram.programId);
const scopedSbaUserAuthority = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("sba-scoped-user-nft-program"),
user.toBuffer(),
nft.mintAddress.toBuffer(),
rewardDistributorProgram.programId.toBuffer(),
], soulboundProgram.programId)[0];
const stakeEntry = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("stake-entry"),
stakePool.toBuffer(),
nft.mintAddress.toBuffer(),
getStakeSeed(1, user).toBuffer(),
], stakePoolProgram.programId)[0];
const rewardEntry = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("reward-entry"),
rewardDistributor.toBuffer(),
stakeEntry.toBuffer(),
], rewardDistributorProgram.programId)[0];
const userRewardMintTokenAccount = yield (0, spl_token_1.getAssociatedTokenAddress)(goldMint, scopedSbaUserAuthority, true);
let { data, keys } = yield rewardDistributorProgram.methods
.claimRewards()
.accounts({
rewardEntry,
rewardDistributor,
stakeEntry,
stakePool,
originalMint: nft.mintAddress,
rewardMint: goldMint,
userRewardMintTokenAccount,
authority: scopedSbaUserAuthority,
user,
})
.instruction();
// Need to set the signer on the PDA to false so that we can serialize
// the transaction without error. The CPI in the program will flip this
// back to true before signging with PDA seeds.
keys = keys.map((k) => {
return Object.assign(Object.assign({}, k), { isSigner: k.pubkey.equals(scopedSbaUserAuthority) ? false : k.isSigner });
});
const nftToken = yield (0, spl_token_1.getAssociatedTokenAddress)(nft.mintAddress, user);
//
// If this is the first time using the soulbound program, then we need
// to initialize the user account.
//
const soulboundInitInstructions = yield (() => __awaiter(this, void 0, void 0, function* () {
// If the soul bound authority user is already created, do nothing.
if (yield isSoulBoundAuthorityUserInitialized(user, soulboundProgram)) {
return [];
}
// If the soulbound authority user is not yet created, then we
// need to create it before claiming a reward.
else {
__cached = null; // Wipe cache.
return [
yield soulboundProgram.methods
.createSbaUser()
.accounts({
sba: sbaUser,
authority: user,
payer: user,
})
.instruction(),
];
}
}))();
const claimIx = yield soulboundProgram.methods
.executeTxScopedUserNftProgram(data)
.accounts({
sbaUser,
nftToken,
nftMint: nft.mintAddress,
authority: user,
delegate: web3_js_1.PublicKey.default,
authorityOrDelegate: user,
scopedAuthority: scopedSbaUserAuthority,
program: rewardDistributorProgram.programId,
})
.remainingAccounts(keys)
.instruction();
const updateIx = yield stakePoolProgram.methods
.updateTotalStakeSeconds()
.accounts({
stakeEntry,
lastStaker: user,
})
.instruction();
return soulboundInitInstructions.concat([updateIx, claimIx]);
});
}
// Should invoke this method on load to slightly speed things up.
//
// Note this account can only be created; it can't be removed.
let __cached = null;
function isSoulBoundAuthorityUserInitialized(user, soulboundProgram = SOUL_BOUND_PROGRAM) {
return __awaiter(this, void 0, void 0, function* () {
const [sbaUser] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("sba-scoped-user"), user.toBuffer()], soulboundProgram.programId);
if (__cached !== null) {
return __cached;
}
try {
yield soulboundProgram.account.soulBoundAuthorityUser.fetch(sbaUser);
__cached = true;
return true;
}
catch (_a) {
__cached = false;
return false;
}
});
}
function readGoldPoints({ user, nft, goldMint = GOLD_MINT, stakePool = STAKE_POOL, rewardDistributor = REWARD_DISTRIBUTOR, soulboundProgram = SOUL_BOUND_PROGRAM, stakePoolProgram = STAKE_POOL_PROGRAM, rewardDistributorProgram = REWARD_DISTRIBUTOR_PROGRAM, accounts, }) {
return __awaiter(this, void 0, void 0, function* () {
const unclaimed = yield (() => __awaiter(this, void 0, void 0, function* () {
try {
return yield readUnclaimedGoldPoints({
user,
nft,
stakePool,
rewardDistributor,
stakePoolProgram,
rewardDistributorProgram,
accounts,
});
}
catch (_a) {
return new BN(0);
}
}))();
const claimed = yield (() => __awaiter(this, void 0, void 0, function* () {
try {
return yield readClaimedGoldPoints({
user,
nft,
goldMint,
soulboundProgram,
rewardDistributorProgram,
accounts,
});
}
catch (_b) {
return new BN(0);
}
}))();
const native = unclaimed.add(claimed);
const decimals = 0;
return native.toNumber() / Math.pow(10, decimals);
});
}
// Unclaimed gold points are calculated client side.
//
// Rant: Would be nice if the contract just had a view function so that
// we don't have to redo this logic in typescript land, but such is life.
function readUnclaimedGoldPoints({ user, nft, stakePool = STAKE_POOL, rewardDistributor = REWARD_DISTRIBUTOR, stakePoolProgram = STAKE_POOL_PROGRAM, rewardDistributorProgram = REWARD_DISTRIBUTOR_PROGRAM, accounts, }) {
return __awaiter(this, void 0, void 0, function* () {
const stakeEntryAcc = accounts
? accounts.stakeEntry
: yield fetchStakeEntry({
user,
nft,
stakePool,
stakePoolProgram,
});
const rewardEntryAcc = accounts
? accounts.rewardEntry
: yield fetchRewardEntry({
user,
nft: nft,
stakePool,
rewardDistributor,
stakePoolProgram,
rewardDistributorProgram,
});
// This means the staker unstaked.
if (stakeEntryAcc.lastStaker.equals(web3_js_1.PublicKey.default)) {
return new BN(0);
}
if (stakeEntryAcc.amount.eq(new BN(0))) {
return new BN(0);
}
const totalStakeSeconds = stakeEntryAcc.totalStakeSeconds.add(stakeEntryAcc.amount.eq(new BN(0))
? new BN(0)
: new BN(Date.now() / 1000).sub(stakeEntryAcc.lastUpdatedAt));
const rewardSecondsReceived = rewardEntryAcc.rewardSecondsReceived;
const rewardDistributorAcc = accounts
? accounts.rewardDistributor
: yield rewardDistributorProgram.account.rewardDistributor.fetch(rewardDistributor);
const rewardAmountToReceive = totalStakeSeconds
.sub(rewardSecondsReceived)
.div(rewardDistributorAcc.rewardDurationSeconds)
.mul(rewardDistributorAcc.rewardAmount)
.mul(new BN(1))
.div(new BN(10).pow(new BN(rewardDistributorAcc.multiplierDecimals)));
return rewardAmountToReceive;
});
}
// Points swept into the soulbound token account. These are soulbound to the
// user and nft (combinatino) and automatically swept during unstaking.
function readClaimedGoldPoints({ user, nft, goldMint = GOLD_MINT, soulboundProgram = SOUL_BOUND_PROGRAM, rewardDistributorProgram = REWARD_DISTRIBUTOR_PROGRAM, accounts, }) {
return __awaiter(this, void 0, void 0, function* () {
const userRewardMintTokenAccount = yield goldPointsAddress({
user,
nft,
goldMint,
soulboundProgram,
rewardDistributorProgram,
});
const claimedAmount = yield (() => __awaiter(this, void 0, void 0, function* () {
try {
const rewardTokenAccount = accounts
? accounts.goldTokenAccount
: yield (0, spl_token_1.getAccount)(soulboundProgram.provider.connection, userRewardMintTokenAccount);
return new BN(rewardTokenAccount.amount.toString());
}
catch (_a) {
return new BN(0);
}
}))();
return claimedAmount;
});
}
function goldPointsAddress({ user, nft, goldMint = GOLD_MINT, soulboundProgram = SOUL_BOUND_PROGRAM, rewardDistributorProgram = REWARD_DISTRIBUTOR_PROGRAM, }) {
return __awaiter(this, void 0, void 0, function* () {
const scopedSbaUserAuthority = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("sba-scoped-user-nft-program"),
user.toBuffer(),
nft.mintAddress.toBuffer(),
rewardDistributorProgram.programId.toBuffer(),
], soulboundProgram.programId)[0];
const userRewardMintTokenAccount = yield (0, spl_token_1.getAssociatedTokenAddress)(goldMint, scopedSbaUserAuthority, true);
return userRewardMintTokenAccount;
});
}
function transferRewards({ amount, fromUser, // fromUser should be the client payer/signer.
fromNft, toNft, goldMint = GOLD_MINT, stakePool = STAKE_POOL, rewardDistributor = REWARD_DISTRIBUTOR, soulboundProgram = SOUL_BOUND_PROGRAM, stakePoolProgram = STAKE_POOL_PROGRAM, rewardDistributorProgram = REWARD_DISTRIBUTOR_PROGRAM, }) {
return __awaiter(this, void 0, void 0, function* () {
const toUser = fromUser; // Transfers only allowed between same wallet.
const [fromSbaUser] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("sba-scoped-user"), fromUser.toBuffer()], soulboundProgram.programId);
const fromScopedSbaUserAuthority = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("sba-scoped-user-nft-program"),
fromUser.toBuffer(),
fromNft.mintAddress.toBuffer(),
rewardDistributorProgram.programId.toBuffer(),
], soulboundProgram.programId)[0];
const fromStakeEntry = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("stake-entry"),
stakePool.toBuffer(),
fromNft.mintAddress.toBuffer(),
getStakeSeed(1, fromUser).toBuffer(),
], stakePoolProgram.programId)[0];
const fromRewardEntry = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("reward-entry"),
rewardDistributor.toBuffer(),
fromStakeEntry.toBuffer(),
], rewardDistributorProgram.programId)[0];
const fromScopedSbaUserAuthorityAta = yield (0, spl_token_1.getAssociatedTokenAddress)(goldMint, fromScopedSbaUserAuthority, true);
const toScopedSbaUserAuthority = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("sba-scoped-user-nft-program"),
toUser.toBuffer(),
toNft.mintAddress.toBuffer(),
rewardDistributorProgram.programId.toBuffer(),
], soulboundProgram.programId)[0];
const toStakeEntry = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("stake-entry"),
stakePool.toBuffer(),
toNft.mintAddress.toBuffer(),
getStakeSeed(1, toUser).toBuffer(),
], stakePoolProgram.programId)[0];
const toRewardEntry = web3_js_1.PublicKey.findProgramAddressSync([
Buffer.from("reward-entry"),
rewardDistributor.toBuffer(),
toStakeEntry.toBuffer(),
], rewardDistributorProgram.programId)[0];
const toScopedSbaUserAuthorityAta = yield (0, spl_token_1.getAssociatedTokenAddress)(goldMint, toScopedSbaUserAuthority, true);
const fromNftToken = yield (0, spl_token_1.getAssociatedTokenAddress)(fromNft.mintAddress, fromUser);
let { data, keys } = yield rewardDistributorProgram.methods
.transferRewards(amount !== null && amount !== void 0 ? amount : null)
.accounts({
rewardEntryA: fromRewardEntry,
rewardEntryB: toRewardEntry,
stakeEntryA: fromStakeEntry,
stakeEntryB: toStakeEntry,
rewardDistributor,
stakePool,
originalMintA: fromNft.mintAddress,
originalMintB: toNft.mintAddress,
rewardMint: goldMint,
user: fromUser,
userRewardMintTokenAccountA: fromScopedSbaUserAuthorityAta,
userRewardMintTokenAccountB: toScopedSbaUserAuthorityAta,
authorityA: fromScopedSbaUserAuthority,
authorityB: toScopedSbaUserAuthority,
})
.instruction();
// Need to set the signer on the PDA to false so that we can serialize
// the transaction without error. The CPI in the program will flip this
// back to true before signging with PDA seeds.
keys = keys.map((k) => {
return Object.assign(Object.assign({}, k), { isSigner: k.pubkey.equals(fromScopedSbaUserAuthority)
? false
: k.isSigner });
});
const tx = yield soulboundProgram.methods
.executeTxScopedUserNftProgram(data)
.accounts({
sbaUser: fromSbaUser,
nftToken: fromNftToken,
nftMint: fromNft.mintAddress,
authority: fromUser,
delegate: web3_js_1.PublicKey.default,
authorityOrDelegate: fromUser,
scopedAuthority: fromScopedSbaUserAuthority,
program: rewardDistributorProgram.programId,
})
.remainingAccounts(keys)
.transaction();
// @ts-ignore
return yield window.xnft.solana.send(tx);
});
}
// Supply is the token supply of the nft mint.
function getStakeSeed(supply, user) {
if (supply > 1) {
return user;
}
else {
return web3_js_1.PublicKey.default;
}
}
return {
stake,
stakeInstruction,
unstake,
unstakeInstruction,
claimAndUnstakeInstructions,
isStaked,
isSoulBoundAuthorityUserInitialized,
readGoldPoints,
readUnclaimedGoldPoints,
readClaimedGoldPoints,
transferRewards,
anchor: {
soulbound: SOUL_BOUND_PROGRAM,
rewardDistributor: REWARD_DISTRIBUTOR_PROGRAM,
stakePool: STAKE_POOL_PROGRAM,
},
constants: {
REWARD_DISTRIBUTOR,
},
rewardEntryAddress,
stakeEntryAddress,
goldPointsAddress,
};
}
exports.createStakeApi = createStakeApi;
//# sourceMappingURL=index.js.map