Skip to content

Commit

Permalink
add elaborate gda test for flow distribution
Browse files Browse the repository at this point in the history
  • Loading branch information
kasparkallas authored Mar 13, 2024
1 parent a0623c7 commit 5d1813d
Showing 1 changed file with 251 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,25 @@ import { assert, describe, test } from "matchstick-as";
import { Address, BigInt, Bytes } from "@graphprotocol/graph-ts";
import { alice as alice_, bob as bob_, delta, echo, maticXAddress, superfluidPool } from "../constants";
import { getPoolMemberID } from "../../src/utils";
import { handleInstantDistributionUpdated } from "../../src/mappings/gdav1";
import { createInstantDistributionUpdatedEvent, createMemberUnitsUpdatedEvent, createPoolAndReturnPoolCreatedEvent } from "../gdav1/gdav1.helper";
import { handleFlowDistributionUpdated, handleInstantDistributionUpdated } from "../../src/mappings/gdav1";
import { createFlowDistributionUpdatedEvent, createInstantDistributionUpdatedEvent, createMemberUnitsUpdatedEvent, createPoolAndReturnPoolCreatedEvent } from "../gdav1/gdav1.helper";
import { mockedAppManifestAndRealtimeBalanceOf } from "../mockedFunctions";
import { handleMemberUnitsUpdated } from "../../src/mappings/superfluidPool";

