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

Commit e5d66f4

Browse files
Allow deploying any released contracts from SDK (#542)
1 parent 39dc804 commit e5d66f4

File tree

7 files changed

+166
-146
lines changed

7 files changed

+166
-146
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
2+
3+
[Home](./index.md) &gt; [@thirdweb-dev/sdk](./sdk.md) &gt; [ContractDeployer](./sdk.contractdeployer.md) &gt; [deployReleasedContract](./sdk.contractdeployer.deployreleasedcontract.md)
4+
5+
## ContractDeployer.deployReleasedContract() method
6+
7+
Deploy any released contract by its name
8+
9+
<b>Signature:</b>
10+
11+
```typescript
12+
deployReleasedContract(releaserAddress: string, contractName: string, constructorParams: any[]): Promise<string>;
13+
```
14+
15+
## Parameters
16+
17+
| Parameter | Type | Description |
18+
| --- | --- | --- |
19+
| releaserAddress | string | the address of the releaser |
20+
| contractName | string | the name of the contract to deploy |
21+
| constructorParams | any\[\] | the constructor params to pass to the contract |
22+
23+
<b>Returns:</b>
24+
25+
Promise&lt;string&gt;
26+

docs/sdk.contractdeployer.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export declare class ContractDeployer extends RPCConnectionHandler
3030
| [deployNFTCollection(metadata)](./sdk.contractdeployer.deploynftcollection.md) | | Deploys an NFT Collection contract |
3131
| [deployNFTDrop(metadata)](./sdk.contractdeployer.deploynftdrop.md) | | Deploys a new NFTDrop contract |
3232
| [deployPack(metadata)](./sdk.contractdeployer.deploypack.md) | | Deploys a new Pack contract |
33+
| [deployReleasedContract(releaserAddress, contractName, constructorParams)](./sdk.contractdeployer.deployreleasedcontract.md) | | Deploy any released contract by its name |
3334
| [deploySignatureDrop(metadata)](./sdk.contractdeployer.deploysignaturedrop.md) | | Deploys a new SignatureDrop contract |
3435
| [deploySplit(metadata)](./sdk.contractdeployer.deploysplit.md) | | Deploys a new Split contract |
3536
| [deployToken(metadata)](./sdk.contractdeployer.deploytoken.md) | | Deploys a new Token contract |

etc/sdk.api.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,12 @@ export class ContractDeployer extends RPCConnectionHandler {
11511151
constructor(network: NetworkOrSignerOrProvider, options: SDKOptions, storage: IStorage);
11521152
// @internal
11531153
deployBuiltInContract<TContract extends ValidContractClass>(contractType: TContract["contractType"], contractMetadata: z.input<TContract["schema"]["deploy"]>): Promise<string>;
1154+
// @internal (undocumented)
1155+
deployContractFromUri(publishMetadataUri: string, constructorParamValues: any[]): Promise<string>;
1156+
// @internal (undocumented)
1157+
deployContractWithAbi(abi: ContractInterface, bytecode: BytesLike | {
1158+
object: string;
1159+
}, constructorParams: Array<any>): Promise<string>;
11541160
deployEdition(metadata: NFTContractDeployMetadata): Promise<string>;
11551161
deployEditionDrop(metadata: NFTContractDeployMetadata): Promise<string>;
11561162
deployMarketplace(metadata: MarketplaceContractDeployMetadata): Promise<string>;
@@ -1159,6 +1165,7 @@ export class ContractDeployer extends RPCConnectionHandler {
11591165
deployNFTCollection(metadata: NFTContractDeployMetadata): Promise<string>;
11601166
deployNFTDrop(metadata: NFTContractDeployMetadata): Promise<string>;
11611167
deployPack(metadata: NFTContractDeployMetadata): Promise<string>;
1168+
deployReleasedContract(releaserAddress: string, contractName: string, constructorParams: any[]): Promise<string>;
11621169
deploySignatureDrop(metadata: NFTContractDeployMetadata): Promise<string>;
11631170
deploySplit(metadata: SplitContractDeployMetadata): Promise<string>;
11641171
deployToken(metadata: TokenContractDeployMetadata): Promise<string>;

src/core/classes/contract-deployer.ts

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import {
1212
Marketplace,
1313
NFTCollection,
1414
NFTDrop,
15-
SignatureDrop,
1615
Pack,
16+
SignatureDrop,
1717
Split,
1818
Token,
1919
Vote,
@@ -28,6 +28,13 @@ import {
2828
} from "../../types/deploy/deploy-metadata";
2929
import { TokenDrop } from "../../contracts/token-drop";
3030
import { Multiwrap } from "../../contracts/multiwrap";
31+
import { ThirdwebSDK } from "../sdk";
32+
import invariant from "tiny-invariant";
33+
import {
34+
extractConstructorParamsFromAbi,
35+
fetchPreDeployMetadata,
36+
} from "../../common/index";
37+
import { BigNumber, BytesLike, ContractInterface, ethers } from "ethers";
3138

3239
/**
3340
* Handles deploying new contracts
@@ -341,6 +348,26 @@ export class ContractDeployer extends RPCConnectionHandler {
341348
return await factory.deploy(contractType, contractMetadata);
342349
}
343350

351+
/**
352+
* Deploy any released contract by its name
353+
* @param releaserAddress the address of the releaser
354+
* @param contractName the name of the contract to deploy
355+
* @param constructorParams the constructor params to pass to the contract
356+
*/
357+
public async deployReleasedContract(
358+
releaserAddress: string,
359+
contractName: string,
360+
constructorParams: any[],
361+
): Promise<string> {
362+
const release = await new ThirdwebSDK("polygon")
363+
.getPublisher()
364+
.getLatest(releaserAddress, contractName);
365+
return await this.deployContractFromUri(
366+
release.metadataUri,
367+
constructorParams,
368+
);
369+
}
370+
344371
/**
345372
* @internal
346373
*/
@@ -410,4 +437,93 @@ export class ContractDeployer extends RPCConnectionHandler {
410437
registry.updateSignerOrProvider(this.getSignerOrProvider());
411438
});
412439
}
440+
441+
/**
442+
* @internal
443+
* @param publishMetadataUri
444+
* @param constructorParamValues
445+
*/
446+
public async deployContractFromUri(
447+
publishMetadataUri: string,
448+
constructorParamValues: any[],
449+
) {
450+
const signer = this.getSigner();
451+
invariant(signer, "A signer is required");
452+
const metadata = await fetchPreDeployMetadata(
453+
publishMetadataUri,
454+
this.storage,
455+
);
456+
const bytecode = metadata.bytecode.startsWith("0x")
457+
? metadata.bytecode
458+
: `0x${metadata.bytecode}`;
459+
if (!ethers.utils.isHexString(bytecode)) {
460+
throw new Error(`Contract bytecode is invalid.\n\n${bytecode}`);
461+
}
462+
const constructorParamTypes = extractConstructorParamsFromAbi(
463+
metadata.abi,
464+
).map((p) => p.type);
465+
const paramValues = this.convertParamValues(
466+
constructorParamTypes,
467+
constructorParamValues,
468+
);
469+
return this.deployContractWithAbi(metadata.abi, bytecode, paramValues);
470+
}
471+
472+
private convertParamValues(
473+
constructorParamTypes: string[],
474+
constructorParamValues: any[],
475+
) {
476+
// check that both arrays are same length
477+
if (constructorParamTypes.length !== constructorParamValues.length) {
478+
throw Error("Passed the wrong number of constructor arguments");
479+
}
480+
return constructorParamTypes.map((p, index) => {
481+
if (p === "tuple" || p.endsWith("[]")) {
482+
if (typeof constructorParamValues[index] === "string") {
483+
return JSON.parse(constructorParamValues[index]);
484+
} else {
485+
return constructorParamValues[index];
486+
}
487+
}
488+
if (p === "bytes32") {
489+
invariant(
490+
ethers.utils.isHexString(constructorParamValues[index]),
491+
`Could not parse bytes32 value. Expected valid hex string but got "${constructorParamValues[index]}".`,
492+
);
493+
return ethers.utils.hexZeroPad(constructorParamValues[index], 32);
494+
}
495+
if (p.startsWith("bytes")) {
496+
invariant(
497+
ethers.utils.isHexString(constructorParamValues[index]),
498+
`Could not parse bytes value. Expected valid hex string but got "${constructorParamValues[index]}".`,
499+
);
500+
return ethers.utils.toUtf8Bytes(constructorParamValues[index]);
501+
}
502+
if (p.startsWith("uint") || p.startsWith("int")) {
503+
return BigNumber.from(constructorParamValues[index].toString());
504+
}
505+
return constructorParamValues[index];
506+
});
507+
}
508+
509+
/**
510+
* @internal
511+
* @param abi
512+
* @param bytecode
513+
* @param constructorParams
514+
*/
515+
public async deployContractWithAbi(
516+
abi: ContractInterface,
517+
bytecode: BytesLike | { object: string },
518+
constructorParams: Array<any>,
519+
): Promise<string> {
520+
const signer = this.getSigner();
521+
invariant(signer, "Signer is required to deploy contracts");
522+
const deployer = await new ethers.ContractFactory(abi, bytecode)
523+
.connect(signer)
524+
.deploy(...constructorParams);
525+
const deployedContract = await deployer.deployed();
526+
// TODO parse transaction receipt
527+
return deployedContract.address;
528+
}
413529
}

src/core/classes/contract-publisher.ts

Lines changed: 1 addition & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,10 @@ import { NetworkOrSignerOrProvider, TransactionResult } from "../types";
22
import { SDKOptions } from "../../schema/sdk-options";
33
import { IStorage } from "../interfaces";
44
import { RPCConnectionHandler } from "./rpc-connection-handler";
5-
import {
6-
BigNumber,
7-
BytesLike,
8-
constants,
9-
ContractInterface,
10-
ethers,
11-
utils,
12-
} from "ethers";
5+
import { constants, utils } from "ethers";
136
import invariant from "tiny-invariant";
147
import {
158
extractConstructorParams,
16-
extractConstructorParamsFromAbi,
179
extractFunctions,
1810
fetchContractMetadataFromAddress,
1911
fetchPreDeployMetadata,
@@ -376,119 +368,6 @@ export class ContractPublisher extends RPCConnectionHandler {
376368
};
377369
}
378370

379-
/**
380-
* @internal
381-
* @param publisherAddress
382-
* @param contractId
383-
* @param constructorParamValues
384-
* @param contractMetadata
385-
*/
386-
public async deployPublishedContract(
387-
publisherAddress: string,
388-
contractId: string,
389-
constructorParamValues: any[],
390-
): Promise<string> {
391-
// TODO this gets the latest version, should we allow deploying a certain version?
392-
const contract = await this.publisher.readContract.getPublishedContract(
393-
publisherAddress,
394-
contractId,
395-
);
396-
return this.deployContract(
397-
contract.publishMetadataUri,
398-
constructorParamValues,
399-
);
400-
}
401-
402-
/**
403-
* @internal
404-
* @param publishMetadataUri
405-
* @param constructorParamValues
406-
*/
407-
public async deployContract(
408-
publishMetadataUri: string,
409-
constructorParamValues: any[],
410-
) {
411-
const signer = this.getSigner();
412-
invariant(signer, "A signer is required");
413-
const metadata = await fetchPreDeployMetadata(
414-
publishMetadataUri,
415-
this.storage,
416-
);
417-
const bytecode = metadata.bytecode.startsWith("0x")
418-
? metadata.bytecode
419-
: `0x${metadata.bytecode}`;
420-
if (!ethers.utils.isHexString(bytecode)) {
421-
throw new Error(`Contract bytecode is invalid.\n\n${bytecode}`);
422-
}
423-
const constructorParamTypes = extractConstructorParamsFromAbi(
424-
metadata.abi,
425-
).map((p) => p.type);
426-
const paramValues = this.convertParamValues(
427-
constructorParamTypes,
428-
constructorParamValues,
429-
);
430-
431-
return this.deployContractWithAbi(metadata.abi, bytecode, paramValues);
432-
}
433-
434-
private convertParamValues(
435-
constructorParamTypes: string[],
436-
constructorParamValues: any[],
437-
) {
438-
// check that both arrays are same length
439-
if (constructorParamTypes.length !== constructorParamValues.length) {
440-
throw Error("Passed the wrong number of constructor arguments");
441-
}
442-
return constructorParamTypes.map((p, index) => {
443-
if (p === "tuple" || p.endsWith("[]")) {
444-
if (typeof constructorParamValues[index] === "string") {
445-
return JSON.parse(constructorParamValues[index]);
446-
} else {
447-
return constructorParamValues[index];
448-
}
449-
}
450-
if (p === "bytes32") {
451-
invariant(
452-
ethers.utils.isHexString(constructorParamValues[index]),
453-
`Could not parse bytes32 value. Expected valid hex string but got "${constructorParamValues[index]}".`,
454-
);
455-
return ethers.utils.hexZeroPad(constructorParamValues[index], 32);
456-
}
457-
if (p.startsWith("bytes")) {
458-
invariant(
459-
ethers.utils.isHexString(constructorParamValues[index]),
460-
`Could not parse bytes value. Expected valid hex string but got "${constructorParamValues[index]}".`,
461-
);
462-
return ethers.utils.toUtf8Bytes(constructorParamValues[index]);
463-
}
464-
if (p.startsWith("uint") || p.startsWith("int")) {
465-
return BigNumber.from(constructorParamValues[index].toString());
466-
}
467-
return constructorParamValues[index];
468-
});
469-
}
470-
471-
/**
472-
* @internal
473-
* @param abi
474-
* @param bytecode
475-
* @param constructorParams
476-
*/
477-
public async deployContractWithAbi(
478-
abi: ContractInterface,
479-
bytecode: BytesLike | { object: string },
480-
constructorParams: Array<any>,
481-
): Promise<string> {
482-
const signer = this.getSigner();
483-
invariant(signer, "Signer is required to deploy contracts");
484-
const deployer = await new ethers.ContractFactory(abi, bytecode)
485-
.connect(signer)
486-
.deploy(...constructorParams);
487-
const deployedContract = await deployer.deployed();
488-
// TODO parse transaction receipt
489-
return deployedContract.address;
490-
}
491-
492371
private toPublishedContract(
493372
contractModel: IContractPublisher.CustomContractInstanceStruct,
494373
): PublishedContract {

test/custom.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ describe("Custom Contracts", async () => {
4242

4343
beforeEach(async () => {
4444
sdk.updateSignerOrProvider(adminWallet);
45-
const publisher = sdk.getPublisher();
46-
customContractAddress = await publisher.deployContract(
45+
customContractAddress = await sdk.deployer.deployContractFromUri(
4746
simpleContractUri,
4847
[],
4948
);

0 commit comments

Comments
 (0)