Skip to content
This repository was archived by the owner on Aug 30, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/sdk.contractdeployer.deployreleasedcontract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@thirdweb-dev/sdk](./sdk.md) &gt; [ContractDeployer](./sdk.contractdeployer.md) &gt; [deployReleasedContract](./sdk.contractdeployer.deployreleasedcontract.md)

## ContractDeployer.deployReleasedContract() method

Deploy any released contract by its name

<b>Signature:</b>

```typescript
deployReleasedContract(releaserAddress: string, contractName: string, constructorParams: any[]): Promise<string>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| releaserAddress | string | the address of the releaser |
| contractName | string | the name of the contract to deploy |
| constructorParams | any\[\] | the constructor params to pass to the contract |

<b>Returns:</b>

Promise&lt;string&gt;

1 change: 1 addition & 0 deletions docs/sdk.contractdeployer.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export declare class ContractDeployer extends RPCConnectionHandler
| [deployNFTCollection(metadata)](./sdk.contractdeployer.deploynftcollection.md) | | Deploys an NFT Collection contract |
| [deployNFTDrop(metadata)](./sdk.contractdeployer.deploynftdrop.md) | | Deploys a new NFTDrop contract |
| [deployPack(metadata)](./sdk.contractdeployer.deploypack.md) | | Deploys a new Pack contract |
| [deployReleasedContract(releaserAddress, contractName, constructorParams)](./sdk.contractdeployer.deployreleasedcontract.md) | | Deploy any released contract by its name |
| [deploySignatureDrop(metadata)](./sdk.contractdeployer.deploysignaturedrop.md) | | Deploys a new SignatureDrop contract |
| [deploySplit(metadata)](./sdk.contractdeployer.deploysplit.md) | | Deploys a new Split contract |
| [deployToken(metadata)](./sdk.contractdeployer.deploytoken.md) | | Deploys a new Token contract |
Expand Down
7 changes: 7 additions & 0 deletions etc/sdk.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1151,6 +1151,12 @@ export class ContractDeployer extends RPCConnectionHandler {
constructor(network: NetworkOrSignerOrProvider, options: SDKOptions, storage: IStorage);
// @internal
deployBuiltInContract<TContract extends ValidContractClass>(contractType: TContract["contractType"], contractMetadata: z.input<TContract["schema"]["deploy"]>): Promise<string>;
// @internal (undocumented)
deployContractFromUri(publishMetadataUri: string, constructorParamValues: any[]): Promise<string>;
// @internal (undocumented)
deployContractWithAbi(abi: ContractInterface, bytecode: BytesLike | {
object: string;
}, constructorParams: Array<any>): Promise<string>;
deployEdition(metadata: NFTContractDeployMetadata): Promise<string>;
deployEditionDrop(metadata: NFTContractDeployMetadata): Promise<string>;
deployMarketplace(metadata: MarketplaceContractDeployMetadata): Promise<string>;
Expand All @@ -1159,6 +1165,7 @@ export class ContractDeployer extends RPCConnectionHandler {
deployNFTCollection(metadata: NFTContractDeployMetadata): Promise<string>;
deployNFTDrop(metadata: NFTContractDeployMetadata): Promise<string>;
deployPack(metadata: NFTContractDeployMetadata): Promise<string>;
deployReleasedContract(releaserAddress: string, contractName: string, constructorParams: any[]): Promise<string>;
deploySignatureDrop(metadata: NFTContractDeployMetadata): Promise<string>;
deploySplit(metadata: SplitContractDeployMetadata): Promise<string>;
deployToken(metadata: TokenContractDeployMetadata): Promise<string>;
Expand Down
118 changes: 117 additions & 1 deletion src/core/classes/contract-deployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import {
Marketplace,
NFTCollection,
NFTDrop,
SignatureDrop,
Pack,
SignatureDrop,
Split,
Token,
Vote,
Expand All @@ -28,6 +28,13 @@ import {
} from "../../types/deploy/deploy-metadata";
import { TokenDrop } from "../../contracts/token-drop";
import { Multiwrap } from "../../contracts/multiwrap";
import { ThirdwebSDK } from "../sdk";
import invariant from "tiny-invariant";
import {
extractConstructorParamsFromAbi,
fetchPreDeployMetadata,
} from "../../common/index";
import { BigNumber, BytesLike, ContractInterface, ethers } from "ethers";

/**
* Handles deploying new contracts
Expand Down Expand Up @@ -341,6 +348,26 @@ export class ContractDeployer extends RPCConnectionHandler {
return await factory.deploy(contractType, contractMetadata);
}

/**
* Deploy any released contract by its name
* @param releaserAddress the address of the releaser
* @param contractName the name of the contract to deploy
* @param constructorParams the constructor params to pass to the contract
*/
public async deployReleasedContract(
releaserAddress: string,
contractName: string,
constructorParams: any[],
): Promise<string> {
const release = await new ThirdwebSDK("polygon")
.getPublisher()
.getLatest(releaserAddress, contractName);
return await this.deployContractFromUri(
release.metadataUri,
constructorParams,
);
}

/**
* @internal
*/
Expand Down Expand Up @@ -410,4 +437,93 @@ export class ContractDeployer extends RPCConnectionHandler {
registry.updateSignerOrProvider(this.getSignerOrProvider());
});
}

/**
* @internal
* @param publishMetadataUri
* @param constructorParamValues
*/
public async deployContractFromUri(
publishMetadataUri: string,
constructorParamValues: any[],
) {
const signer = this.getSigner();
invariant(signer, "A signer is required");
const metadata = await fetchPreDeployMetadata(
publishMetadataUri,
this.storage,
);
const bytecode = metadata.bytecode.startsWith("0x")
? metadata.bytecode
: `0x${metadata.bytecode}`;
if (!ethers.utils.isHexString(bytecode)) {
throw new Error(`Contract bytecode is invalid.\n\n${bytecode}`);
}
const constructorParamTypes = extractConstructorParamsFromAbi(
metadata.abi,
).map((p) => p.type);
const paramValues = this.convertParamValues(
constructorParamTypes,
constructorParamValues,
);
return this.deployContractWithAbi(metadata.abi, bytecode, paramValues);
}

private convertParamValues(
constructorParamTypes: string[],
constructorParamValues: any[],
) {
// check that both arrays are same length
if (constructorParamTypes.length !== constructorParamValues.length) {
throw Error("Passed the wrong number of constructor arguments");
}
return constructorParamTypes.map((p, index) => {
if (p === "tuple" || p.endsWith("[]")) {
if (typeof constructorParamValues[index] === "string") {
return JSON.parse(constructorParamValues[index]);
} else {
return constructorParamValues[index];
}
}
if (p === "bytes32") {
invariant(
ethers.utils.isHexString(constructorParamValues[index]),
`Could not parse bytes32 value. Expected valid hex string but got "${constructorParamValues[index]}".`,
);
return ethers.utils.hexZeroPad(constructorParamValues[index], 32);
}
if (p.startsWith("bytes")) {
invariant(
ethers.utils.isHexString(constructorParamValues[index]),
`Could not parse bytes value. Expected valid hex string but got "${constructorParamValues[index]}".`,
);
return ethers.utils.toUtf8Bytes(constructorParamValues[index]);
}
if (p.startsWith("uint") || p.startsWith("int")) {
return BigNumber.from(constructorParamValues[index].toString());
}
return constructorParamValues[index];
});
}

/**
* @internal
* @param abi
* @param bytecode
* @param constructorParams
*/
public async deployContractWithAbi(
abi: ContractInterface,
bytecode: BytesLike | { object: string },
constructorParams: Array<any>,
): Promise<string> {
const signer = this.getSigner();
invariant(signer, "Signer is required to deploy contracts");
const deployer = await new ethers.ContractFactory(abi, bytecode)
.connect(signer)
.deploy(...constructorParams);
const deployedContract = await deployer.deployed();
// TODO parse transaction receipt
return deployedContract.address;
}
}
123 changes: 1 addition & 122 deletions src/core/classes/contract-publisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,10 @@ import { NetworkOrSignerOrProvider, TransactionResult } from "../types";
import { SDKOptions } from "../../schema/sdk-options";
import { IStorage } from "../interfaces";
import { RPCConnectionHandler } from "./rpc-connection-handler";
import {
BigNumber,
BytesLike,
constants,
ContractInterface,
ethers,
utils,
} from "ethers";
import { constants, utils } from "ethers";
import invariant from "tiny-invariant";
import {
extractConstructorParams,
extractConstructorParamsFromAbi,
extractFunctions,
fetchContractMetadataFromAddress,
fetchPreDeployMetadata,
Expand Down Expand Up @@ -376,119 +368,6 @@ export class ContractPublisher extends RPCConnectionHandler {
};
}

/**
* @internal
* @param publisherAddress
* @param contractId
* @param constructorParamValues
* @param contractMetadata
*/
public async deployPublishedContract(
publisherAddress: string,
contractId: string,
constructorParamValues: any[],
): Promise<string> {
// TODO this gets the latest version, should we allow deploying a certain version?
const contract = await this.publisher.readContract.getPublishedContract(
publisherAddress,
contractId,
);
return this.deployContract(
contract.publishMetadataUri,
constructorParamValues,
);
}

/**
* @internal
* @param publishMetadataUri
* @param constructorParamValues
*/
public async deployContract(
publishMetadataUri: string,
constructorParamValues: any[],
) {
const signer = this.getSigner();
invariant(signer, "A signer is required");
const metadata = await fetchPreDeployMetadata(
publishMetadataUri,
this.storage,
);
const bytecode = metadata.bytecode.startsWith("0x")
? metadata.bytecode
: `0x${metadata.bytecode}`;
if (!ethers.utils.isHexString(bytecode)) {
throw new Error(`Contract bytecode is invalid.\n\n${bytecode}`);
}
const constructorParamTypes = extractConstructorParamsFromAbi(
metadata.abi,
).map((p) => p.type);
const paramValues = this.convertParamValues(
constructorParamTypes,
constructorParamValues,
);

return this.deployContractWithAbi(metadata.abi, bytecode, paramValues);
}

private convertParamValues(
constructorParamTypes: string[],
constructorParamValues: any[],
) {
// check that both arrays are same length
if (constructorParamTypes.length !== constructorParamValues.length) {
throw Error("Passed the wrong number of constructor arguments");
}
return constructorParamTypes.map((p, index) => {
if (p === "tuple" || p.endsWith("[]")) {
if (typeof constructorParamValues[index] === "string") {
return JSON.parse(constructorParamValues[index]);
} else {
return constructorParamValues[index];
}
}
if (p === "bytes32") {
invariant(
ethers.utils.isHexString(constructorParamValues[index]),
`Could not parse bytes32 value. Expected valid hex string but got "${constructorParamValues[index]}".`,
);
return ethers.utils.hexZeroPad(constructorParamValues[index], 32);
}
if (p.startsWith("bytes")) {
invariant(
ethers.utils.isHexString(constructorParamValues[index]),
`Could not parse bytes value. Expected valid hex string but got "${constructorParamValues[index]}".`,
);
return ethers.utils.toUtf8Bytes(constructorParamValues[index]);
}
if (p.startsWith("uint") || p.startsWith("int")) {
return BigNumber.from(constructorParamValues[index].toString());
}
return constructorParamValues[index];
});
}

/**
* @internal
* @param abi
* @param bytecode
* @param constructorParams
*/
public async deployContractWithAbi(
abi: ContractInterface,
bytecode: BytesLike | { object: string },
constructorParams: Array<any>,
): Promise<string> {
const signer = this.getSigner();
invariant(signer, "Signer is required to deploy contracts");
const deployer = await new ethers.ContractFactory(abi, bytecode)
.connect(signer)
.deploy(...constructorParams);
const deployedContract = await deployer.deployed();
// TODO parse transaction receipt
return deployedContract.address;
}

private toPublishedContract(
contractModel: IContractPublisher.CustomContractInstanceStruct,
): PublishedContract {
Expand Down
3 changes: 1 addition & 2 deletions test/custom.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ describe("Custom Contracts", async () => {

beforeEach(async () => {
sdk.updateSignerOrProvider(adminWallet);
const publisher = sdk.getPublisher();
customContractAddress = await publisher.deployContract(
customContractAddress = await sdk.deployer.deployContractFromUri(
simpleContractUri,
[],
);
Expand Down
Loading