gemworks / gem-farm

Configurable staking for NFT Projects on Solana
https://gemfarm.gg/
MIT License
338 stars 251 forks source link

combining cooldown, unstake and withdraw into a bundle tx #97

Open rashidkhokhar98 opened 2 years ago

rashidkhokhar98 commented 2 years ago

we had it working in the previous commit but now with the latest, unable to comprehend much. would be much help if someone can guide if its still possible :)

Fahad-pnw commented 2 years ago

having the same issue, anybody been able to figure?

ghost commented 2 years ago

Can someone shares some code for combining cooldown, unstake and withdraw into a bundle tx? Thanks in advance.

ghost commented 2 years ago

Thank you @johnwinsor for sharing. If one transaction with multiple istructions will be better.

ghost commented 2 years ago

Made it work with one transaction:

when you want to unske a nft, you need unstake,unstake(this is for ending the cooldown),withdraw and stake 4 instructions. but if the vault is empty, don't stake, otherwise it will give a error.

action part:

let ins1 = farmerStatus === 'unstaked' ? [] : await farmClient.insOfUnstake(farmPublicKey, farmAccount.bank, 
farmerAccount.identity, farmerAccount.vault, farmAccount.rewardA.rewardMint, farmAccount.rewardB.rewardMint);
        let ins2 = await bankClient.insOfWithdraw(farmAccount.bank, farmerAccount.vault, new solweb3.PublicKey(nft.metaOnchain.mint));
        let ins3 = stakedNfts.length === 1 ? [] : await farmClient.insOfStake(farmPublicKey, farmerAccount.identity);

        let tx = new solweb3.Transaction({
            feePayer: wallet.publicKey,
            recentBlockhash: (await connection.getRecentBlockhash()).blockhash,
        }).add(...[...ins1, ...ins2, ...ins3]);

        const signed = await wallet.signTransaction(tx)
        await connection.sendRawTransaction(signed.serialize());

In your farmClient:

async insOfUnstake(farm: solweb3.PublicKey, bank: solweb3.PublicKey, farmerIdentity: solweb3.Signer, vault: solweb3.PublicKey, rewardAMint: solweb3.PublicKey, rewardBMint: solweb3.PublicKey, willBeEmpty: boolean) {
    const identityPk: solweb3.PublicKey = farmerIdentity.publicKey ? farmerIdentity.publicKey : (farmerIdentity as any);
    try {
        const [farmer, bumpFarmer] = await findFarmerPDA(farm, identityPk);
        const [farmAuth, bumpAuth] = await findFarmAuthorityPDA(farm);
        const [farmTreasury, bumpTreasury] = await findFarmTreasuryPDA(farm);
        const endStaking = this.farmProgram.instruction.unstake(bumpAuth, bumpTreasury, bumpFarmer, false, {
            accounts: {
                farm: farm,
                farmer: farmer,
                farmTreasury: farmTreasury,
                identity: identityPk,
                bank: bank,
                vault: vault,
                farmAuthority: farmAuth,
                gemBank: this.bankProgram.programId,
                systemProgram: solweb3.SystemProgram.programId,
                feeAcc: feeAccount
            },
            signers: [],
        });

        const [potA, potABump] = await findRewardsPotPDA(farm, rewardAMint);
        const [potB, potBBump] = await findRewardsPotPDA(farm, rewardBMint);
        const rewardADestination = await this.findATA(rewardAMint, this.wallet.publicKey);
        const rewardBDestination = await this.findATA(rewardBMint, this.wallet.publicKey);
        const rewards = this.farmProgram.instruction.claim(bumpAuth, bumpFarmer, potABump, potBBump, {
            accounts: {
                farm,
                farmAuthority: farmAuth,
                farmer,
                identity: identityPk,
                rewardAPot: potA,
                rewardAMint,
                rewardADestination,
                rewardBPot: potB,
                rewardBMint,
                rewardBDestination,
                tokenProgram: spltok.TOKEN_PROGRAM_ID,
                associatedTokenProgram: spltok.ASSOCIATED_TOKEN_PROGRAM_ID,
                systemProgram: solweb3.SystemProgram.programId,
                rent: solweb3.SYSVAR_RENT_PUBKEY,
            },
            signers: [],
        });
        return [endStaking, endStaking, rewards];
    }
    catch(e) {
        console.log(e);
    }
}
async insOfStake(farm: solweb3.PublicKey, farmerIdentity: solweb3.Signer) {
    try {
        const identityPk: solweb3.PublicKey = farmerIdentity.publicKey ? farmerIdentity.publicKey : (farmerIdentity as any);
        const farmAcc = await this.fetchFarmAcc(farm);
        const [farmer, farmerBump] = await findFarmerPDA(farm, this.wallet.publicKey);
        const [vault, vaultBump] = await findVaultPDA(farmAcc.bank, identityPk);
        const [farmAuth, farmAuthBump] = await findFarmAuthorityPDA(farm);

        return [this.farmProgram.instruction.stake(farmAuthBump, farmerBump, {
            accounts: {
                farm,
                farmer,
                identity: identityPk,
                bank: farmAcc.bank,
                vault,
                farmAuthority: farmAuth,
                gemBank: this.bankProgram.programId,
                feeAcc: feeAccount,
                systemProgram: solweb3.SystemProgram.programId,
            },
            signers: [],
        })];
    }
    catch(e) {
        console.log(e);
    }
}

In your backClient:

async insOfWithdraw(bank: solweb3.PublicKey, vault: solweb3.PublicKey, gemMint: solweb3.PublicKey) {
    try {
        var vaultOwner: solweb3.PublicKey = this.wallet.publicKey;
        var receiver: solweb3.PublicKey = this.wallet.publicKey;

        const [gemBox, gemBoxBump] = await findGemBoxPDA(vault, gemMint);
        const [GDR, GDRBump] = await findGdrPDA(vault, gemMint);
        const [vaultAuth, vaultAuthBump] = await findVaultAuthorityPDA(vault);
        const [gemRarity, gemRarityBump] = await findRarityPDA(bank, gemMint);
        const gemDestination = await this.findATA(gemMint, receiver);

        return [this.bankProgram.instruction.withdrawGem(vaultAuthBump, gemBoxBump, GDRBump, gemRarityBump, new BN(1), {
            accounts: {
                bank,
                vault,
                owner: vaultOwner,
                authority: vaultAuth,
                gemBox,
                gemDepositReceipt: GDR,
                gemDestination,
                gemMint,
                gemRarity,
                receiver,
                tokenProgram: spltok.TOKEN_PROGRAM_ID,
                associatedTokenProgram: spltok.ASSOCIATED_TOKEN_PROGRAM_ID,
                systemProgram: solweb3.SystemProgram.programId,
                rent: solweb3.SYSVAR_RENT_PUBKEY,
            },
            signers: []
        })];
    }
    catch(e) {
        console.log(e);
    }
}

Tested, it is working for me. Only one wallet confirmation is needed, otherwise the wallet atleast popup 3 times to let you to confirm.