Skip to content

Commit

Permalink
Add abstracted contract interface to hyperdive/sdk (#355)
Browse files Browse the repository at this point in the history
  • Loading branch information
ryangoree authored Aug 29, 2023
1 parent 435dede commit e5f24a5
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 6 deletions.
1 change: 1 addition & 0 deletions packages/hyperdrive-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@hyperdrive/prettier-config": "*",
"@hyperdrive/tsconfig": "*",
"@parcel/transformer-typescript-types": "2.8.3",
"abitype": "^0.9.8",
"dotenv": "^16.0.3",
"happy-dom": "^10.7.0",
"parcel": "^2.8.0",
Expand Down
154 changes: 154 additions & 0 deletions packages/hyperdrive-sdk/src/base/abitype.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import {
Abi,
AbiParametersToPrimitiveTypes,
ExtractAbiFunction,
ExtractAbiFunctionNames,
AbiStateMutability,
ExtractAbiEventNames,
ExtractAbiEvent,
} from "abitype";
type EventName<TAbi extends Abi> = ExtractAbiEventNames<TAbi>;

/**
* Get a union of function names from an abi
*/
export type FunctionName<
TAbi extends Abi,
TAbiStateMutability extends AbiStateMutability = AbiStateMutability,
> = ExtractAbiFunctionNames<TAbi, TAbiStateMutability>;

/**
* Get an array of argument types for a function from an abi
*/
export type FunctionArgs<
TAbi extends Abi,
TFunctionName extends FunctionName<TAbi> = FunctionName<TAbi>,
> = AbiParametersToPrimitiveTypes<
ExtractAbiFunction<TAbi, TFunctionName>["inputs"],
"inputs"
>;

/**
* Get the return type of a function from an abi
*/
export type FunctionReturnType<
TAbi extends Abi,
TFunctionName extends FunctionName<TAbi> = FunctionName<TAbi>,
> = AbiParametersToPrimitiveTypes<
ExtractAbiFunction<TAbi, TFunctionName>["outputs"],
"outputs"
>[0];

/**
* Get a strongly typed function type from an abi
*/
export type ContractFunction<
TAbi extends Abi,
TAbiStateMutability extends AbiStateMutability = AbiStateMutability,
> = <TFunctionName extends FunctionName<TAbi, TAbiStateMutability>>(
fn: TFunctionName,
args: FunctionArgs<TAbi, TFunctionName>,
) => Promise<FunctionReturnType<TAbi, TFunctionName>>;

/**
* FilterArray<['a', 'b', 'c'], 'b'> = ['a', 'c']
*/
type FilterArray<T extends readonly any[], V> = T extends readonly [
infer L,
...infer R,
]
? L extends V
? [L, ...FilterArray<R, V>]
: [...FilterArray<R, V>]
: [];

/**
* Events in a contract abi look like this. There's obviously more fields, but
* these are the ones we care about.
*/
type AbiEventObject = { type: "address" | "uint256" };

/**
* A mapping of event abi "type" field values to their typescript equivalents.
*/
type TransformEventTypeMap = {
address: string;
uint256: bigint;
};

/**
* The resulting tuple of args values returned in an event from queryFilter.
*/
type TransformEventTypes<Tup extends readonly AbiEventObject[]> =
Tup extends readonly [
infer H extends AbiEventObject,
...infer R extends readonly AbiEventObject[],
]
? [TransformEventTypeMap[H["type"]], ...TransformEventTypes<R>]
: Tup;

/**
* A strongly typed Event you can expect back from calling queryFilter.
* eg: TypedEvent<erc20ABI, 'Transfer'> =
* { args: [from: string, to: string, amount: number]}
*/

export interface TypedEvent<
TAbi extends Abi,
TEventName extends ExtractAbiEventNames<TAbi>,
> extends Event {
args: TransformEventTypes<
FilterArray<
ExtractAbiEvent<TAbi, TEventName>["inputs"],
{ indexed: true } | { indexed: false }
>
>;
}

/**
* A mapping of event abi "type" field values to their typescript equivalents.
* This is for the filterArgs passed to queryFilter, so each one can also be
* null.
*/
type TransformFilterTypeMap = {
address: string | null;
uint256: bigint | null;
};

/**
* Identical to TransformEventTypes, however the resulting tuple will have null
* as an option for each value. These are the accepted filterArgs values when
* using queryFilter
*/
type TransformFilterTypes<Tup extends readonly AbiEventObject[]> =
Tup extends readonly [
infer H extends AbiEventObject,
...infer R extends readonly AbiEventObject[],
]
? [TransformFilterTypeMap[H["type"]], ...TransformFilterTypes<R>]
: Tup;

/**
* The filterArgs tuple containing all possible indexed fields you can use with
* queryFilter, eg:
*
* ExtractEventFilterArgs<erc20ABI, 'Transfer'> =
* [from: string | null, to: string | null]
*/
export type EventFilter<
TAbi extends Abi,
TEventName extends ExtractAbiEventNames<TAbi>,
> = TransformFilterTypes<
FilterArray<ExtractAbiEvent<TAbi, TEventName>["inputs"], { indexed: true }>
>;

type BlockTag = "latest" | "earliest" | "pending" | "safe" | "finalized";

export type ContractEventFunction<TAbi extends Abi> = <
TEventName extends EventName<TAbi>,
>(
eventName: TEventName,
fromBlock: bigint | BlockTag,
toBlock: bigint | BlockTag,
filter: EventFilter<TAbi, TEventName>,
) => Promise<TypedEvent<TAbi, TEventName>[]>;
15 changes: 15 additions & 0 deletions packages/hyperdrive-sdk/src/contract/Contract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Abi, Address } from "abitype";
import { ContractEventFunction, ContractFunction } from "src/base/abitype";

