Skip to content

Commit

Permalink
[SUBGRAPH] [BUG] PoolMember not getting updated when the member units…
Browse files Browse the repository at this point in the history
… change (#1877)

* add a test starter

* add the test

* fixes

* improve test

* update dev container for matchstick compatibility

* implement the fix

* clean-up

* add elaborate test for pool  total amount received

* fix test issue

* add even more comments

* fix test name

* ignore test

---------

Co-authored-by: 0xdavinchee <[email protected]>
  • Loading branch information
kasparkallas and 0xdavinchee authored Mar 12, 2024
1 parent 24762f1 commit b48fcca
Show file tree
Hide file tree
Showing 8 changed files with 390 additions and 42 deletions.
7 changes: 5 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
"name": "Node.js & TypeScript",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bookworm",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-22.04",
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
// If having issues with Nix then consult:
Expand All @@ -19,7 +19,9 @@
"ghcr.io/lukewiwa/features/shellcheck:0": {},
"ghcr.io/devcontainers-contrib/features/curl-apt-get:1": {},
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers-contrib/features/act:1": {}
"ghcr.io/devcontainers-contrib/features/act:1": {},
"ghcr.io/devcontainers/features/node:1": {},
"ghcr.io/eitsupi/devcontainer-features/jq-likes:2": {}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
Expand All @@ -32,6 +34,7 @@
"source /home/node/.bashrc && foundryup",
"yarn global add npm-run-all",
"yarn install && yarn build",
"sudo apt-get install libpq5", // for subgraph's matchstick
"./tasks/fix-devcontainer.sh && nix develop . -c bash <(echo \"yarn install && yarn build\")"
]
// Configure tool-specific properties.
Expand Down
12 changes: 6 additions & 6 deletions packages/subgraph/src/mappingHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ export function updatePoolTotalAmountFlowedAndDistributed(
return pool;
}

