Skip to content

Commit

Permalink
feat(ant): add ANT read interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Atticus committed Mar 15, 2024
1 parent 1b6772e commit 06bb36d
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 22 deletions.
10 changes: 8 additions & 2 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@ services:
environment:
- LOG_LEVEL=debug
- PREFETCH_CONTRACTS=true
- PREFETCH_CONTRACT_IDS=_NctcA2sRy1-J4OmIQZbYFPM17piNcbdBPH2ncX2RL8
- PREFETCH_CONTRACT_IDS=['_NctcA2sRy1-J4OmIQZbYFPM17piNcbdBPH2ncX2RL8', 'UC2zwawQoTnh0TNd9mYLQS4wObBBeaOU5LPQTNETqA4']
- BOOTSTRAP_CONTRACTS=false
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:3000/healthcheck']
test:
[
'CMD',
'curl',
'-f',
'http://localhost:3000/healthcheck'
]
interval: 10s
timeout: 5s
retries: 5
35 changes: 35 additions & 0 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import {
ANTRecord,
ANTState,
ArIOState,
ArNSNameData,
EpochDistributionData,
Expand All @@ -27,6 +29,27 @@ export type BlockHeight = number;
export type SortKey = string;
export type WalletAddress = string;

// TODO: append this with other configuration options (e.g. local vs. remote evaluation)
export type ContractConfiguration =
| {
contract?: SmartWeaveContract<unknown>;

Check failure on line 35 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Insert `··`

Check failure on line 35 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Insert `··`
}

Check failure on line 36 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Insert `··`

Check failure on line 36 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Insert `··`
| {
contractTxId: string;

Check failure on line 38 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Insert `··`

Check failure on line 38 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Insert `··`
};

Check failure on line 39 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Insert `··`

Check failure on line 39 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Insert `··`

export function isContractConfiguration<T>(
config: ContractConfiguration,
): config is { contract: SmartWeaveContract<T> } {
return 'contract' in config;
}

export function isContractTxIdConfiguration(
config: ContractConfiguration,
): config is { contractTxId: string } {
return 'contractTxId' in config;
}

export type EvaluationOptions = {
evalTo?: { sortKey: SortKey } | { blockHeight: BlockHeight };
// TODO: any other evaluation constraints
Expand Down Expand Up @@ -102,6 +125,18 @@ export interface ArIOContract {
}: EvaluationParameters): Promise<EpochDistributionData>;
}

export interface ANTContract {
getState({ evaluationOptions }: EvaluationParameters): Promise<ANTState>;
getRecord({ domain, evaluationOptions }: EvaluationParameters<{ domain: string }>): Promise<ANTRecord>;

Check failure on line 130 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Replace `·domain,·evaluationOptions` with `⏎····domain,⏎····evaluationOptions,⏎·`

Check failure on line 130 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Replace `·domain,·evaluationOptions` with `⏎····domain,⏎····evaluationOptions,⏎·`
getRecords({ evaluationOptions }: EvaluationParameters): Promise<Record<string, ANTRecord>>;

Check failure on line 131 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Replace `·evaluationOptions` with `⏎····evaluationOptions,⏎·`

Check failure on line 131 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Replace `·evaluationOptions` with `⏎····evaluationOptions,⏎·`
getOwner({ evaluationOptions }: EvaluationParameters): Promise<string>;
getControllers({ evaluationOptions }: EvaluationParameters): Promise<any[]>;

Check warning on line 133 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Unexpected any. Specify a different type

Check warning on line 133 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Unexpected any. Specify a different type
getTicker({ evaluationOptions }: EvaluationParameters): Promise<any>;

Check warning on line 134 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Unexpected any. Specify a different type

Check warning on line 134 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Unexpected any. Specify a different type
getName({ evaluationOptions }: EvaluationParameters): Promise<any>;

Check warning on line 135 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Unexpected any. Specify a different type

Check warning on line 135 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Unexpected any. Specify a different type
getBalance({ address, evaluationOptions }: EvaluationParameters<{ address: string }>): Promise<number>;

Check failure on line 136 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Replace `·address,·evaluationOptions` with `⏎····address,⏎····evaluationOptions,⏎·`

Check failure on line 136 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Replace `·address,·evaluationOptions` with `⏎····address,⏎····evaluationOptions,⏎·`
getBalances({ evaluationOptions }: EvaluationParameters): Promise<Record<string, number>>;

Check failure on line 137 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Replace `·evaluationOptions` with `⏎····evaluationOptions,⏎·`

Check failure on line 137 in src/common.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Replace `·evaluationOptions` with `⏎····evaluationOptions,⏎·`
}

