Skip to content

Commit

Permalink
lots of updates
Browse files Browse the repository at this point in the history
  • Loading branch information
jnsdls committed Jan 28, 2024
1 parent d412a10 commit 196163f
Show file tree
Hide file tree
Showing 29 changed files with 844 additions and 449 deletions.
8 changes: 8 additions & 0 deletions packages/thirdweb/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
"import": "./esm/event/index.js",
"default": "./cjs/event/index.js"
},
"./rpc": {
"types": "./types/rpc/index.d.ts",
"import": "./esm/rpc/index.js",
"default": "./cjs/rpc/index.js"
},
"./react": {
"types": "./types/react/index.d.ts",
"import": "./esm/react/index.js",
Expand Down Expand Up @@ -72,6 +77,9 @@
"event": [
"./types/event/index.d.ts"
],
"rpc": [
"./types/rpc/index.d.ts"
],
"storage": [
"./types/storage/index.d.ts"
],
Expand Down
4 changes: 2 additions & 2 deletions packages/thirdweb/src/adapters/ethers5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ async function toEthersContract<abi extends Abi = []>(
return new ethers.Contract(
twContract.address,
JSON.stringify(twContract.abi),
toEthersProvider(ethers, twContract, twContract.chainId),
toEthersProvider(ethers, twContract.client, twContract.chainId),
);
}

Expand All @@ -81,7 +81,7 @@ async function toEthersContract<abi extends Abi = []>(
return new ethers.Contract(
twContract.address,
JSON.stringify(abi),
toEthersProvider(ethers, twContract, twContract.chainId),
toEthersProvider(ethers, twContract.client, twContract.chainId),
);
}

Expand Down
4 changes: 2 additions & 2 deletions packages/thirdweb/src/adapters/ethers6.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ async function toEthersContract<abi extends Abi = []>(
return new ethers.Contract(
twContract.address,
JSON.stringify(twContract.abi),
toEthersProvider(ethers, twContract, twContract.chainId),
toEthersProvider(ethers, twContract.client, twContract.chainId),
);
}

Expand All @@ -82,7 +82,7 @@ async function toEthersContract<abi extends Abi = []>(
return new ethers.Contract(
twContract.address,
JSON.stringify(abi),
toEthersProvider(ethers, twContract, twContract.chainId),
toEthersProvider(ethers, twContract.client, twContract.chainId),
);
}

Expand Down
6 changes: 3 additions & 3 deletions packages/thirdweb/src/contract/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ export type ContractOptions<abi extends Abi = []> = {
readonly abi?: abi;
};

export type ThirdwebContract<abi extends Abi = []> = ThirdwebClient & {
export type ThirdwebContract<abi extends Abi = []> = {
readonly client: ThirdwebClient;
readonly address: string;
readonly chainId: number;
readonly abi?: abi;
Expand All @@ -23,8 +24,7 @@ export type ThirdwebContract<abi extends Abi = []> = ThirdwebClient & {
export function contract<const abi extends Abi = []>(
options: ContractOptions<abi>,
): ThirdwebContract<abi> {
const { client, ...rest } = options;
return { ...client, ...rest } as const;
return options;
}

export { resolveContractAbi } from "./actions/resolve-abi.js";
133 changes: 23 additions & 110 deletions packages/thirdweb/src/event/actions/watch.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,13 @@
import {
formatAbiItem,
type Abi,
type AbiEvent,
type ExtractAbiEventNames,
type AbiParameter,
type AbiParameterToPrimitiveType,
parseAbiItem,
} from "abitype";
import { type ContractEventInput } from "../event.js";
import {
hexToBigInt,
toHex,
type Log,
toEventSelector,
type Hex,
toBytes,
keccak256,
FilterTypeNotSupportedError,
encodeAbiParameters,
} from "viem";
import { type GetLogsReturnType } from "viem";
import { eth_blockNumber, eth_getLogs, getRpcClient } from "../../rpc/index.js";
import type { ParseEvent } from "../../abi/types.js";
import { getRpcClient } from "../../rpc/index.js";

type WatchOptions<
abi extends Abi,
Expand All @@ -30,15 +17,12 @@ type WatchOptions<
: ExtractAbiEventNames<abi>,
> = {
onLogs: (
logs: Array<
Log<
bigint,
number,
boolean,
ParseEvent<abi, event>,
undefined,
abi extends { length: 0 } ? [ParseEvent<abi, event>] : abi
>
logs: GetLogsReturnType<
ParseEvent<abi, event>,
[ParseEvent<abi, event>],
undefined,
bigint,
bigint
>,
) => void | undefined;
} & ContractEventInput<abi, event>;
Expand All @@ -50,53 +34,38 @@ export function watch<
? AbiEvent | string
: ExtractAbiEventNames<abi>,
>(options: WatchOptions<abi, event>) {
const rpcRequest = getRpcClient(options.contract, {
const rpcRequest = getRpcClient(options.contract.client, {
chainId: options.contract.chainId,
});

let lastBlock = 0n;
const parsedEvent =
const parsedEvent: ParseEvent<abi, event> =
typeof options.event === "string"
? parseAbiItem(options.event as any)
: options.event;
? (parseAbiItem(options.event as string) as ParseEvent<abi, event>)
: (options.event as ParseEvent<abi, event>);
if (parsedEvent.type !== "event") {
throw new Error("Expected event");
}
rpcRequest({
method: "eth_blockNumber",
params: [],
}).then((x) => {
lastBlock = hexToBigInt(x);
eth_blockNumber(rpcRequest).then((x) => {
lastBlock = x;
});

const interval = setInterval(async function () {
const blockHex = await rpcRequest({
method: "eth_blockNumber",
params: [],
});
const newBlock = hexToBigInt(blockHex);
const newBlock = await eth_blockNumber(rpcRequest);

if (lastBlock === 0n) {
lastBlock = newBlock;
} else if (newBlock > lastBlock) {
const logs = await rpcRequest({
method: "eth_getLogs",
params: [
{
address: options.contract.address,
topics: [
encodeEventTopic({
event: parsedEvent,
params: (options.params || []) as unknown[],
}),
],
fromBlock: toHex(lastBlock + 1n),
toBlock: toHex(newBlock),
},
],
const logs = await eth_getLogs(rpcRequest, {
fromBlock: lastBlock,
toBlock: newBlock,
address: options.contract.address,
event: parsedEvent,
// @ts-expect-error - missing | undefined in type
args: options.params,
});
if (logs.length) {
// TODO parsing etc
// @ts-expect-error - this works fine
options.onLogs(logs);
}

Expand All @@ -109,59 +78,3 @@ export function watch<
clearInterval(interval);
};
}

// TODO clean all of this up

function encodeEventTopic({
event,
params,
}: {
event: AbiEvent;
params: unknown[];
}) {
const definition = formatAbiItem(event);
const signature = toEventSelector(definition);

let topics: Hex[] = [];
if (params && "inputs" in event) {
const indexedInputs = event.inputs?.filter(
(param) => "indexed" in param && param.indexed,
);
const args_ = Array.isArray(params)
? params
: // TODO: bring this back
// : Object.values(args).length > 0
// ? indexedInputs?.map((x: any) => (args as any)[x.name]) ?? []
[];

if (args_.length > 0) {
topics =
indexedInputs?.map((param, i) =>
Array.isArray(args_[i])
? (args_[i] as any).map((_: any, j: number) =>
encodeArg({ param, value: (args_[i] as any)[j] }),
)
: args_[i]
? encodeArg({ param, value: args_[i] })
: null,
) ?? [];
}
}
return [signature, ...topics];
}

function encodeArg({
param,
value,
}: {
param: AbiParameter;
value: AbiParameterToPrimitiveType<AbiParameter>;
}) {
if (param.type === "string" || param.type === "bytes") {
return keccak256(toBytes(value as string));
}
if (param.type === "tuple" || param.type.match(/^(.*)\[(\d+)?\]$/)) {
throw new FilterTypeNotSupportedError(param.type);
}
return encodeAbiParameters([param], [value]);
}
4 changes: 2 additions & 2 deletions packages/thirdweb/src/event/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
import type { ThirdwebContract } from "../contract/index.js";
import type { ParseEvent } from "../abi/types.js";

type Params<event extends AbiEvent> = AbiParametersToPrimitiveTypes<
export type EventParams<event extends AbiEvent> = AbiParametersToPrimitiveTypes<
event["inputs"]
>;

Expand All @@ -17,7 +17,7 @@ export type ContractEventInput<
> = {
contract: ThirdwebContract<abi>;
event: event;
params?: Params<ParseEvent<abi, event>>;
params?: EventParams<ParseEvent<abi, event>>;
};

// the only difference here is that we don't alow string events
Expand Down
2 changes: 1 addition & 1 deletion packages/thirdweb/src/extensions/erc721/read/getNFT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const getNFT = /*@__PURE__*/ createReadExtension("erc721.getNFT")(
]);
return parseNFT(
await fetchTokenMetadata({
client: options.contract,
client: options.contract.client,
tokenId: options.tokenId,
tokenUri: uri,
}),
Expand Down
2 changes: 1 addition & 1 deletion packages/thirdweb/src/extensions/erc721/write/mintTo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function mintTo(options: TxOpts<MintToParams>) {
// load the upload code if we need it
const { upload } = await import("../../../storage/upload.js");
tokenUri = (
await upload(options.contract, {
await upload(options.contract.client, {
files: [options.nft],
})
)[0] as string;
Expand Down
25 changes: 12 additions & 13 deletions packages/thirdweb/src/gas/fee-data.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { ThirdwebClient } from "../client/client.js";
import { parseUnits } from "viem";
import {
blockByNumber,
gasPrice,
maxPriorityFeePerGas,
} from "../rpc/methods.js";
eth_gasPrice,
eth_getBlockByNumber,
eth_maxPriorityFeePerGas,
getRpcClient,
} from "../rpc/index.js";

type FeeData = {
maxFeePerGas: null | bigint;
Expand Down Expand Up @@ -44,12 +45,11 @@ export async function getDynamicFeeData(
let maxFeePerGas: null | bigint = null;
let maxPriorityFeePerGas_: null | bigint = null;

const { getRpcClient } = await import("../rpc/index.js");
const rpcClient = getRpcClient(client, { chainId });
const rpcRequest = getRpcClient(client, { chainId });

const [block, eth_maxPriorityFeePerGas] = await Promise.all([
blockByNumber(rpcClient, "latest", false),
maxPriorityFeePerGas(rpcClient).catch(() => null),
const [block, maxPriorityFeePerGas] = await Promise.all([
eth_getBlockByNumber(rpcRequest, { blockTag: "latest" }),
eth_maxPriorityFeePerGas(rpcRequest).catch(() => null),
]);

const baseBlockFee =
Expand All @@ -59,9 +59,9 @@ export async function getDynamicFeeData(
if (chainId === 80001 || chainId === 137) {
// for polygon, get fee data from gas station
maxPriorityFeePerGas_ = await getPolygonGasPriorityFee(chainId);
} else if (eth_maxPriorityFeePerGas) {
} else if (maxPriorityFeePerGas) {
// prioritize fee from eth_maxPriorityFeePerGas
maxPriorityFeePerGas_ = eth_maxPriorityFeePerGas;
maxPriorityFeePerGas_ = maxPriorityFeePerGas;
}
// TODO bring back(?)
// else {
Expand Down Expand Up @@ -103,9 +103,8 @@ export async function getGasPrice(
client: ThirdwebClient,
chainId: number,
): Promise<bigint> {
const { getRpcClient } = await import("../rpc/index.js");
const rpcClient = getRpcClient(client, { chainId });
const gasPrice_ = await gasPrice(rpcClient);
const gasPrice_ = await eth_gasPrice(rpcClient);
const maxGasPrice = 300n; // 300 gwei
const extraTip = (gasPrice_ / BigInt(100)) * BigInt(10);
const txGasPrice = gasPrice_ + extraTip;
Expand Down
10 changes: 10 additions & 0 deletions packages/thirdweb/src/rpc/actions/eth_blockNumber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { type EIP1193RequestFn, type EIP1474Methods, hexToBigInt } from "viem";

export async function eth_blockNumber(
request: EIP1193RequestFn<EIP1474Methods>,
): Promise<bigint> {
const blockNumberHex = await request({
method: "eth_blockNumber",
});
return hexToBigInt(blockNumberHex);
}
28 changes: 28 additions & 0 deletions packages/thirdweb/src/rpc/actions/eth_call.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
type BlockTag,
numberToHex,
type EIP1193RequestFn,
type EIP1474Methods,
type RpcTransactionRequest,
type Hex,
} from "viem";

export async function eth_call(
request: EIP1193RequestFn<EIP1474Methods>,
params: Partial<RpcTransactionRequest> & {
blockNumber?: bigint | number;
blockTag?: BlockTag;
},
): Promise<Hex> {
const { blockNumber, blockTag, ...txRequest } = params;
const blockNumberHex = blockNumber ? numberToHex(blockNumber) : undefined;
// TODO: per RPC spec omitting the block is allowed, however for some reason our RPCs don't like it, so we default to "latest" here
const block = blockNumberHex || blockTag || "latest";

return await request({
method: "eth_call",
params: block
? [txRequest as Partial<RpcTransactionRequest>, block]
: [txRequest as Partial<RpcTransactionRequest>],
});
}
Loading

0 comments on commit 196163f

Please sign in to comment.