@onrail-xyz/evm 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js ADDED
@@ -0,0 +1,79 @@
1
+ import { hex, argOf } from "@onrail-xyz/utils";
2
+ import { serialize, isItem, isOmitted, calcStaticSize } from "@onrail-xyz/binary-layout";
3
+ import { toAtomicIfAmount } from "@onrail-xyz/common";
4
+ import { wordSize, selectorLayout, paddedSlotLayout, abiEncodedBytesItem, signatureOf } from "./layouting.js";
5
+ //the marker `trailingBytesParam` sets, read only here - nothing outside the spec builder asks
6
+ // whether a param is the dynamic one
7
+ const isDynamicParam = (param) => "dynamic" in param;
8
+ //viem spells call data as hex and values as bigint where this package speaks bytes and amounts,
9
+ // and calls the sender `account` because it also accepts a whole Account: every field is
10
+ // converted so that consumers hand the result straight to sendTransaction/estimateGas
11
+ export const toViemTx = (tx) => ({
12
+ to: tx.to,
13
+ data: hex.encode(tx.data, true),
14
+ ...(tx.from !== undefined && { account: tx.from }),
15
+ ...(tx.value !== undefined && { value: toAtomicIfAmount(tx.value) }),
16
+ ...(tx.accessList !== undefined && { accessList: tx.accessList }),
17
+ });
18
+ //the composer is contextually typed from the params, so it is written with names only
19
+ export const abiFunction = (name, params, composer, ...output) => [name, params, composer, argOf(output)];
20
+ function resolveArgs(layout, composer, args) {
21
+ //For 0 or 2+ args, it's unambiguously the composer (positional) form.
22
+ //For a single object arg, it's ambiguous only when the layout has exactly one non-omitted
23
+ // field — the arg could be the object form { name: value } or a struct passed positionally.
24
+ // We assume object form if the object has exactly one key matching that field's name.
25
+ // For 2+ non-omitted fields, a single arg must be object form (positional would have multiple).
26
+ if (args.length === 1 && typeof args[0] === "object" && args[0] !== null) {
27
+ let nonOmittedCount = 0;
28
+ let firstName;
29
+ for (const [name, field] of Object.entries(layout)) {
30
+ if (isItem(field) && isOmitted(field))
31
+ continue;
32
+ if (++nonOmittedCount > 1)
33
+ return args[0];
34
+ firstName = name;
35
+ }
36
+ //single non-omitted field: assume object form if the object has exactly one matching key
37
+ const keys = Object.keys(args[0]);
38
+ if (keys.length === 1 && keys[0] === firstName)
39
+ return args[0];
40
+ }
41
+ return composer(...args);
42
+ }
43
+ export const contractFromSpec = (contract, spec) => {
44
+ const result = {};
45
+ for (const [name, params, composer, outputLayout] of spec) {
46
+ const [key, abiName] = typeof name === "string" ? [name, name] : name;
47
+ const sig = signatureOf(abiName, params);
48
+ const dynamicIndex = params.findIndex(isDynamicParam);
49
+ //a second dynamic param cannot be last either, so the one check covers both
50
+ if (dynamicIndex >= 0 && dynamicIndex !== params.length - 1)
51
+ throw new Error(`${sig}: a dynamic parameter must be the only one, and come last`);
52
+ //the dynamic payload follows the whole head, which is not one word per preceding param:
53
+ // a static tuple param spans as many slots as it has members
54
+ const staticFields = params.filter(param => !isDynamicParam(param))
55
+ .map(param => paddedSlotLayout(param.item));
56
+ const headSize = staticFields.reduce((sum, field) => sum + calcStaticSize(field), wordSize);
57
+ let staticIndex = 0;
58
+ const inputLayout = Object.fromEntries(params.map(param => [
59
+ param.name,
60
+ isDynamicParam(param)
61
+ ? abiEncodedBytesItem({ layout: param.dynamic.layout, offset: headSize })
62
+ : staticFields[staticIndex++],
63
+ ]));
64
+ const layout = selectorLayout(sig)(inputLayout);
65
+ const method = (...args) => ({
66
+ to: contract,
67
+ data: outputLayout !== undefined
68
+ ? [layout, resolveArgs(inputLayout, composer, args), outputLayout]
69
+ : serialize(layout, resolveArgs(inputLayout, composer, args)),
70
+ });
71
+ //shape-dispatching methods would report length 0; stamp the positional arity so it stays
72
+ // observable, e.g. for arity-driven call batching
73
+ Object.defineProperty(method, "length", { value: composer.length });
74
+ if (Object.hasOwn(result, key))
75
+ throw new Error(`duplicate method key: ${key}`);
76
+ result[key] = method;
77
+ }
78
+ return result;
79
+ };
@@ -0,0 +1,72 @@
1
+ import type { Address, Hex } from "viem";
2
+ import type { RoUint8Array, RoArray, StrRecord, DeepRo } from "@onrail-xyz/utils";
3
+ import type { BytesNItem } from "./layouting.js";
4
+ import { abiAddressItem, abiBoolItem, uint256Item } from "./layouting.js";
5
+ export type Eip712Field = {
6
+ readonly name: string;
7
+ readonly type: string;
8
+ };
9
+ type Eip712Value<T extends string> = string extends T ? Address | boolean | bigint | RoUint8Array | string : T extends "address" ? Address : T extends "bool" ? boolean : T extends `uint${number}` | `int${number}` ? bigint : T extends `bytes${number}` | "bytes" ? RoUint8Array : T extends "string" ? string : never;
10
+ export type Eip712Message<F extends RoArray<Eip712Field> = RoArray<Eip712Field>> = {
11
+ readonly [E in F[number] as E["name"]]: Eip712Value<E["type"]>;
12
+ };
13
+ declare const domainSeparatorFields: readonly [{
14
+ readonly name: "name";
15
+ readonly type: "string";
16
+ }, {
17
+ readonly name: "version";
18
+ readonly type: "string";
19
+ }, {
20
+ readonly name: "chainId";
21
+ readonly type: "uint256";
22
+ }, {
23
+ readonly name: "verifyingContract";
24
+ readonly type: "address";
25
+ }, {
26
+ readonly name: "salt";
27
+ readonly type: "bytes32";
28
+ }];
29
+ export type Eip712Domain = Partial<Eip712Message<typeof domainSeparatorFields>>;
30
+ export type Eip712Data<Message = StrRecord> = {
31
+ readonly types: StrRecord<RoArray<Eip712Field>>;
32
+ readonly primaryType: string;
33
+ readonly domain: Eip712Domain;
34
+ readonly message: DeepRo<Message>;
35
+ };
36
+ export type ViemTypedData<T> = T extends RoUint8Array ? Hex : T extends object ? {
37
+ readonly [K in keyof T]: ViemTypedData<T[K]>;
38
+ } : T;
39
+ export declare const toViemTypedData: <T>(value: T) => ViemTypedData<T>;
40
+ declare const int256Item: {
41
+ readonly binary: "int";
42
+ readonly size: 32;
43
+ };
44
+ type WordItem<T extends string> = T extends "bool" ? typeof abiBoolItem : T extends "address" ? typeof abiAddressItem : T extends `uint${number}` ? typeof uint256Item : T extends `int${number}` ? typeof int256Item : T extends `bytes${infer N extends number}` ? BytesNItem<N> : never;
45
+ export type Eip712EncodeDataLayout<F extends RoArray<Eip712Field>> = {
46
+ readonly [E in F[number] as E["name"]]: WordItem<E["type"]>;
47
+ };
48
+ export declare const eip712EncodeDataLayout: <const F extends RoArray<Eip712Field>>(fields: F) => Eip712EncodeDataLayout<F>;
49
+ export declare const eip712DomainType: (domain: Eip712Domain) => ({
50
+ readonly name: "name";
51
+ readonly type: "string";
52
+ } | {
53
+ readonly name: "version";
54
+ readonly type: "string";
55
+ } | {
56
+ readonly name: "chainId";
57
+ readonly type: "uint256";
58
+ } | {
59
+ readonly name: "verifyingContract";
60
+ readonly type: "address";
61
+ } | {
62
+ readonly name: "salt";
63
+ readonly type: "bytes32";
64
+ })[];
65
+ export declare const guessEip712Domain: (name: string, verifyingContract: Address, chainId: bigint, domainSeparator: RoUint8Array, versionGuesses?: RoArray<string>) => {
66
+ readonly name: string;
67
+ readonly version?: string;
68
+ readonly chainId: bigint;
69
+ readonly verifyingContract: `0x${string}`;
70
+ };
71
+ export {};
72
+ //# sourceMappingURL=eip712.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eip712.d.ts","sourceRoot":"","sources":["../src/eip712.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAY,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAM5F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAY,cAAc,EAAE,WAAW,EAAE,WAAW,EAAc,MAAM,gBAAgB,CAAC;AAIhG,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAK3E,KAAK,WAAW,CAAC,CAAC,SAAS,MAAM,IAC/B,MAAM,SAAS,CAAC,GACd,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,MAAM,GAClD,CAAC,SAAS,SAAS,GACnB,OAAO,GACP,CAAC,SAAS,MAAM,GAChB,OAAO,GACP,CAAC,SAAS,OAAO,MAAM,EAAE,GAAG,MAAM,MAAM,EAAE,GAC1C,MAAM,GACN,CAAC,SAAS,QAAQ,MAAM,EAAE,GAAG,OAAO,GACpC,YAAY,GACZ,CAAC,SAAS,QAAQ,GAClB,MAAM,GACN,KAAK,CAAC;AAIV,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,IAC7E;IAAE,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;CAAE,CAAC;AAErE,QAAA,MAAM,qBAAqB;aACvB,IAAI,EAAE,MAAM;aAAe,IAAI,EAAE,QAAQ;;aACzC,IAAI,EAAE,SAAS;aAAY,IAAI,EAAE,QAAQ;;aACzC,IAAI,EAAE,SAAS;aAAY,IAAI,EAAE,SAAS;;aAC1C,IAAI,EAAE,mBAAmB;aAAE,IAAI,EAAE,SAAS;;aAC1C,IAAI,EAAE,MAAM;aAAe,IAAI,EAAE,SAAS;EACpC,CAAC;AAKX,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC;AAEhF,MAAM,MAAM,UAAU,CAAC,OAAO,GAAG,SAAS,IAAI;IAC5C,QAAQ,CAAC,KAAK,EAAQ,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAO,YAAY,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAM,MAAM,CAAC,OAAO,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,CAAC,IACzB,CAAC,SAAS,YAAY,GACpB,GAAG,GACH,CAAC,SAAS,MAAM,GAChB;IAAE,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAChD,CAAC,CAAC;AAIN,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,CAAC,KAAG,aAAa,CAAC,CAAC,CAQxC,CAAC;AAUtB,QAAA,MAAM,UAAU;aAAK,MAAM,EAAE,KAAK;aAAE,IAAI;CAAqB,CAAC;AAE9D,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,IAC5B,CAAC,SAAS,MAAM,GACd,OAAO,WAAW,GAClB,CAAC,SAAS,SAAS,GACnB,OAAO,cAAc,GACrB,CAAC,SAAS,OAAO,MAAM,EAAE,GACzB,OAAO,WAAW,GAClB,CAAC,SAAS,MAAM,MAAM,EAAE,GACxB,OAAO,UAAU,GACjB,CAAC,SAAS,QAAQ,MAAM,CAAC,SAAS,MAAM,EAAE,GAC1C,UAAU,CAAC,CAAC,CAAC,GACb,KAAK,CAAC;AAmBV,MAAM,MAAM,sBAAsB,CAAC,CAAC,SAAS,OAAO,CAAC,WAAW,CAAC,IAC/D;IAAE,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;CAAE,CAAC;AAElE,eAAO,MAAM,sBAAsB,GAChC,KAAK,CAAC,CAAC,SAAS,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC,KAAG,sBAAsB,CAAC,CAAC,CACmB,CAAC;AAMjG,eAAO,MAAM,gBAAgB,WAAY,YAAY;mBAzF3C,MAAM;mBAAqB,QAAQ;;mBACnC,SAAS;mBAAkB,QAAQ;;mBACnC,SAAS;mBAAkB,SAAS;;mBACpC,mBAAmB;mBAAQ,SAAS;;mBACpC,MAAM;mBAAqB,SAAS;IAsFmB,CAAC;AAqElE,eAAO,MAAM,iBAAiB,SACT,MAAM,qBACN,OAAO,WACP,MAAM,mBACN,YAAY,mBACZ,OAAO,CAAC,MAAM,CAAC;;;;;CAYnC,CAAC"}
package/dist/eip712.js ADDED
@@ -0,0 +1,96 @@
1
+ import { bytes, hex, utf8 } from "@onrail-xyz/utils";
2
+ import { serialize } from "@onrail-xyz/binary-layout";
3
+ import { hashItem } from "@onrail-xyz/common";
4
+ import { keccak256 } from "./hashing.js";
5
+ import { wordSize, abiAddressItem, abiBoolItem, uint256Item, bytesNItem } from "./layouting.js";
6
+ const domainSeparatorFields = [
7
+ { name: "name", type: "string" },
8
+ { name: "version", type: "string" },
9
+ { name: "chainId", type: "uint256" },
10
+ { name: "verifyingContract", type: "address" },
11
+ { name: "salt", type: "bytes32" },
12
+ ];
13
+ //viem spells bytes values as hex where this package speaks bytes: every bytes leaf of domain and
14
+ // message is converted so that consumers hand the result straight to signTypedData/hashTypedData
15
+ export const toViemTypedData = (value) => (value instanceof Uint8Array
16
+ ? hex.encode(value, true)
17
+ : Array.isArray(value)
18
+ ? value.map(toViemTypedData)
19
+ : typeof value === "object" && value !== null
20
+ ? Object.fromEntries(Object.entries(value).map(([k, v]) => [k, toViemTypedData(v)]))
21
+ : value);
22
+ // ---- encodeData ----
23
+ // A struct's encodeData puts each atomic field on a word, in field order, so a layout spelled
24
+ // from the field list serializes a message to exactly those bytes and reads one back - which
25
+ // is how a message is derived from data that already has a word-per-field layout. A dynamic
26
+ // (`bytes`, `string`), array or struct-typed field takes a word too, but holding a hash this
27
+ // layout does not compute, so such a field is rejected. Values ride at word width: a `uint8`
28
+ // field's range is its composer's to keep.
29
+ const int256Item = { binary: "int", size: wordSize };
30
+ const wordItem = (type) => {
31
+ if (type === "bool")
32
+ return abiBoolItem;
33
+ if (type === "address")
34
+ return abiAddressItem;
35
+ if (/^uint\d+$/.test(type))
36
+ return uint256Item;
37
+ if (/^int\d+$/.test(type))
38
+ return int256Item;
39
+ const bytesN = /^bytes(\d+)$/.exec(type);
40
+ if (bytesN !== null)
41
+ return bytesNItem(Number(bytesN[1]));
42
+ throw new Error(`EIP-712 type '${type}' has no encodeData word - only atomic types are encoded`);
43
+ };
44
+ export const eip712EncodeDataLayout = (fields) => Object.fromEntries(fields.map(f => [f.name, wordItem(f.type)]));
45
+ // ---- Domain Separator ----
46
+ //the domain's type as viem derives it - the fields present, in the standard's order - so a message
47
+ // composed with it hashes identically on both sides
48
+ export const eip712DomainType = (domain) => domainSeparatorFields.filter(f => domain[f.name] !== undefined);
49
+ const associatedLayoutItem = {
50
+ name: hashItem,
51
+ version: hashItem,
52
+ chainId: { binary: "uint", size: wordSize },
53
+ verifyingContract: abiAddressItem,
54
+ salt: hashItem,
55
+ };
56
+ const hashString = (s) => keccak256(utf8.encode(s));
57
+ const typeString = (fields) => "EIP712Domain("
58
+ + domainSeparatorFields //enforces correct order (iterating over fields would not)
59
+ .filter(dsf => fields.includes(dsf.name))
60
+ .map(dsf => `${dsf.type} ${dsf.name}`)
61
+ .join(",")
62
+ + ")";
63
+ const typeHash = (fields) => hashString(typeString(fields));
64
+ const typeHashItem = (fields) => ({ binary: "bytes", fixed: typeHash(fields) });
65
+ const separatorLayout = (fields) => ({
66
+ typeHash: typeHashItem(fields),
67
+ ...Object.fromEntries(domainSeparatorFields //enforces correct order (iterating over fields would not)
68
+ .filter(dsf => fields.includes(dsf.name))
69
+ .map(dsf => [dsf.name, associatedLayoutItem[dsf.name]])),
70
+ });
71
+ const matchesHash = (layout, candidate, expected) => bytes.equals(keccak256(serialize(layout, candidate)), expected);
72
+ // ---- Domain Resolution ----
73
+ // Reconstructs the domain of tokens that only expose DOMAIN_SEPARATOR() by brute-forcing the
74
+ // version field against the on-chain hash. Covers the { name, chainId, verifyingContract } domain
75
+ // with an optional version, i.e. everything that follows EIP-2612's reference implementation.
76
+ const typicalDomainFields = ["name", "chainId", "verifyingContract"];
77
+ const unversionedLayout = separatorLayout(typicalDomainFields);
78
+ const versionedLayout = separatorLayout([...typicalDomainFields, "version"]);
79
+ const guessDomainSeparatorVersion = (known, domainSeparator, guesses) => {
80
+ for (const version of guesses)
81
+ if (matchesHash(versionedLayout, { ...known, version: hashString(version) }, domainSeparator))
82
+ return version;
83
+ throw new Error("Could not determine domain separator version");
84
+ };
85
+ //reconstructs the EIP-712 domain from on-chain data, guesses the version if needed
86
+ export const guessEip712Domain = (name, verifyingContract, chainId, domainSeparator, versionGuesses = ["1", "2", "0"]) => {
87
+ const known = { name: hashString(name), chainId, verifyingContract };
88
+ return {
89
+ name,
90
+ ...(matchesHash(unversionedLayout, known, domainSeparator)
91
+ ? {}
92
+ : { version: guessDomainSeparatorVersion(known, domainSeparator, versionGuesses) }),
93
+ chainId,
94
+ verifyingContract,
95
+ };
96
+ };
@@ -0,0 +1,113 @@
1
+ import type { Address } from "viem";
2
+ import type { OptionalArg } from "@onrail-xyz/utils";
3
+ import type { KindWithAtomic } from "@onrail-xyz/amount";
4
+ import type { ContractMethods } from "./client.js";
5
+ declare const erc20Spec: <const K extends KindWithAtomic | undefined = undefined>(...kind: OptionalArg<K>) => readonly [import("./client.js").FuncSpec<"name", readonly [], () => {}, Readonly<{
6
+ custom: Readonly<{
7
+ to: import("@onrail-xyz/utils").Function<[{
8
+ readonly item: import("@onrail-xyz/utils").RoUint8Array;
9
+ readonly postPadding: import("@onrail-xyz/utils").RoUint8Array;
10
+ }], string>;
11
+ from: import("@onrail-xyz/utils").Function<[string], {
12
+ readonly item: import("@onrail-xyz/utils").RoUint8Array;
13
+ readonly postPadding: import("@onrail-xyz/utils").RoUint8Array;
14
+ }>;
15
+ }>;
16
+ readonly binary: "bytes";
17
+ readonly layout: {
18
+ readonly offset: {
19
+ readonly binary: "uint";
20
+ readonly size: 32;
21
+ readonly fixed: bigint;
22
+ };
23
+ readonly lengthPadding: {
24
+ readonly binary: "bytes";
25
+ readonly fixed: Uint8Array<ArrayBuffer>;
26
+ };
27
+ readonly item: {
28
+ readonly binary: "bytes";
29
+ readonly size: {
30
+ readonly binary: "uint";
31
+ readonly size: 4;
32
+ };
33
+ };
34
+ readonly postPadding: {
35
+ readonly binary: "bytes";
36
+ };
37
+ };
38
+ }>>, import("./client.js").FuncSpec<"symbol", readonly [], () => {}, Readonly<{
39
+ custom: Readonly<{
40
+ to: import("@onrail-xyz/utils").Function<[{
41
+ readonly item: import("@onrail-xyz/utils").RoUint8Array;
42
+ readonly postPadding: import("@onrail-xyz/utils").RoUint8Array;
43
+ }], string>;
44
+ from: import("@onrail-xyz/utils").Function<[string], {
45
+ readonly item: import("@onrail-xyz/utils").RoUint8Array;
46
+ readonly postPadding: import("@onrail-xyz/utils").RoUint8Array;
47
+ }>;
48
+ }>;
49
+ readonly binary: "bytes";
50
+ readonly layout: {
51
+ readonly offset: {
52
+ readonly binary: "uint";
53
+ readonly size: 32;
54
+ readonly fixed: bigint;
55
+ };
56
+ readonly lengthPadding: {
57
+ readonly binary: "bytes";
58
+ readonly fixed: Uint8Array<ArrayBuffer>;
59
+ };
60
+ readonly item: {
61
+ readonly binary: "bytes";
62
+ readonly size: {
63
+ readonly binary: "uint";
64
+ readonly size: 4;
65
+ };
66
+ };
67
+ readonly postPadding: {
68
+ readonly binary: "bytes";
69
+ };
70
+ };
71
+ }>>, import("./client.js").FuncSpec<"decimals", readonly [], () => {}, Readonly<{
72
+ binary: "bytes";
73
+ layout: {
74
+ readonly _padding: {
75
+ readonly binary: "bytes";
76
+ readonly fixed: Uint8Array<ArrayBuffer>;
77
+ };
78
+ readonly item: {
79
+ readonly binary: "uint";
80
+ readonly size: 1;
81
+ };
82
+ };
83
+ custom: import("@onrail-xyz/binary-layout").Conversion<{
84
+ readonly item: number;
85
+ }, number>;
86
+ }>>, import("./client.js").FuncSpec<"totalSupply", readonly [], () => {}, import("@onrail-xyz/common").AmountItem<32, K>>, import("./client.js").FuncSpec<"balanceOf", readonly [import("./layouting.js").AbiParam<"owner", "address", import("./layouting.js").AddressItem, `0x${string}`>], (owner: `0x${string}`) => {
87
+ owner: `0x${string}`;
88
+ }, import("@onrail-xyz/common").AmountItem<32, K>>, import("./client.js").FuncSpec<"allowance", readonly [import("./layouting.js").AbiParam<"owner", "address", import("./layouting.js").AddressItem, `0x${string}`>, import("./layouting.js").AbiParam<"spender", "address", import("./layouting.js").AddressItem, `0x${string}`>], (owner: `0x${string}`, spender: `0x${string}`) => {
89
+ owner: `0x${string}`;
90
+ spender: `0x${string}`;
91
+ }, import("@onrail-xyz/common").AmountItem<32, K>>, import("./client.js").FuncSpec<"approve", readonly [import("./layouting.js").AbiParam<"spender", "address", import("./layouting.js").AddressItem, `0x${string}`>, import("./layouting.js").AbiParam<"value", "uint256", import("@onrail-xyz/common").AmountItem<32, K>, import("@onrail-xyz/common").AmountOr<K, bigint>>], (spender: `0x${string}`, value: import("@onrail-xyz/common").AmountOr<K, bigint>) => {
92
+ spender: `0x${string}`;
93
+ value: import("@onrail-xyz/common").AmountOr<K, bigint>;
94
+ }, undefined>, import("./client.js").FuncSpec<"transfer", readonly [import("./layouting.js").AbiParam<"to", "address", import("./layouting.js").AddressItem, `0x${string}`>, import("./layouting.js").AbiParam<"value", "uint256", import("@onrail-xyz/common").AmountItem<32, K>, import("@onrail-xyz/common").AmountOr<K, bigint>>], (to: `0x${string}`, value: import("@onrail-xyz/common").AmountOr<K, bigint>) => {
95
+ to: `0x${string}`;
96
+ value: import("@onrail-xyz/common").AmountOr<K, bigint>;
97
+ }, undefined>, import("./client.js").FuncSpec<"transferFrom", readonly [import("./layouting.js").AbiParam<"from", "address", import("./layouting.js").AddressItem, `0x${string}`>, import("./layouting.js").AbiParam<"to", "address", import("./layouting.js").AddressItem, `0x${string}`>, import("./layouting.js").AbiParam<"value", "uint256", import("@onrail-xyz/common").AmountItem<32, K>, import("@onrail-xyz/common").AmountOr<K, bigint>>], (from: `0x${string}`, to: `0x${string}`, value: import("@onrail-xyz/common").AmountOr<K, bigint>) => {
98
+ from: `0x${string}`;
99
+ to: `0x${string}`;
100
+ value: import("@onrail-xyz/common").AmountOr<K, bigint>;
101
+ }, undefined>];
102
+ export declare const erc20: <const K extends KindWithAtomic | undefined = undefined>(contract: Address, ...kind: OptionalArg<K>) => ContractMethods<ReturnType<typeof erc20Spec<K>>>;
103
+ export declare const erc20Events: <const K extends KindWithAtomic | undefined = undefined>(...kind: OptionalArg<K>) => readonly [import("./layouting.js").SigVariantOf<"Transfer", readonly [import("./layouting.js").AbiParam<"from", "address", import("./layouting.js").AddressItem, `0x${string}`>, import("./layouting.js").AbiParam<"to", "address", import("./layouting.js").AddressItem, `0x${string}`>, import("./layouting.js").AbiParam<"value", "uint256", import("@onrail-xyz/common").AmountItem<32, K>, import("@onrail-xyz/common").AmountOr<K, bigint>>]>, import("./layouting.js").SigVariantOf<"Approval", readonly [import("./layouting.js").AbiParam<"owner", "address", import("./layouting.js").AddressItem, `0x${string}`>, import("./layouting.js").AbiParam<"spender", "address", import("./layouting.js").AddressItem, `0x${string}`>, import("./layouting.js").AbiParam<"value", "uint256", import("@onrail-xyz/common").AmountItem<32, K>, import("@onrail-xyz/common").AmountOr<K, bigint>>]>];
104
+ declare const allowanceAdjustersSpec: <const K extends KindWithAtomic | undefined = undefined>(...kind: OptionalArg<K>) => readonly [import("./client.js").FuncSpec<"increaseAllowance", readonly [import("./layouting.js").AbiParam<"spender", "address", import("./layouting.js").AddressItem, `0x${string}`>, import("./layouting.js").AbiParam<"addedValue", "uint256", import("@onrail-xyz/common").AmountItem<32, K>, import("@onrail-xyz/common").AmountOr<K, bigint>>], (spender: `0x${string}`, addedValue: import("@onrail-xyz/common").AmountOr<K, bigint>) => {
105
+ spender: `0x${string}`;
106
+ addedValue: import("@onrail-xyz/common").AmountOr<K, bigint>;
107
+ }, undefined>, import("./client.js").FuncSpec<"decreaseAllowance", readonly [import("./layouting.js").AbiParam<"spender", "address", import("./layouting.js").AddressItem, `0x${string}`>, import("./layouting.js").AbiParam<"subtractedValue", "uint256", import("@onrail-xyz/common").AmountItem<32, K>, import("@onrail-xyz/common").AmountOr<K, bigint>>], (spender: `0x${string}`, subtractedValue: import("@onrail-xyz/common").AmountOr<K, bigint>) => {
108
+ spender: `0x${string}`;
109
+ subtractedValue: import("@onrail-xyz/common").AmountOr<K, bigint>;
110
+ }, undefined>];
111
+ export declare const allowanceAdjusters: <const K extends KindWithAtomic | undefined = undefined>(contract: Address, ...kind: OptionalArg<K>) => ContractMethods<ReturnType<typeof allowanceAdjustersSpec<K>>>;
112
+ export {};
113
+ //# sourceMappingURL=erc20.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"erc20.d.ts","sourceRoot":"","sources":["../src/erc20.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAgBnD,QAAA,MAAM,SAAS,GAAI,KAAK,CAAC,CAAC,SAAS,cAAc,GAAG,SAAS,GAAG,SAAS,WAC9D,WAAW,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAbwB,MAAM;2BAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;cA6B/D,CAAC;AAEF,eAAO,MAAM,KAAK,GAAI,KAAK,CAAC,CAAC,SAAS,cAAc,GAAG,SAAS,GAAG,SAAS,YAChE,OAAO,WACP,WAAW,CAAC,CAAC,CAAC,KACvB,eAAe,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CACF,CAAC;AAGjD,eAAO,MAAM,WAAW,GAAI,KAAK,CAAC,CAAC,SAAS,cAAc,GAAG,SAAS,GAAG,SAAS,WACvE,WAAW,CAAC,CAAC,CAAC,02BAOxB,CAAC;AAEF,QAAA,MAAM,sBAAsB,GAAI,KAAK,CAAC,CAAC,SAAS,cAAc,GAAG,SAAS,GAAG,SAAS,WAC3E,WAAW,CAAC,CAAC,CAAC;;;;;;cAUxB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,KAAK,CAAC,CAAC,SAAS,cAAc,GAAG,SAAS,GAAG,SAAS,YAC7E,OAAO,WACP,WAAW,CAAC,CAAC,CAAC,KACvB,eAAe,CAAC,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC,CAAC,CAAC,CACF,CAAC"}
package/dist/erc20.js ADDED
@@ -0,0 +1,44 @@
1
+ import { utf8Conversion, withCustom } from "@onrail-xyz/binary-layout";
2
+ import { paddedSlotLayout, evmAmountItem, abiEncodedBytesItem, sigVariant, addressParam, amountParam } from "./layouting.js";
3
+ import { abiFunction, contractFromSpec } from "./client.js";
4
+ const abiStringItem = withCustom(abiEncodedBytesItem(), utf8Conversion);
5
+ const decimalsItem = paddedSlotLayout({ binary: "uint", size: 1 });
6
+ const from = addressParam("from");
7
+ const to = addressParam("to");
8
+ const owner = addressParam("owner");
9
+ const spender = addressParam("spender");
10
+ const valueParam = (...kind) => amountParam("value", "uint256", ...kind);
11
+ const erc20Spec = (...kind) => {
12
+ const value = valueParam(...kind);
13
+ const amountItem = evmAmountItem(...kind);
14
+ const abiF = abiFunction;
15
+ return [
16
+ abiF("name", [], () => ({}), abiStringItem),
17
+ abiF("symbol", [], () => ({}), abiStringItem),
18
+ abiF("decimals", [], () => ({}), decimalsItem),
19
+ abiF("totalSupply", [], () => ({}), amountItem),
20
+ abiF("balanceOf", [owner], owner => ({ owner }), amountItem),
21
+ abiF("allowance", [owner, spender], (owner, spender) => ({ owner, spender }), amountItem),
22
+ abiF("approve", [spender, value], (spender, value) => ({ spender, value })),
23
+ abiF("transfer", [to, value], (to, value) => ({ to, value })),
24
+ abiF("transferFrom", [from, to, value], (from, to, value) => ({ from, to, value })),
25
+ ];
26
+ };
27
+ export const erc20 = (contract, ...kind) => contractFromSpec(contract, erc20Spec(...kind));
28
+ //`Transfer` and `Approval` as `buildParseEvent` variants; `allowanceAdjusters` emits the latter
29
+ export const erc20Events = (...kind) => {
30
+ const value = valueParam(...kind);
31
+ return [
32
+ sigVariant("Transfer", from, to, value),
33
+ sigVariant("Approval", owner, spender, value),
34
+ ];
35
+ };
36
+ const allowanceAdjustersSpec = (...kind) => {
37
+ const addedValue = amountParam("addedValue", "uint256", ...kind);
38
+ const subtractedValue = amountParam("subtractedValue", "uint256", ...kind);
39
+ return [
40
+ abiFunction("increaseAllowance", [spender, addedValue], (spender, addedValue) => ({ spender, addedValue })),
41
+ abiFunction("decreaseAllowance", [spender, subtractedValue], (spender, subtractedValue) => ({ spender, subtractedValue })),
42
+ ];
43
+ };
44
+ export const allowanceAdjusters = (contract, ...kind) => contractFromSpec(contract, allowanceAdjustersSpec(...kind));