export function getOrInitPoolMember(
export function getOrInitOrUpdatePoolMember(
event: ethereum.Event,
poolAddress: Address,
poolMemberAddress: Address
Expand All @@ -548,19 +548,19 @@ export function getOrInitPoolMember(
poolMember = new PoolMember(poolMemberID);
poolMember.createdAtTimestamp = event.block.timestamp;
poolMember.createdAtBlockNumber = event.block.number;
poolMember.updatedAtTimestamp = event.block.timestamp;
poolMember.updatedAtBlockNumber = event.block.number;


poolMember.units = BIG_INT_ZERO;
poolMember.isConnected = false;
poolMember.totalAmountClaimed = BIG_INT_ZERO;
poolMember.poolTotalAmountDistributedUntilUpdatedAt = BIG_INT_ZERO;
poolMember.totalAmountReceivedUntilUpdatedAt = BIG_INT_ZERO;

poolMember.account = poolMemberAddress.toHex();
poolMember.pool = poolAddress.toHex();
}

poolMember.updatedAtTimestamp = event.block.timestamp;
poolMember.updatedAtBlockNumber = event.block.number;

return poolMember;
}

Expand Down
10 changes: 5 additions & 5 deletions packages/subgraph/src/mappings/gdav1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
_createTokenStatisticLogEntity,
getOrInitPool,
getOrInitPoolDistributor,
getOrInitPoolMember,
getOrInitOrUpdatePoolMember,
getOrInitTokenStatistic,
updateATSStreamedAndBalanceUntilUpdatedAt,
updateAggregateDistributionAgreementData,
Expand Down Expand Up @@ -84,7 +84,7 @@ export function handlePoolConnectionUpdated(
event: PoolConnectionUpdated
): void {
// Update Pool Member Entity
let poolMember = getOrInitPoolMember(
let poolMember = getOrInitOrUpdatePoolMember(
event,
event.params.pool,
event.params.account
Expand Down Expand Up @@ -162,6 +162,9 @@ export function handlePoolConnectionUpdated(
false // isIDA
);

// Create Event Entity
_createPoolConnectionUpdatedEntity(event, poolMember.id);

// Create ATS and Token Statistic Log Entities
const eventName = "PoolConnectionUpdated";
_createAccountTokenSnapshotLogEntity(
Expand All @@ -172,9 +175,6 @@ export function handlePoolConnectionUpdated(
);

_createTokenStatisticLogEntity(event, event.params.token, eventName);

// Create Event Entity
_createPoolConnectionUpdatedEntity(event, poolMember.id);
}

export function handleBufferAdjusted(event: BufferAdjusted): void {
Expand Down
44 changes: 21 additions & 23 deletions packages/subgraph/src/mappings/superfluidPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
_createAccountTokenSnapshotLogEntity,
_createTokenStatisticLogEntity,
getOrInitPool,
getOrInitPoolMember,
getOrInitOrUpdatePoolMember,
updateATSStreamedAndBalanceUntilUpdatedAt,
updateAggregateDistributionAgreementData,
updatePoolMemberTotalAmountUntilUpdatedAtFields,
Expand All @@ -28,7 +28,7 @@ export function handleDistributionClaimed(event: DistributionClaimed): void {
pool.save();

// Update PoolMember
let poolMember = getOrInitPoolMember(event, event.address, event.params.member);
let poolMember = getOrInitOrUpdatePoolMember(event, event.address, event.params.member);
poolMember.totalAmountClaimed = event.params.totalClaimed;

poolMember = updatePoolMemberTotalAmountUntilUpdatedAtFields(pool, poolMember);
Expand All @@ -48,29 +48,16 @@ export function handleDistributionClaimed(event: DistributionClaimed): void {
}

export function handleMemberUnitsUpdated(event: MemberUnitsUpdated): void {
// - PoolMember
// - units
let poolMember = getOrInitPoolMember(event, event.address, event.params.member);
const hasMembershipWithUnits = membershipWithUnitsExists(poolMember.id);

let pool = getOrInitPool(event, event.address.toHex());

const previousUnits = poolMember.units;
const unitsDelta = event.params.newUnits.minus(previousUnits);
let poolMember = getOrInitOrUpdatePoolMember(event, event.address, event.params.member);

pool = updatePoolTotalAmountFlowedAndDistributed(event, pool);

poolMember = updatePoolMemberTotalAmountUntilUpdatedAtFields(pool, poolMember);


const previousUnits = poolMember.units;
const unitsDelta = event.params.newUnits.minus(previousUnits);
poolMember.units = event.params.newUnits;

const eventName = "MemberUnitsUpdated";
updateTokenStatsStreamedUntilUpdatedAt(event.params.token, event.block);
_createTokenStatisticLogEntity(event, event.params.token, eventName);

updateATSStreamedAndBalanceUntilUpdatedAt(event.params.member, event.params.token, event.block, null);
_createAccountTokenSnapshotLogEntity(event, event.params.member, event.params.token, eventName);

if (poolMember.isConnected) {
pool.totalConnectedUnits = pool.totalConnectedUnits.plus(unitsDelta);
} else {
Expand All @@ -79,7 +66,8 @@ export function handleMemberUnitsUpdated(event: MemberUnitsUpdated): void {
pool.totalUnits = pool.totalUnits.plus(unitsDelta);

// 0 units to > 0 units
if (previousUnits.equals(BIG_INT_ZERO) && event.params.newUnits.gt(BIG_INT_ZERO)) {
const didPoolMemberBecomeActive = previousUnits.equals(BIG_INT_ZERO) && event.params.newUnits.gt(BIG_INT_ZERO)
if (didPoolMemberBecomeActive) {
pool.totalMembers = pool.totalMembers + 1;
// if the member is connected with units now, we add one to connected
if (poolMember.isConnected) {
Expand All @@ -92,7 +80,7 @@ export function handleMemberUnitsUpdated(event: MemberUnitsUpdated): void {
updateAggregateDistributionAgreementData(
event.params.member,
event.params.token,
hasMembershipWithUnits,
true, // has units
poolMember.isConnected,
true, // only place we increment subWithUnits
false, // not deleting
Expand All @@ -102,8 +90,10 @@ export function handleMemberUnitsUpdated(event: MemberUnitsUpdated): void {
false // isIDA
);
}

// > 0 units to 0 units
if (previousUnits.gt(BIG_INT_ZERO) && poolMember.units.equals(BIG_INT_ZERO)) {
const didPoolMemberBecomeInactive = previousUnits.gt(BIG_INT_ZERO) && poolMember.units.equals(BIG_INT_ZERO)
if (didPoolMemberBecomeInactive) {
pool.totalMembers = pool.totalMembers - 1;
// if the member is connected with no units now, we subtract one from connected
if (poolMember.isConnected) {
Expand All @@ -116,7 +106,7 @@ export function handleMemberUnitsUpdated(event: MemberUnitsUpdated): void {
updateAggregateDistributionAgreementData(
event.params.member,
event.params.token,
hasMembershipWithUnits,
false, // has units
poolMember.isConnected,
false, // don't increment memberWithUnits
false, // not disconnecting membership
Expand All @@ -132,6 +122,14 @@ export function handleMemberUnitsUpdated(event: MemberUnitsUpdated): void {

// Create Event Entity
_createMemberUnitsUpdatedEntity(event, poolMember.id, pool.totalUnits);

// Other entity updates
const eventName = "MemberUnitsUpdated";
updateTokenStatsStreamedUntilUpdatedAt(event.params.token, event.block);
_createTokenStatisticLogEntity(event, event.params.token, eventName);

updateATSStreamedAndBalanceUntilUpdatedAt(event.params.member, event.params.token, event.block, null);
_createAccountTokenSnapshotLogEntity(event, event.params.member, event.params.token, eventName);
}

function _createDistributionClaimedEntity(event: DistributionClaimed, poolMemberId: string): DistributionClaimedEvent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe("ALEPH Total Supply Bug", () => {
mockedTokenName(superToken, "tokenName");
mockedTokenSymbol(superToken, "tokenSymbol");
mockedTokenDecimals(superToken, 18);

// unused mocked function call after change in this commit (removing total supply RPC call in getOrInitSuperToken)
mockedTokenTotalSupply(superToken, totalSupply);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { handleMemberUnitsUpdated } from "../../src/mappings/superfluidPool";
import { createMemberUnitsUpdatedEvent } from "../gdav1/gdav1.helper";
import { Address, BigInt } from "@graphprotocol/graph-ts";
import { FAKE_INITIAL_BALANCE, alice, bob, charlie } from "../constants";
import { BIG_INT_ZERO, getPoolMemberID } from "../../src/utils";
import { assert, describe, test } from "matchstick-as";
import { mockedGetAppManifest, mockedRealtimeBalanceOf } from "../mockedFunctions";

describe("PoolMember not updating when units changed", () => {
test("emit MemberUnitsUpdated event", () => {
const superTokenAddress = alice;

const poolAddress = Address.fromString(bob);
const poolMemberAccountAddress = Address.fromString(charlie);
const poolMemberId = getPoolMemberID(poolAddress, poolMemberAccountAddress);

mockedGetAppManifest(poolMemberAccountAddress.toHexString(), false, false, BIG_INT_ZERO);

// Initialize pool member for the first time
const firstEvent = createMemberUnitsUpdatedEvent(
superTokenAddress,
poolMemberAccountAddress.toHexString(),
BigInt.fromI32(0), // old units
BigInt.fromI32(0) // new units
);
firstEvent.address = poolAddress;

mockedRealtimeBalanceOf(
superTokenAddress,
poolMemberAccountAddress.toHexString(),
firstEvent.block.timestamp,
FAKE_INITIAL_BALANCE,
BigInt.fromI32(0),
BIG_INT_ZERO
);

handleMemberUnitsUpdated(firstEvent);
// ---


const newUnits = BigInt.fromI32(100);
const blockNumber = BigInt.fromI32(200)
const timestamp = BigInt.fromI32(300)

const secondEvent = createMemberUnitsUpdatedEvent(
superTokenAddress,
poolMemberAccountAddress.toHexString(),
BigInt.fromI32(0), // old units
newUnits
);
secondEvent.block.timestamp = timestamp
secondEvent.address = poolAddress;
secondEvent.block.number = blockNumber;

mockedRealtimeBalanceOf(
superTokenAddress,
poolMemberAccountAddress.toHexString(),
secondEvent.block.timestamp,
FAKE_INITIAL_BALANCE,
BigInt.fromI32(0),
BIG_INT_ZERO
);

// Act
handleMemberUnitsUpdated(secondEvent);

// Assert
assert.fieldEquals(
"PoolMember",
poolMemberId,
"units",
newUnits.toString()
);

assert.fieldEquals(
"PoolMember",
poolMemberId,
"updatedAtTimestamp",
timestamp.toString()
);

assert.fieldEquals(
"PoolMember",
poolMemberId,
"updatedAtBlockNumber",
blockNumber.toString()
);
});
});
Loading

0 comments on commit b48fcca

Please sign in to comment.