/**
* Problem description
1. Create pool
2. Add member A and update A units to 100
3. Distribute 100 tokens
4. Add member B and update B units to 100
4. Distribute 100 tokens
Expected result:
member A 150 tokens
member B 50 tokens
Actual result:
member A 100 tokens
member B 50 tokens
*/
describe("PoolMember ending up with wrong `totalAmountReceivedUntilUpdatedAt`", () => {
test("create elaborate scenario with 2 distributions and 2 pool members", () => {
/**
* Problem description
1. Create pool
2. Add member A and update A units to 100
3. Distribute 1000 tokens
4. Add member B and update B units to 100
5. Distribute 1000 tokens
Expected result:
member A 1500 tokens
member B 500 tokens
*/
test("create elaborate scenario with 2 instant distributions and 2 pool members", () => {
const superTokenAddress = maticXAddress;
const poolAdminAndDistributorAddress = Address.fromString(delta);
const poolAddress = Address.fromString(superfluidPool);
Expand Down Expand Up @@ -209,5 +205,241 @@ describe("PoolMember ending up with wrong `totalAmountReceivedUntilUpdatedAt`",
"100"
);
})
/**
* Problem description
1. Create pool
2. Add member A and update A units to 100
3. Flow 1000 tokens (elapse 1 second)
4. Add member B and update B units to 100
5. Flow 1000 tokens (elapse 1 second)
6. Update flow rate to 2000 tokens
7. Flow 2000 tokens (elapse 1 second)
Expected result:
member A 2500 tokens
member B 1500 tokens
Actual result:
member A 100 tokens
member B 50 tokens
*/
test("create elaborate scenario with 2 flowing distributions and 2 pool members", () => {
const superTokenAddress = maticXAddress;
const poolAdminAndDistributorAddress = Address.fromString(delta);
const poolAddress = Address.fromString(superfluidPool);

// # Arrange State 1
// ## Arrange Pool
const poolCreatedEvent = createPoolAndReturnPoolCreatedEvent(poolAdminAndDistributorAddress.toHexString(), superTokenAddress, poolAddress.toHexString());
assert.stringEquals(poolCreatedEvent.block.timestamp.toString(), BigInt.fromI32(1).toString());

// ## Arrange PoolMember 1
const aliceAddress = Address.fromString(alice_);
const aliceId = getPoolMemberID(poolAddress, aliceAddress);
const aliceCreatedEvent = createMemberUnitsUpdatedEvent(
superTokenAddress,
aliceAddress.toHexString(),
BigInt.fromI32(0), // old units
BigInt.fromI32(100) // new units
);
aliceCreatedEvent.address = poolAddress;
aliceCreatedEvent.block.timestamp = poolCreatedEvent.block.timestamp; // 1

mockedAppManifestAndRealtimeBalanceOf(superTokenAddress, aliceAddress.toHexString(), aliceCreatedEvent.block.timestamp);
handleMemberUnitsUpdated(aliceCreatedEvent);

// # First flow rate
const firstFlowRateEvent = createFlowDistributionUpdatedEvent(
superTokenAddress,
poolAddress.toHexString(),
poolAdminAndDistributorAddress.toHexString(),
echo,
BigInt.fromI32(0), // oldFlowRate
BigInt.fromI32(1000), // newDistributorToPoolFlowRate
BigInt.fromI32(1000), // newTotalDistributionFlowRate
poolAdminAndDistributorAddress.toHexString(), // adjustmentFlowRecipient
BigInt.fromI32(0),
Bytes.fromHexString("0x")
);
firstFlowRateEvent.block.timestamp = poolCreatedEvent.block.timestamp; // 1
firstFlowRateEvent.address = poolAddress;

mockedAppManifestAndRealtimeBalanceOf(superTokenAddress, poolAdminAndDistributorAddress.toHexString(), firstFlowRateEvent.block.timestamp);
handleFlowDistributionUpdated(firstFlowRateEvent);

// TODO: This fails, how has this already flown???
assert.fieldEquals(
"Pool",
poolAddress.toHexString(),
"totalAmountDistributedUntilUpdatedAt",
"0" // nothing is flowed yet
);
assert.fieldEquals(
"Pool",
poolAddress.toHexString(),
"totalUnits",
"100"
);
assert.fieldEquals(
"Pool",
poolAddress.toHexString(),
"totalMembers",
"1"
);
assert.fieldEquals(
"PoolMember",
aliceId,
"totalAmountReceivedUntilUpdatedAt",
"0"
);
assert.fieldEquals(
"PoolMember",
aliceId,
"units",
"100"
);
// ---

// # Arrange State 2
// ## Arrange PoolMember 2 (new member)
const bobAddress = Address.fromString(bob_);
const bobId = getPoolMemberID(poolAddress, bobAddress);
let createBobEvent = createMemberUnitsUpdatedEvent(
superTokenAddress,
bobAddress.toHexString(),
BigInt.fromI32(0), // old units
BigInt.fromI32(100) // new units
);
createBobEvent.address = poolAddress;
createBobEvent.block.timestamp = BigInt.fromI32(2); // Skip 1 second to let it flow to Alice

mockedAppManifestAndRealtimeBalanceOf(superTokenAddress, bobAddress.toHexString(), createBobEvent.block.timestamp);
handleMemberUnitsUpdated(createBobEvent);

assert.fieldEquals(
"Pool",
poolAddress.toHexString(),
"totalAmountDistributedUntilUpdatedAt",
"1000"
);
assert.fieldEquals(
"PoolMember",
bobId,
"totalAmountReceivedUntilUpdatedAt",
"0" // Bob just joined, shouldn't have any received
);

// # Second flow rate
const secondFlowRateEvent = createFlowDistributionUpdatedEvent(
superTokenAddress,
poolAddress.toHexString(),
poolAdminAndDistributorAddress.toHexString(),
echo,
BigInt.fromI32(1000), // oldFlowRate
BigInt.fromI32(2000), // newDistributorToPoolFlowRate
BigInt.fromI32(2000), // newTotalDistributionFlowRate
poolAdminAndDistributorAddress.toHexString(), // adjustmentFlowRecipient
BigInt.fromI32(0),
Bytes.fromHexString("0x")
);
secondFlowRateEvent.block.timestamp = BigInt.fromI32(3); // One second skipped, 2 seconds flown to Alice, 1 second to Bob
secondFlowRateEvent.address = poolAddress;

mockedAppManifestAndRealtimeBalanceOf(superTokenAddress, poolAdminAndDistributorAddress.toHexString(), secondFlowRateEvent.block.timestamp);
handleFlowDistributionUpdated(secondFlowRateEvent);

assert.fieldEquals(
"Pool",
poolAddress.toHexString(),
"totalAmountDistributedUntilUpdatedAt",
"2000" // Only for first flow rate
);
assert.fieldEquals(
"Pool",
poolAddress.toHexString(),
"totalUnits",
"200"
);
assert.fieldEquals(
"PoolMember",
bobId,
"totalAmountReceivedUntilUpdatedAt",
"500" // Bob just joined, shouldn't have any received
);
assert.fieldEquals(
"PoolMember",
bobId,
"units",
"100"
);
assert.fieldEquals(
"PoolMember",
aliceId,
"totalAmountReceivedUntilUpdatedAt",
"1500"
);
// ---

// Arrange State 3
// # Update PoolMember 2's units to get the `totalAmountReceivedUntilUpdatedAt`
const updateBobEvent = createMemberUnitsUpdatedEvent(
superTokenAddress,
bobAddress.toHexString(),
BigInt.fromI32(100), // old units
BigInt.fromI32(100) // new units
);
// Note, the units can stay the same, we just want to trigger an update.
updateBobEvent.address = poolAddress;
updateBobEvent.block.timestamp = BigInt.fromI32(4); // 4 - 1 = 3 seconds of flow

mockedAppManifestAndRealtimeBalanceOf(superTokenAddress, bobAddress.toHexString(), updateBobEvent.block.timestamp);
handleMemberUnitsUpdated(createBobEvent);

assert.fieldEquals(
"Pool",
poolAddress.toHexString(),
"totalAmountDistributedUntilUpdatedAt",
"4000"
);
assert.fieldEquals(
"PoolMember",
bobId,
"totalAmountReceivedUntilUpdatedAt",
"1500" // 50% of 2000
);
assert.fieldEquals(
"PoolMember",
bobId,
"units",
"100"
);

// # Update PoolMember 1's units to get the `totalAmountReceivedUntilUpdatedAt`
const updateAliceEvent = createMemberUnitsUpdatedEvent(
superTokenAddress,
aliceAddress.toHexString(),
BigInt.fromI32(100), // old units
BigInt.fromI32(100) // new units
);
// Note, the units can stay the same, we just want to trigger an update.
updateAliceEvent.address = poolAddress;
updateAliceEvent.block.timestamp = updateBobEvent.block.timestamp; // 4

mockedAppManifestAndRealtimeBalanceOf(superTokenAddress, aliceAddress.toHexString(), updateAliceEvent.block.timestamp);
handleMemberUnitsUpdated(updateAliceEvent);

assert.fieldEquals(
"PoolMember",
aliceId,
"totalAmountReceivedUntilUpdatedAt",
"2500"
);
assert.fieldEquals(
"PoolMember",
aliceId,
"units",
"100"
);
})
});

0 comments on commit 5d1813d

Please sign in to comment.