/* eslint-disable @typescript-eslint/no-explicit-any */
export interface Logger {
setLogLevel: (level: string) => void;
Expand Down
93 changes: 93 additions & 0 deletions src/common/ant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* Copyright (C) 2022-2024 Permanent Data Solutions, Inc. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import {
ANTContract,

Check failure on line 18 in src/common/ant.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Delete `··`

Check failure on line 18 in src/common/ant.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Delete `··`
ANTRecord,

Check failure on line 19 in src/common/ant.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Replace `····` with `··`

Check failure on line 19 in src/common/ant.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Replace `····` with `··`
ANTState,
ContractConfiguration,
EvaluationOptions,
EvaluationParameters,
SmartWeaveContract,
isContractConfiguration,
isContractTxIdConfiguration,
} from '../types.js';
import { RemoteContract } from './contracts/remote-contract.js';

export class ANT implements ANTContract {
private contract: SmartWeaveContract<ANTState>;

constructor(config: ContractConfiguration) {

if (isContractConfiguration<ANTState>(config)) {
this.contract = config.contract;
} else if (isContractTxIdConfiguration(config)) {
this.contract = new RemoteContract<ANTState>({
contractTxId: config.contractTxId,
});
}
}

/**
* Returns the current state of the contract.
*/
async getState(params: EvaluationParameters): Promise<ANTState> {
const state = await this.contract.getContractState(params);
return state;
}

async getRecord({ domain, evaluationOptions }: EvaluationParameters<{ domain: string; }>): Promise<ANTRecord> {
const records = await this.getRecords({ evaluationOptions });

return records[domain]
}
async getRecords({ evaluationOptions }: { evaluationOptions?: EvaluationOptions | Record<string, never> | undefined; }): Promise<Record<string, ANTRecord>> {
const state = await this.contract.getContractState({ evaluationOptions });
return state.records;
}

async getOwner({ evaluationOptions }: { evaluationOptions?: EvaluationOptions | Record<string, never> | undefined; }): Promise<string> {
const state = await this.contract.getContractState({ evaluationOptions });
return state.owner;
}

async getControllers({ evaluationOptions }: { evaluationOptions?: EvaluationOptions | Record<string, never> | undefined; }): Promise<any[]> {

Check warning on line 67 in src/common/ant.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Unexpected any. Specify a different type

Check warning on line 67 in src/common/ant.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Unexpected any. Specify a different type
const state = await this.contract.getContractState({ evaluationOptions });
return state.controllers;
}

async getName({ evaluationOptions }: { evaluationOptions?: EvaluationOptions | Record<string, never> | undefined; }): Promise<any> {

Check warning on line 72 in src/common/ant.ts

View workflow job for this annotation

GitHub Actions / build (18.x, lint)

Unexpected any. Specify a different type

Check warning on line 72 in src/common/ant.ts

View workflow job for this annotation

GitHub Actions / build (20.x, lint)

Unexpected any. Specify a different type
const state = await this.contract.getContractState({ evaluationOptions });
return state.name;
}

async getTicker({ evaluationOptions }: { evaluationOptions?: EvaluationOptions | Record<string, never> | undefined; }): Promise<string> {
const state = await this.contract.getContractState({ evaluationOptions });
return state.ticker;
}

async getBalances({ evaluationOptions }: { evaluationOptions?: EvaluationOptions | Record<string, never> | undefined; }): Promise<Record<string, number>> {
const state = await this.contract.getContractState({ evaluationOptions });
return state.balances;
}

async getBalance({ address, evaluationOptions }: EvaluationParameters<{ address: string; }>): Promise<number> {
const balances = await this.getBalances({ evaluationOptions });
return balances[address];
}


}
23 changes: 3 additions & 20 deletions src/common/ar-io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,35 +19,18 @@ import {
ArIOContract,
ArIOState,
ArNSNameData,
ContractConfiguration,
EpochDistributionData,
EvaluationParameters,
Gateway,
Observations,
SmartWeaveContract,
WeightedObserver,
isContractConfiguration,
isContractTxIdConfiguration,
} from '../types.js';
import { RemoteContract } from './contracts/remote-contract.js';

// TODO: append this with other configuration options (e.g. local vs. remote evaluation)
export type ContractConfiguration =
| {
contract?: SmartWeaveContract<unknown>;
}
| {
contractTxId: string;
};

function isContractConfiguration<T>(
config: ContractConfiguration,
): config is { contract: SmartWeaveContract<T> } {
return 'contract' in config;
}

function isContractTxIdConfiguration(
config: ContractConfiguration,
): config is { contractTxId: string } {
return 'contractTxId' in config;
}

export class ArIO implements ArIOContract {
private contract: SmartWeaveContract<ArIOState>;
Expand Down
17 changes: 17 additions & 0 deletions src/contract-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,20 @@ export interface ArIOState {
vaults: RegistryVaults;
prescribedObservers: PrescribedObservers;
}


// ANT

export type ANTRecord = {
transactionId: string;
ttlSeconds: number;
};

export type ANTState = {
owner: WalletAddress;
controllers: WalletAddress[];
name: string;
ticker: string;
records: Record<string, ANTRecord>;
balances: Balances;
};
64 changes: 64 additions & 0 deletions tests/ant.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { ANT } from '../src/common/ant';
import { RemoteContract } from '../src/common/contracts/remote-contract';
import { ANTState } from '../src/contract-state';


describe('ANT contract apis', () => {

const ant = new ANT({
contract: new RemoteContract<ANTState>({
url: process.env.REMOTE_CACHE_URL || 'http://localhost:3000',
contractTxId: "UC2zwawQoTnh0TNd9mYLQS4wObBBeaOU5LPQTNETqA4",
}),
});

const sortKey = "000001383961,0000000000000,13987aba2d71b6229989690c15d2838a4deef0a90c3fc9e4d7227ed17e35d0bd";
const blockHeight = 1383961;

it.each([[{ sortKey }], [{ blockHeight }]])(`should get contract state with evaluation options: ${JSON.stringify('%s')}`, async (evalTo) => {
const state = await ant.getState({ evaluationOptions: { evalTo } });
expect(state).toBeDefined();
});

it.each([[{ sortKey }], [{ blockHeight }]])(`should get record: ${JSON.stringify('%s')}`, async (evalTo) => {
const record = await ant.getRecord({ domain: "@", evaluationOptions: { evalTo } });
expect(record).toBeDefined();
});

it.each([[{ sortKey }], [{ blockHeight }]])(`should get records with evaluation options: ${JSON.stringify('%s')}`, async (evalTo) => {
const records = await ant.getRecords({ evaluationOptions: { evalTo } });
console.dir({ records: records['@'] }, { depth: 4 })
expect(records).toBeDefined();
});

it.each([[{ sortKey }], [{ blockHeight }]])(`should get owner with evaluation options: ${JSON.stringify('%s')}`, async (evalTo) => {
const owner = await ant.getOwner({ evaluationOptions: { evalTo } });
expect(owner).toBeDefined();
});

it.each([[{ sortKey }], [{ blockHeight }]])(`should get controllers with evaluation options: ${JSON.stringify('%s')}`, async (evalTo) => {
const controllers = await ant.getControllers({ evaluationOptions: { evalTo } });
expect(controllers).toBeDefined();
});

it.each([[{ sortKey }], [{ blockHeight }]])(`should get name with evaluation options: ${JSON.stringify('%s')}`, async (evalTo) => {
const state = await ant.getName({ evaluationOptions: { evalTo } });
expect(state).toBeDefined();
});

it.each([[{ sortKey }], [{ blockHeight }]])(`should get ticker with evaluation options: ${JSON.stringify('%s')}`, async (evalTo) => {
const state = await ant.getTicker({ evaluationOptions: { evalTo } });
expect(state).toBeDefined();
});

it.each([[{ sortKey }], [{ blockHeight }]])(`should get balances with evaluation options: ${JSON.stringify('%s')}`, async (evalTo) => {
const state = await ant.getBalances({ evaluationOptions: { evalTo } });
expect(state).toBeDefined();
});

it.each([[{ sortKey }], [{ blockHeight }]])(`should get balance with evaluation options: ${JSON.stringify('%s')}`, async (evalTo) => {
const state = await ant.getBalance({ address: "TRVCopHzzO1VSwRUUS8umkiO2MpAL53XtVGlLaJuI94", evaluationOptions: { evalTo } });
expect(state).toBeDefined();
});

})

0 comments on commit 06bb36d

Please sign in to comment.