Skip to content

Commit

Permalink
pending rewards function
Browse files Browse the repository at this point in the history
  • Loading branch information
thesoftwarejedi committed Sep 30, 2021
1 parent a6aebfe commit 78c1d91
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 3 deletions.
51 changes: 48 additions & 3 deletions tests/reward-pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,35 @@ describe('Multiuser Reward Pool', () => {
assert.fail("single stake pool should fail if funded token b");
} catch (e) { }

try {
var expected = (await user.getUserPendingRewardsFunction())();
console.log("Expected", expected[0], expected[1]);
} catch (e) {
console.log(e);
process.exit();
}

await funders[2].fund(1_000_000_000, 0);
await wait(5);

expected = await user.getUserPendingRewardsFunction();
var e = expected()
console.log("Expected", e[0], e[1]);
await wait(1);
e = expected()
console.log("Expected", e[0], e[1]);
await wait(1);
e = expected()
console.log("Expected", e[0], e[1]);
await wait(1);
e = expected()
console.log("Expected", e[0], e[1]);
await wait(1);
e = expected()
console.log("Expected", e[0], e[1]);
await wait(1);
e = expected()
console.log("Expected", e[0], e[1]);

await claimForUsers([user]);
await user.unstakeTokens(100_000);
await user.closeUser();
Expand Down Expand Up @@ -285,8 +312,26 @@ describe('Multiuser Reward Pool', () => {
assert(0 < (await provider.connection.getTokenAccountBalance(users[1].mintBPubkey)).value.uiAmount);
});

it('waits', async () => {
await wait(6); //pool 1 @ -1, pool 2 @ 19
it('waits and watches', async () => {
var expectedFn = await users[0].getUserPendingRewardsFunction();
await wait(1);
var expected = expectedFn();
console.log('user 1 estimated A', expected[0], 'estimated B', expected[1]);
await wait(1);
expected = expectedFn();
console.log('user 1 estimated A', expected[0], 'estimated B', expected[1]);
await wait(1);
expected = expectedFn();
console.log('user 1 estimated A', expected[0], 'estimated B', expected[1]);
await wait(1);
expected = expectedFn();
console.log('user 1 estimated A', expected[0], 'estimated B', expected[1]);
await wait(1);
expected = expectedFn();
console.log('user 1 estimated A', expected[0], 'estimated B', expected[1]);
await wait(1); //pool 1 @ -1, pool 2 @ 19
expected = expectedFn();
console.log('user 1 estimated A', expected[0], 'estimated B', expected[1]);
});

it('Users claim at end of fund', async () => {
Expand Down
67 changes: 67 additions & 0 deletions tests/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class User {
this.pubkey = this.keypair.publicKey;

let envProvider = anchor.Provider.env();
envProvider.commitment = 'pending';
await utils.sendLamports(envProvider, this.pubkey, initialLamports);

this.provider = new anchor.Provider(envProvider.connection, new anchor.Wallet(this.keypair), envProvider.opts);
Expand Down Expand Up @@ -334,6 +335,72 @@ class User {
});
}

async getUserPendingRewardsFunction() {
return await User.getPendingRewardsFunction(this.program, this.poolPubkey);
}

// *returns a function* that when called returns an array of 2 values, the pending rewardA and rewardB
// this function is accurate forever (even after pool ends), unless the pool is changed through
// funding, or anyone staking/unstaking.
// Querying the chain is only done on initial call (this method) to build the function.
// Computations are done against current date/time every time the returned function is called.
static async getPendingRewardsFunction(rewardsPoolAnchorProgram, rewardsPoolPubkey) {
const U64_MAX = new anchor.BN("18446744073709551615", 10);
let poolObject = await rewardsPoolAnchorProgram.account.pool.fetch(rewardsPoolPubkey);
let rewardAPerToken = new anchor.BN(poolObject.rewardAPerTokenStored);
let rewardBPerToken = new anchor.BN(poolObject.rewardBPerTokenStored);
let rewardARate = new anchor.BN(poolObject.rewardARate);
let rewardBRate = new anchor.BN(poolObject.rewardBRate);
let lastUpdate = poolObject.lastUpdateTime;
var singleStaking = poolObject.rewardAMint.toString() == poolObject.rewardBMint.toString();

let vaultBalance = await rewardsPoolAnchorProgram.provider.connection.getTokenAccountBalance(poolObject.stakingVault);
vaultBalance = new anchor.BN(parseInt(vaultBalance.value.amount));

//a function that gives the total rewards emitted over the whole pool since last update
let fnAllRewardsPerToken = () => {
var lastApplicable = Math.min(Math.floor(Date.now() / 1000), poolObject.rewardDurationEnd);
var elapsed = new anchor.BN(lastApplicable - lastUpdate);
var currentARewardPerToken = rewardAPerToken.add(elapsed.mul(rewardARate).mul(U64_MAX).div(vaultBalance));
var currentBRewardPerToken;
if (singleStaking) {
currentBRewardPerToken = new anchor.BN(0);
} else {
currentBRewardPerToken = rewardBPerToken.add(elapsed.mul(rewardBRate).mul(U64_MAX).div(vaultBalance));
}
return [currentARewardPerToken, currentBRewardPerToken];
};

const [
userPubkey, _userNonce,
] = await anchor.web3.PublicKey.findProgramAddress(
[rewardsPoolAnchorProgram.provider.wallet.publicKey.toBuffer(), rewardsPoolPubkey.toBuffer()],
rewardsPoolAnchorProgram.programId
);
let userObject = await rewardsPoolAnchorProgram.account.user.fetch(userPubkey);
let completeA = new anchor.BN(userObject.rewardAPerTokenComplete);
let completeB = new anchor.BN(userObject.rewardBPerTokenComplete);
let pendingA = new anchor.BN(userObject.rewardAPerTokenPending);
let pendingB = new anchor.BN(userObject.rewardBPerTokenPending);
let balanceStaked = new anchor.BN(userObject.balanceStaked);

//a function that gives a user's total unclaimed rewards since last update
let currentPending = () => {
var rwds = fnAllRewardsPerToken();
var a = balanceStaked.mul(rwds[0]).sub(completeA).div(U64_MAX).add(pendingA).toNumber();
var b;
if (singleStaking) {
b = 0;
} else {
b = balanceStaked.mul(rwds[0]).sub(completeB).div(U64_MAX).add(pendingB).toNumber();
}
return [a, b];

}

return currentPending;
}

async claim() {
let poolObject = await this.program.account.pool.fetch(this.poolPubkey);

Expand Down

0 comments on commit 78c1d91

Please sign in to comment.