Skip to content
This repository was archived by the owner on Aug 30, 2022. It is now read-only.

Commit f9b6fab

Browse files
Support tuple types for thirdweb deploy (#436)
* support tuples in constructor params * better function sig for tuples
1 parent 424df52 commit f9b6fab

File tree

6 files changed

+78
-21
lines changed

6 files changed

+78
-21
lines changed

etc/sdk.api.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,6 +1785,10 @@ export enum EventType {
17851785
export function extractConstructorParams(predeployMetadataUri: string, storage: IStorage): Promise<{
17861786
[x: string]: any;
17871787
stateMutability?: string | undefined;
1788+
components?: {
1789+
name: string;
1790+
type: string;
1791+
}[] | undefined;
17881792
name: string;
17891793
type: string;
17901794
}[]>;
@@ -1795,6 +1799,10 @@ export function extractConstructorParams(predeployMetadataUri: string, storage:
17951799
export function extractConstructorParamsFromAbi(abi: z.input<typeof AbiSchema>): {
17961800
[x: string]: any;
17971801
stateMutability?: string | undefined;
1802+
components?: {
1803+
name: string;
1804+
type: string;
1805+
}[] | undefined;
17981806
name: string;
17991807
type: string;
18001808
}[];

src/common/feature-detection.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { IStorage } from "../core";
44
import {
55
AbiFunction,
66
AbiSchema,
7+
AbiTypeSchema,
78
PreDeployMetadata,
89
PreDeployMetadataFetched,
910
PublishedMetadata,
@@ -90,11 +91,10 @@ export function extractFunctionsFromAbi(
9091
const parsed = [];
9192
for (const f of functions) {
9293
const args =
93-
f.inputs
94-
?.map((i) => `${i.name || "key"}: ${toJSType(i.type)}`)
95-
?.join(", ") || "";
94+
f.inputs?.map((i) => `${i.name || "key"}: ${toJSType(i)}`)?.join(", ") ||
95+
"";
9696
const fargs = args ? `, ${args}` : "";
97-
const out = f.outputs?.map((o) => toJSType(o.type, true))?.join(", ");
97+
const out = f.outputs?.map((o) => toJSType(o, true))?.join(", ");
9898
const promise = out ? `: Promise<${out}>` : `: Promise<TransactionResult>`;
9999
const signature = `contract.call("${f.name}"${fargs})${promise}`;
100100
parsed.push({
@@ -108,23 +108,42 @@ export function extractFunctionsFromAbi(
108108
return parsed;
109109
}
110110

111-
function toJSType(contractType: string, isReturnType = false): string {
112-
let jsType = contractType;
113-
if (contractType.startsWith("bytes")) {
111+
function toJSType(
112+
contractType: z.input<typeof AbiTypeSchema>,
113+
isReturnType = false,
114+
withName = false,
115+
): string {
116+
let jsType = contractType.type;
117+
let isArray = false;
118+
if (jsType.endsWith("[]")) {
119+
isArray = true;
120+
jsType = jsType.slice(0, -2);
121+
}
122+
if (jsType.startsWith("bytes")) {
114123
jsType = "BytesLike";
115124
}
116-
if (contractType.startsWith("uint") || contractType.startsWith("int")) {
125+
if (jsType.startsWith("uint") || jsType.startsWith("int")) {
117126
jsType = isReturnType ? "BigNumber" : "BigNumberish";
118127
}
119-
if (contractType === "bool") {
128+
if (jsType.startsWith("bool")) {
120129
jsType = "boolean";
121130
}
122-
if (contractType === "address") {
131+
if (jsType === "address") {
123132
jsType = "string";
124133
}
125-
if (contractType.endsWith("[]")) {
134+
if (jsType === "tuple") {
135+
if (contractType.components) {
136+
jsType = `{ ${contractType.components
137+
.map((a) => toJSType(a, false, true))
138+
.join(", ")} }`;
139+
}
140+
}
141+
if (isArray) {
126142
jsType += "[]";
127143
}
144+
if (withName) {
145+
jsType = `${contractType.name}: ${jsType}`;
146+
}
128147
return jsType;
129148
}
130149

src/contracts/smart-contract.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,6 @@ export class SmartContract<
203203
* ********************/
204204

205205
private detectRoyalties() {
206-
// TODO (byoc) change to ThirdwebContract
207206
if (
208207
detectContractFeature<IRoyalty & ThirdwebContract>(
209208
this.contractWrapper,

src/core/classes/contract-publisher.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ export class ContractPublisher extends RPCConnectionHandler {
276276
throw Error("Passed the wrong number of constructor arguments");
277277
}
278278
return constructorParamTypes.map((p, index) => {
279-
if (p.endsWith("[]")) {
279+
if (p === "tuple" || p.endsWith("[]")) {
280280
if (typeof constructorParamValues[index] === "string") {
281281
return JSON.parse(constructorParamValues[index]);
282282
} else {

src/schema/contracts/custom.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,18 @@ export type PreDeployMetadataFetched = {
6969
/**
7070
* @internal
7171
*/
72-
export const AbiTypeSchema = z
73-
.object({
74-
type: z.string(),
75-
name: z.string(),
76-
stateMutability: z.string().optional(),
77-
})
78-
.catchall(z.any());
72+
const AbiTypeBaseSchema = z.object({
73+
type: z.string(),
74+
name: z.string(),
75+
});
76+
77+
/**
78+
* @internal
79+
*/
80+
export const AbiTypeSchema = AbiTypeBaseSchema.extend({
81+
stateMutability: z.string().optional(),
82+
components: z.array(AbiTypeBaseSchema).optional(),
83+
}).catchall(z.any());
7984

8085
/**
8186
* @internal

test/publisher.test.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { IpfsStorage, isFeatureEnabled, ThirdwebSDK } from "../src";
55
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
66
import invariant from "tiny-invariant";
77
import { DropERC721__factory, TokenERC721__factory } from "../typechain";
8+
import { ethers } from "ethers";
89

910
global.fetch = require("cross-fetch");
1011

@@ -134,7 +135,6 @@ describe("Publishing", async () => {
134135
const all = await publisher.getAll(bobWallet.address);
135136
expect(all.length).to.be.eq(1);
136137
});
137-
138138
it("should publish batch contracts", async () => {
139139
const publisher = await sdk.getPublisher();
140140
const tx = await publisher.publishBatch([
@@ -188,4 +188,30 @@ describe("Publishing", async () => {
188188
const all = await c.nft.query.all();
189189
expect(all.length).to.eq(1);
190190
});
191+
192+
it("Constructor params with tuples", async () => {
193+
const realSDK = new ThirdwebSDK(adminWallet);
194+
const pub = await realSDK.getPublisher();
195+
const ipfsUri = "ipfs://QmZQa56Cj1gFnZgKSkvGE5uzhaQrQV3nU6upDWDusCaCwY/0";
196+
const addr = await pub.deployContract(ipfsUri, [
197+
"0x1234",
198+
"123",
199+
JSON.stringify(["0x1234", "0x4567"]),
200+
JSON.stringify([
201+
213,
202+
ethers.utils.hexZeroPad("0x1234", 32),
203+
[adminWallet.address, samWallet.address],
204+
]),
205+
]);
206+
const c = await sdk.getContract(addr);
207+
const uri = await c.call("contractUri");
208+
expect(uri).to.eq(ethers.utils.hexZeroPad("0x1234", 32));
209+
210+
const tx = await c.call("updateStruct", {
211+
aNumber: 123,
212+
aString: ethers.utils.hexZeroPad("0x1234", 32),
213+
anArray: [adminWallet.address, samWallet.address],
214+
});
215+
expect(tx).to.not.eq(undefined);
216+
});
191217
});

0 commit comments

Comments
 (0)