Skip to content

Commit

Permalink
Merge pull request #172 from lidofinance/feature/si-1675-rewards-self…
Browse files Browse the repository at this point in the history
…-transfer-edgecase

fix: self transfer edge case
  • Loading branch information
Jeday authored Oct 31, 2024
2 parents 6ea7a6d + b3e311d commit 169fee9
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 142 deletions.
8 changes: 8 additions & 0 deletions packages/sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# 4.0.1

## SDK

### Fixed

- `LidoSDKRewards` now filter outs edgecases with self-transfers

# 4.0.0

## Breaking change
Expand Down
297 changes: 155 additions & 142 deletions packages/sdk/src/rewards/rewards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,58 +192,65 @@ export class LidoSDKRewards extends LidoSDKModule {
let totalRewards = 0n;
let shareRate = baseShareRate;
let prevSharesBalance = baseBalanceShares;
let rewards: Reward<RewardsChainEvents>[] = events.map((event) => {
if (event.eventName === 'TransferShares') {
const { from, to, sharesValue } = event.args;
let type: Reward<RewardsChainEvents>['type'],
changeShares: Reward<RewardsChainEvents>['changeShares'],
balanceShares: Reward<RewardsChainEvents>['balanceShares'];

if (isAddressEqual(to, address)) {
type = isAddressEqual(from, zeroAddress) ? 'submit' : 'transfer_in';
balanceShares = prevSharesBalance + sharesValue;
changeShares = sharesValue;
} else {
type = isAddressEqual(to, withdrawalQueueAddress)
? 'withdrawal'
: 'transfer_out';
balanceShares = prevSharesBalance - sharesValue;
changeShares = -sharesValue;
let rewards = events
.map((event) => {
if (event.eventName === 'TransferShares') {
const { from, to, sharesValue } = event.args;

if (isAddressEqual(to, from)) {
return null;
}

let type: Reward<RewardsChainEvents>['type'],
changeShares: Reward<RewardsChainEvents>['changeShares'],
balanceShares: Reward<RewardsChainEvents>['balanceShares'];

if (isAddressEqual(to, address)) {
type = isAddressEqual(from, zeroAddress) ? 'submit' : 'transfer_in';
balanceShares = prevSharesBalance + sharesValue;
changeShares = sharesValue;
} else {
type = isAddressEqual(to, withdrawalQueueAddress)
? 'withdrawal'
: 'transfer_out';
balanceShares = prevSharesBalance - sharesValue;
changeShares = -sharesValue;
}

prevSharesBalance = balanceShares;
return {
type,
balanceShares,
changeShares,
change: getCurrentStethFromShares(changeShares),
balance: getCurrentStethFromShares(balanceShares),
shareRate,
originalEvent: event,
};
}

prevSharesBalance = balanceShares;
return {
type,
balanceShares,
changeShares,
change: getCurrentStethFromShares(changeShares),
balance: getCurrentStethFromShares(balanceShares),
shareRate,
originalEvent: event,
};
}
if (event.eventName === 'TokenRebased') {
const { postTotalEther, postTotalShares } = event.args;
const oldBalance = getCurrentStethFromShares(prevSharesBalance);
currentTotalEther = postTotalEther;
currentTotalShares = postTotalShares;
const newBalance = getCurrentStethFromShares(prevSharesBalance);
shareRate = getCurrentShareRate();
const change = newBalance - oldBalance;
totalRewards += change;
return {
type: 'rebase',
change,
apr: LidoSDKApr.calculateAprFromRebaseEvent(event.args),
changeShares: 0n,
balance: newBalance,
balanceShares: prevSharesBalance,
shareRate,
originalEvent: event,
};
}
invariant(false, 'Impossible event');
});
if (event.eventName === 'TokenRebased') {
const { postTotalEther, postTotalShares } = event.args;
const oldBalance = getCurrentStethFromShares(prevSharesBalance);
currentTotalEther = postTotalEther;
currentTotalShares = postTotalShares;
const newBalance = getCurrentStethFromShares(prevSharesBalance);
shareRate = getCurrentShareRate();
const change = newBalance - oldBalance;
totalRewards += change;
return {
type: 'rebase',
change,
apr: LidoSDKApr.calculateAprFromRebaseEvent(event.args),
changeShares: 0n,
balance: newBalance,
balanceShares: prevSharesBalance,
shareRate,
originalEvent: event,
};
}
invariant(false, 'Impossible event');
})
.filter((event) => !!event) as Reward<RewardsChainEvents>[];

if (includeOnlyRebases) {
rewards = rewards.filter((r) => r.type === 'rebase');
Expand Down Expand Up @@ -380,101 +387,107 @@ export class LidoSDKRewards extends LidoSDKModule {
const baseBalanceShares = prevBalanceShares;

let totalRewards = 0n;
let rewards: Reward<RewardsSubgraphEvents>[] = events.map((event) => {
// it's a transfer
if ('value' in event) {
const {
from,
to,
shares,
sharesAfterIncrease,
value,
balanceAfterDecrease,
balanceAfterIncrease,
sharesAfterDecrease,
totalPooledEther,
totalShares,
} = event;
let type: Reward<RewardsSubgraphEvents>['type'],
changeShares: Reward<RewardsSubgraphEvents>['changeShares'],
balanceShares: Reward<RewardsSubgraphEvents>['balanceShares'],
change: Reward<RewardsSubgraphEvents>['change'],
balance: Reward<RewardsSubgraphEvents>['balance'];

if (isAddressEqual(to as Address, address)) {
type = isAddressEqual(from as Address, zeroAddress)
? 'submit'
: 'transfer_in';
changeShares = BigInt(shares);
balanceShares = BigInt(sharesAfterIncrease);
change = BigInt(value);
balance = BigInt(balanceAfterIncrease);
} else {
type = isAddressEqual(to as Address, withdrawalQueueAddress)
? 'withdrawal'
: 'transfer_out';
balance = BigInt(balanceAfterDecrease);
change = -BigInt(value);
changeShares = -BigInt(shares);
balanceShares = BigInt(sharesAfterDecrease);
let rewards = events
.map((event) => {
// it's a transfer
if ('value' in event) {
const {
from,
to,
shares,
sharesAfterIncrease,
value,
balanceAfterDecrease,
balanceAfterIncrease,
sharesAfterDecrease,
totalPooledEther,
totalShares,
} = event;
let type: Reward<RewardsSubgraphEvents>['type'],
changeShares: Reward<RewardsSubgraphEvents>['changeShares'],
balanceShares: Reward<RewardsSubgraphEvents>['balanceShares'],
change: Reward<RewardsSubgraphEvents>['change'],
balance: Reward<RewardsSubgraphEvents>['balance'];

if (isAddressEqual(to as Address, from as Address)) {
return null;
}

if (isAddressEqual(to as Address, address)) {
type = isAddressEqual(from as Address, zeroAddress)
? 'submit'
: 'transfer_in';
changeShares = BigInt(shares);
balanceShares = BigInt(sharesAfterIncrease);
change = BigInt(value);
balance = BigInt(balanceAfterIncrease);
} else {
type = isAddressEqual(to as Address, withdrawalQueueAddress)
? 'withdrawal'
: 'transfer_out';
balance = BigInt(balanceAfterDecrease);
change = -BigInt(value);
changeShares = -BigInt(shares);
balanceShares = BigInt(sharesAfterDecrease);
}

const shareRate = calcShareRate(
BigInt(totalPooledEther),
BigInt(totalShares),
LidoSDKRewards.PRECISION,
);
prevBalance = balance;
prevBalanceShares = balanceShares;

return {
type,
balanceShares,
changeShares,
change,
balance,
shareRate,
originalEvent: event,
};
}

const shareRate = calcShareRate(
BigInt(totalPooledEther),
BigInt(totalShares),
LidoSDKRewards.PRECISION,
);
prevBalance = balance;
prevBalanceShares = balanceShares;

return {
type,
balanceShares,
changeShares,
change,
balance,
shareRate,
originalEvent: event,
};
}
// it's a rebase
if ('apr' in event) {
const {
totalPooledEtherAfter,
totalSharesAfter,
apr: eventApr,
} = event;

const totalEther = BigInt(totalPooledEtherAfter);
const totalShares = BigInt(totalSharesAfter);

const newBalance = sharesToSteth(
prevBalanceShares,
totalEther,
totalShares,
LidoSDKRewards.PRECISION,
);
const change = newBalance - prevBalance;
totalRewards += change;
prevBalance = newBalance;

return {
type: 'rebase',
change,
apr: Number(eventApr),
changeShares: 0n,
balance: newBalance,
balanceShares: prevBalanceShares,
shareRate: calcShareRate(
// it's a rebase
if ('apr' in event) {
const {
totalPooledEtherAfter,
totalSharesAfter,
apr: eventApr,
} = event;

const totalEther = BigInt(totalPooledEtherAfter);
const totalShares = BigInt(totalSharesAfter);

const newBalance = sharesToSteth(
prevBalanceShares,
totalEther,
totalShares,
LidoSDKRewards.PRECISION,
),
originalEvent: event,
};
}
invariant(false, 'impossible event');
});
);
const change = newBalance - prevBalance;
totalRewards += change;
prevBalance = newBalance;

return {
type: 'rebase',
change,
apr: Number(eventApr),
changeShares: 0n,
balance: newBalance,
balanceShares: prevBalanceShares,
shareRate: calcShareRate(
totalEther,
totalShares,
LidoSDKRewards.PRECISION,
),
originalEvent: event,
};
}
invariant(false, 'impossible event');
})
.filter((events) => !!events) as Reward<RewardsSubgraphEvents>[];

if (includeOnlyRebases) {
rewards = rewards.filter((r) => r.type === 'rebase');
Expand Down

0 comments on commit 169fee9

Please sign in to comment.