Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into PE-6656-auctions
Browse files Browse the repository at this point in the history
  • Loading branch information
dtfiedler committed Oct 22, 2024
2 parents c25d681 + 73b46b0 commit 4dc0b06
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 34 deletions.
1 change: 1 addition & 0 deletions src/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1613,6 +1613,7 @@ addEventingHandler("totalTokenSupply", utils.hasMatchingTag("Action", "Total-Tok
["Withdraw-Supply"] = withdrawSupply,
["Protocol-Balance"] = protocolBalance,
Data = json.encode({
-- TODO: we are losing precision on these values unexpectedly. This has been brought to the AO team - for now the tags should be correct as they are stringified
total = totalSupply,
circulating = circulatingSupply,
locked = lockedSupply,
Expand Down
4 changes: 2 additions & 2 deletions tests/handlers.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('handlers', async () => {
});

// assert no errors
assert.deepEqual(supplyResult.Messages[0].Error, undefined);
assert.deepEqual(supplyResult.Messages?.[0]?.Error, undefined);

// assert correct tag in message by finding the index of the tag in the message
const notice = supplyResult.Messages?.[0]?.Tags?.find(
Expand All @@ -72,7 +72,7 @@ describe('handlers', async () => {
);
assert.ok(notice, 'should have a Total-Token-Supply-Notice tag');

const supplyData = JSON.parse(supplyResult.Messages[0].Data);
const supplyData = JSON.parse(supplyResult.Messages?.[0]?.Data);

assert.ok(
supplyData.total === 1000000000 * 1000000,
Expand Down
190 changes: 158 additions & 32 deletions tests/monitor/monitor.test.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
<<<<<<< HEAD
import { AOProcess, IO, IO_DEVNET_PROCESS_ID, IO_TESTNET_PROCESS_ID } from '@ar.io/sdk';
=======
import {
AOProcess,
IO,
IO_DEVNET_PROCESS_ID,
IO_TESTNET_PROCESS_ID,
} from '@ar.io/sdk';
>>>>>>> origin/develop
import { connect } from '@permaweb/aoconnect';
import { strict as assert } from 'node:assert';
import { describe, it, before, after } from 'node:test';
Expand Down Expand Up @@ -34,8 +43,7 @@ describe('setup', () => {

describe('handlers', () => {
it('should always have correct number of handlers', async () => {
const expectedHandlerCount =
processId === IO_TESTNET_PROCESS_ID ? 52 : 53; // TODO: update this if more handlers are added
const expectedHandlerCount = 53; // TODO: update this if more handlers are added
const { Handlers: handlersList } = await io.getInfo();
/**
* There are two security handlers before _eval and _default, so count is 52
Expand Down Expand Up @@ -82,6 +90,21 @@ describe('setup', () => {
});
});

describe('balances', () => {
it('should always be up to date', async () => {
const { items: balances } = await io.getBalances({
limit: 10_000,
});
// assert they are all integers
for (const balance of balances) {
assert(
Number.isInteger(balance.balance),
`Balance for ${balance.address} is not an integer: ${balance.balance}`,
);
}
});
});

describe('distribution totals', () => {
it('should always have correct eligible rewards for the current epoch (within 10 mIO)', async () => {
const { distributions: currentEpochDistributions } =
Expand Down Expand Up @@ -154,29 +177,79 @@ describe('setup', () => {
`Delegated supply is undefined: ${supplyData.delegated}`,
);

const computedCirculating =
supplyData.total -
supplyData.locked -
supplyData.staked -
supplyData.delegated -
supplyData.withdrawn -
supplyData.protocolBalance;
assert(
supplyData.circulating === computedCirculating,
`Circulating supply (${supplyData.circulating}) is not equal to the sum of total, locked, staked, delegated, and withdrawn (${computedCirculating})`,
);
// TODO: there is an unknown precision loss on these values, we are discussing why with Forward. Once fixed, uncomment these tests
// const { items: balances } = await io.getBalances({
// limit: 10_000,
// });

const computedTotal =
supplyData.circulating +
supplyData.locked +
supplyData.withdrawn +
supplyData.staked +
supplyData.delegated +
supplyData.protocolBalance;
assert(
supplyData.total === computedTotal,
`Computed total supply (${computedTotal}) is not equal to the sum of protocol balance, circulating, locked, staked, and delegated (${supplyData.total})`,
);
// const protocolBalance = await io.getBalance({
// address: processId,
// });

// assert(
// protocolBalance === supplyData.protocolBalance,
// `Protocol balance is not equal to the balance provided by the contract: ${protocolBalance} !== ${supplyData.protocolBalance}`,
// );

// const totalBalances = balances.reduce(
// (acc, curr) => acc + curr.balance,
// 0,
// );
// const circulating = totalBalances - protocolBalance;
// assert(
// circulating === supplyData.circulating,
// `Circulating supply is not equal to the sum of the balances minus the protocol balance: ${circulating} !== ${supplyData.circulating}`,
// );

// // get the supply staked
// const { items: gateways } = await io.getGateways({
// limit: 1000,
// });

// const staked = gateways.reduce(
// (acc, curr) => acc + curr.operatorStake,
// 0,
// );

// assert(
// staked === supplyData.staked,
// `Staked supply is not equal to the sum of the operator stakes: ${staked} !== ${supplyData.staked}`,
// );

// const delegated = gateways.reduce(
// (acc, curr) => acc + curr.totalDelegatedStake,
// 0,
// );

// assert(
// delegated === supplyData.delegated,
// `Delegated supply is not equal to the sum of the total delegated stakes: ${delegated} !== ${supplyData.delegated}`,
// );

// const computedTotal =
// supplyData.circulating +
// supplyData.locked +
// supplyData.withdrawn +
// supplyData.staked +
// supplyData.delegated +
// supplyData.protocolBalance;
// assert(
// supplyData.total === computedTotal &&
// computedTotal === 1000000000 * 1000000,
// `Computed total supply (${computedTotal}) is not equal to the sum of protocol balance, circulating, locked, staked, and delegated and withdrawn provided by the contract (${supplyData.total}) and does not match the expected total of 1 billion IO`,
// );

// const computedCirculating =
// supplyData.total -
// supplyData.locked -
// supplyData.staked -
// supplyData.delegated -
// supplyData.withdrawn -
// supplyData.protocolBalance;
// assert(
// supplyData.circulating === computedCirculating,
// `Computed circulating supply (${computedCirculating}) is not equal to the total supply minus protocol balance, locked, staked, delegated, and withdrawn provided by the contract (${supplyData.circulating})`,
// );
});
});

Expand Down Expand Up @@ -230,10 +303,11 @@ describe('setup', () => {

it('the previous epoch should have a been distributed', async () => {
const { epochIndex: currentEpochIndex } = await io.getCurrentEpoch();
const previousEpochIndex = currentEpochIndex - 1;
const { epochIndex, distributions, endTimestamp, startTimestamp } =
await io.getEpoch({ epochIndex: currentEpochIndex - 1 });
await io.getEpoch({ epochIndex: previousEpochIndex });
assert(
epochIndex === currentEpochIndex - 1,
epochIndex === previousEpochIndex,
'Previous epoch index is not valid',
);
assert(distributions, 'Distributions are not valid');
Expand All @@ -249,14 +323,40 @@ describe('setup', () => {
distributions.rewards.eligible !== undefined,
'Eligible rewards are not valid',
);
// assert all eligible rewards are integers
assert(
Object.values(distributions.rewards.eligible).every(
(reward) =>
Number.isInteger(reward.operatorReward) &&
Object.values(reward.delegateRewards).every((delegateReward) =>
Number.isInteger(delegateReward),
),
),
`Eligible rewards for the previous epoch (${previousEpochIndex}) are not integers`,
);
assert(
distributions.rewards.distributed !== undefined,
'Distributed rewards are not valid',
);
// assert distributed rewards are integers
assert(
Object.values(distributions.rewards.distributed).every((reward) =>
Number.isInteger(reward),
),
`Distributed rewards for the previous epoch (${previousEpochIndex}) are not integers`,
);
});
});

// TODO: add demand factor tests
describe('demand factor', () => {
it('should always be greater than 0.5', async () => {
const demandFactor = await io.getDemandFactor();
assert(
demandFactor >= 0.5,
`Demand factor is less than 0.5: ${demandFactor}`,
);
});
});

// gateway registry - ensure no invalid gateways
describe('gateway registry', () => {
Expand All @@ -283,7 +383,18 @@ describe('setup', () => {
countedTotalGateways += gateways.length;
for (const gateway of gateways) {
if (gateway.status === 'joined') {
assert(gateway.operatorStake >= 50_000_000_000);
assert(
Number.isInteger(gateway.operatorStake),
`Gateway ${gateway.gatewayAddress} has an invalid operator stake: ${gateway.operatorStake}`,
);
assert(
Number.isInteger(gateway.totalDelegatedStake),
`Gateway ${gateway.gatewayAddress} has an invalid total delegated stake: ${gateway.totalDelegatedStake}`,
);
assert(
gateway.operatorStake >= 50_000_000_000,
`Gateway ${gateway.gatewayAddress} has less than 50_000_000_000 IO staked`,
);
assert(
gateway.stats.failedConsecutiveEpochs >= 0,
`Gateway ${gateway.gatewayAddress} has less than 0 failed consecutive epochs`,
Expand Down Expand Up @@ -317,6 +428,17 @@ describe('setup', () => {
`Gateway ${gateway.gatewayAddress} has less than 0 prescribed epochs`,
);
}
if (gateway.delegates.length > 0) {
assert(
gateway.delegates?.every(
(delegate) =>
Number.isInteger(delegate.balance) &&
delegate.startTimestamp > 0 &&
delegate.endTimestamp > delegate.startTimestamp,
),
`Gateway ${gateway.gatewayAddress} has invalid delegate balances`,
);
}
if (gateway.status === 'leaving') {
assert(gateway.totalDelegatedStake === 0);
assert(gateway.operatorStake === 0);
Expand All @@ -333,6 +455,10 @@ describe('setup', () => {
);
}
// assert vault balance is greater than 0 and startTimestamp and endTimestamp are valid timestamps 30 days apart
assert(
Number.isInteger(vault.balance),
`Vault ${vaultId} on gateway ${gateway.gatewayAddress} has an invalid balance (${vault.balance})`,
);
assert(
vault.balance >= 0,
`Vault ${vaultId} on gateway ${gateway.gatewayAddress} has an invalid balance (${vault.balance})`,
Expand Down Expand Up @@ -382,12 +508,12 @@ describe('setup', () => {
`ARNs name '${arn.name}' has no start timestamp`,
);
assert(
arn.purchasePrice >= 0,
`ARNs name '${arn.name}' has no purchase price`,
Number.isInteger(arn.purchasePrice) && arn.purchasePrice >= 0,
`ARNs name '${arn.name}' has invalid purchase price: ${arn.purchasePrice}`,
);
assert(
arn.undernameLimit >= 10,
`ARNs name '${arn.name}' has no undername limit`,
Number.isInteger(arn.undernameLimit) && arn.undernameLimit >= 10,
`ARNs name '${arn.name}' has invalid undername limit: ${arn.undernameLimit}`,
);
if (arns.type === 'lease') {
assert(
Expand Down

0 comments on commit 4dc0b06

Please sign in to comment.