/**
* An abstracted contract interface to allow interchangeable web3 libraries.
* Designed to be used by consumers that care about the interface of a contract,
* but aren't necessarily concerned with where it's deployed or how it connects.
*/
export interface Contract<TAbi extends Abi> {
abi: TAbi;
address: Address;
read: ContractFunction<TAbi>;
write: ContractFunction<TAbi, "nonpayable" | "payable">;
getEvents: ContractEventFunction<TAbi>;
}
12 changes: 6 additions & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3335,6 +3335,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.9.3.tgz#294d25288ee683d72baf4e1fed757034e3c8c277"
integrity sha512-dz4qCQLurx97FQhnb/EIYTk/ldQ+oafEDUqC0VVIeQS1Q48/YWt/9YNfMmp9SLFqN41ktxny3c8aYxHjmFIB/w==

abitype@^0.9.8:
version "0.9.8"
resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.9.8.tgz#1f120b6b717459deafd213dfbf3a3dd1bf10ae8c"
integrity sha512-puLifILdm+8sjyss4S+fsUN09obiT1g2YW6CtcQF+QDzxR0euzgEB29MZujC6zMk2a6SVmtttq1fc6+YFA7WYQ==

abortcontroller-polyfill@^1.1.9:
version "1.7.5"
resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed"
Expand Down Expand Up @@ -10064,12 +10069,7 @@ [email protected]:
dependencies:
is-typedarray "^1.0.0"

typescript@^4.7.4, typescript@^4.9.3:
version "4.9.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==

typescript@^5.0.2:
typescript@^4.7.4, typescript@^4.9.3, typescript@^5.0.2:
version "5.1.6"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274"
integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
Expand Down

3 comments on commit e5f24a5

@vercel
Copy link

@vercel vercel bot commented on e5f24a5 Aug 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

hyperdrive-monorepo-hyperdrive-trading – ./apps/hyperdrive-trading

hyperdrive-monorepo-hyperdrive-trading-delvtech.vercel.app
hyperdrive-monorepo-hyperdrive-trading-git-main-delvtech.vercel.app
hyperdrive-monorepo-hyperdrive-trading.vercel.app

@vercel
Copy link

@vercel vercel bot commented on e5f24a5 Aug 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

hyperdrive-sdk-docs – ./apps/hyperdrive-sdk-docs

hyperdrive-sdk-docs-delvtech.vercel.app
hyperdrive-sdk-docs.vercel.app
hyperdrive-sdk-docs-git-main-delvtech.vercel.app

@vercel
Copy link

@vercel vercel bot commented on e5f24a5 Aug 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

hyperdrive-fixed-borrow – ./apps/fixed-borrow

hyperdrive-fixed-borrow-git-main-delvtech.vercel.app
hyperdrive-fixed-borrow-delvtech.vercel.app
hyperdrive-fixed-borrow.vercel.app

Please sign in to comment.