Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(types): use generic types and make config optional on init for ArIO client #52

Merged
merged 10 commits into from
Apr 25, 2024
2 changes: 1 addition & 1 deletion examples/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</script>

<script type="module" defer>
import { ArIO } from 'https://unpkg.com/@ar.io/sdk@1.0.0';
import { ArIO } from '../../bundles/web.bundle.min.js';

const arIO = ArIO.init();

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"prepare": "husky install",
"example:mjs": "yarn build:esm && node examples/node/index.mjs",
"example:cjs": "yarn build:cjs && node examples/node/index.cjs",
"example:web": "yarn build:web && cp -r bundles/* examples/web && http-server --port 8080 --host -o examples/web"
"example:web": "yarn build:web && http-server --port 8080 --host -o examples/web"
},
"devDependencies": {
"@commitlint/cli": "^17.1.2",
Expand Down
41 changes: 18 additions & 23 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,18 @@ export type TransactionId = string;

// TODO: append this with other configuration options (e.g. local vs. remote evaluation)
export type ContractSigner = ArweaveSigner | ArconnectSigner;
export type WithSigner = { signer: ContractSigner }; // TODO: optionally allow JWK in place of signer
export type ContractConfiguration =
export type WithSigner<T = NonNullable<unknown>> = {
signer: ContractSigner;
} & T; // TODO: optionally allow JWK in place of signer
export type OptionalSigner<T = NonNullable<unknown>> = {
signer?: ContractSigner;
} & T;
export type ContractConfiguration<T = NonNullable<unknown>> =
| {
contract?: WarpContract<unknown> | RemoteContract<unknown>;
contract?: WarpContract<T> | RemoteContract<T>;
}
| {
contractTxId: string;
contractTxId?: string;
};

export type EvaluationOptions = {
Expand All @@ -63,13 +68,15 @@ export type EvaluationParameters<T = NonNullable<unknown>> = {
evaluationOptions?: EvaluationOptions | Record<string, never> | undefined;
} & T;

export type WriteParameters<Input> = {
export type ReadParameters<Input> = {
functionName: string;
inputs: Input;
dryWrite?: boolean;
// TODO: add syncState and abortSignal options
inputs?: Input;
};

export type WriteParameters<Input> = WithSigner<
Required<ReadParameters<Input>>
>;

export interface BaseContract<T> {
getState(params: EvaluationParameters): Promise<T>;
}
Expand All @@ -79,10 +86,7 @@ export interface ReadContract {
functionName,
inputs,
evaluationOptions,
}: EvaluationParameters<{
functionName: string;
inputs?: Input;
}>): Promise<State>;
}: EvaluationParameters<ReadParameters<Input>>): Promise<State>;
}

export interface WriteContract {
Expand All @@ -95,15 +99,6 @@ export interface WriteContract {
>): Promise<WriteInteractionResult>;
}

export interface SmartWeaveContract<T> {
getContractState(params: EvaluationParameters): Promise<T>;
readInteraction<I, K>({
functionName,
inputs,
evaluationOptions,
}: EvaluationParameters<{ functionName: string; inputs?: I }>): Promise<K>;
}

// TODO: extend with additional methods
export interface ArIOReadContract extends BaseContract<ArIOState> {
getGateway({
Expand Down Expand Up @@ -139,9 +134,9 @@ export interface ArIOReadContract extends BaseContract<ArIOState> {
getEpoch({
blockHeight,
evaluationOptions,
}: {
}: EvaluationParameters<{
blockHeight: number;
} & EvaluationParameters): Promise<EpochDistributionData>;
}>): Promise<EpochDistributionData>;
getCurrentEpoch({
evaluationOptions,
}: EvaluationParameters): Promise<EpochDistributionData>;
Expand Down
72 changes: 44 additions & 28 deletions src/common/ant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
ContractSigner,
EvaluationOptions,
EvaluationParameters,
OptionalSigner,
WithSigner,
WriteInteractionResult,
} from '../types.js';
Expand All @@ -47,15 +48,18 @@ export class ANT {
* ANT.createContract({ contractTxId: 'myContractTxId' });
* ```
*/
static createContract(config: ContractConfiguration): WarpContract<ANTState> {
static createWriteableContract(
config: Required<ContractConfiguration<ANTState>>,
): WarpContract<ANTState> {
if (isContractConfiguration<ANTState>(config)) {
if (config.contract instanceof WarpContract) {
return config.contract;
}
return config.contract instanceof WarpContract
? config.contract
: new WarpContract<ANTState>(config.contract.configuration());
} else if (isContractTxIdConfiguration(config)) {
return new WarpContract<ANTState>({ contractTxId: config.contractTxId });
} else {
throw new InvalidContractConfigurationError();
}
throw new InvalidContractConfigurationError();
}

/**
Expand All @@ -82,23 +86,20 @@ export class ANT {
* const readable = ANT.init({ contract: myContract });
* ```
*/
static init(
config: ContractConfiguration &
WithSigner &
({ contract: WarpContract<ANTState> } | { contractTxId: string }),
): ANTWritable;
static init(
config?: ContractConfiguration &
({ contract?: RemoteContract<ANTState> } | { contractTxId: string }),
): ANTReadable;
static init(
config: ContractConfiguration & {
signer?: ContractSigner;
} = {},
) {
if (config?.signer) {
const signer = config.signer;
const contract = this.createContract(config);
static init(config: Required<ContractConfiguration<ANTState>>): ANTReadable;
static init({
signer,
...config
}: WithSigner<
// must be a WarpContract to get a ArIOWriteable
{ contract: WarpContract<ANTState> } | { contractTxId: string }
>): ANTWritable;
static init({
signer,
...config
}: OptionalSigner<Required<ContractConfiguration<ANTState>>>) {
if (signer) {
const contract = this.createWriteableContract(config);
return new ANTWritable({ signer, contract });
} else {
return new ANTReadable(config);
Expand All @@ -109,13 +110,15 @@ export class ANT {
export class ANTReadable implements ANTReadContract {
protected contract: RemoteContract<ANTState> | WarpContract<ANTState>;

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

Expand Down Expand Up @@ -325,7 +328,7 @@ export class ANTReadable implements ANTReadContract {
evaluationOptions,
}: EvaluationParameters<{ address: string }>): Promise<number> {
const balances = await this.getBalances({ evaluationOptions });
return balances[address];
return balances[address] || 0;
}
}

Expand All @@ -334,11 +337,24 @@ export class ANTWritable extends ANTReadable {
private signer: ContractSigner;

constructor({
contract,
signer,
}: { contract: WarpContract<ANTState> } & WithSigner) {
super({ contract });
this.signer = signer;
...config
}: WithSigner<
{ contract: WarpContract<ANTState> } | { contractTxId: string }
>) {
if (isContractConfiguration<ANTState>(config)) {
super({ contract: config.contract });
this.signer = signer;
} else if (isContractTxIdConfiguration(config)) {
super({
contract: new WarpContract<ANTState>({
contractTxId: config.contractTxId,
}),
});
this.signer = signer;
} else {
throw new InvalidContractConfigurationError();
}
}

/**
Expand Down
Loading
Loading