Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support to deployNFT and fixes smart_contract getOptions function #268

Merged
merged 13 commits into from
Sep 24, 2024
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

### Added
- Add `deployNFT` method to `WalletAddress` and `Wallet` to deploy an ERC721, updated `SmartContract` class to support deployment and fetching contract details

## [0.6.1] - 2024-09-23

### Added
Expand Down
6 changes: 6 additions & 0 deletions src/client/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1596,6 +1596,12 @@ export interface NFTContractOptions {
* @memberof NFTContractOptions
*/
'symbol': string;
/**
* The base URI for the NFT metadata
* @type {string}
* @memberof NFTContractOptions
*/
'base_uri': string;
}
/**
*
Expand Down
56 changes: 55 additions & 1 deletion src/coinbase/address/wallet_address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
Destination,
StakeOptionsMode,
CreateERC20Options,
CreateERC721Options,
} from "../types";
import { delay } from "../utils";
import { Wallet as WalletClass } from "../wallet";
Expand Down Expand Up @@ -332,7 +333,7 @@ export class WalletAddress extends Address {
* @param options.symbol - The symbol of the ERC20 token.
* @param options.totalSupply - The total supply of the ERC20 token.
* @returns A Promise that resolves to the deployed SmartContract object.
* @throws {Error} If the private key is not loaded when not using server signer.
* @throws {APIError} If the API request to create a smart contract fails.
*/
public async deployToken(options: CreateERC20Options): Promise<SmartContract> {
if (!Coinbase.useServerSigner && !this.key) {
Expand All @@ -351,6 +352,33 @@ export class WalletAddress extends Address {
return smartContract;
}

/**
* Deploys an ERC721 token contract.
*
* @param options - The options for creating the ERC721 token.
* @param options.name - The name of the ERC721 token.
* @param options.symbol - The symbol of the ERC721 token.
* @param options.baseURI - The base URI of the ERC721 token.
* @returns A Promise that resolves to the deployed SmartContract object.
* @throws {APIError} If the API request to create a smart contract fails.
*/
public async deployNFT(options: CreateERC721Options): Promise<SmartContract> {
if (!Coinbase.useServerSigner && !this.key) {
throw new Error("Cannot deploy ERC721 without private key loaded");
}

const smartContract = await this.createERC721(options);

if (Coinbase.useServerSigner) {
return smartContract;
}

await smartContract.sign(this.getSigner());
await smartContract.broadcast();

return smartContract;
}

/**
* Creates an ERC20 token contract.
*
Expand Down Expand Up @@ -378,6 +406,32 @@ export class WalletAddress extends Address {
return SmartContract.fromModel(resp?.data);
}

/**
* Creates an ERC721 token contract.
*
* @param options - The options for creating the ERC721 token.
* @param options.name - The name of the ERC721 token.
* @param options.symbol - The symbol of the ERC721 token.
* @param options.baseURI - The base URI of the ERC721 token.
* @returns A Promise that resolves to the deployed SmartContract object.
* @throws {APIError} If the private key is not loaded when not using server signer.
*/
private async createERC721(options: CreateERC721Options): Promise<SmartContract> {
const resp = await Coinbase.apiClients.smartContract!.createSmartContract(
this.getWalletId(),
this.getId(),
{
type: SmartContractType.Erc721,
options: {
name: options.name,
symbol: options.symbol,
base_uri: options.baseURI,
},
},
);
return SmartContract.fromModel(resp?.data);
}

/**
* Creates a contract invocation with the given data.
*
Expand Down
31 changes: 28 additions & 3 deletions src/coinbase/smart_contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
DeploySmartContractRequest,
SmartContract as SmartContractModel,
SmartContractType as SmartContractTypeModel,
SmartContractOptions as SmartContractOptionsModel,
TokenContractOptions as TokenContractOptionsModel,
} from "../client/api";
import { Transaction } from "./transaction";
import {
Expand Down Expand Up @@ -164,10 +166,19 @@ export class SmartContract {
* @returns The Smart Contract Options.
*/
public getOptions(): SmartContractOptions {
if (this.getType() === SmartContractType.ERC20) {
return this.model.options as TokenContractOptions;
if (this.isERC20(this.getType(), this.model.options)) {
return {
name: this.model.options.name,
symbol: this.model.options.symbol,
totalSupply: this.model.options.total_supply,
} as TokenContractOptions;
} else {
return {
name: this.model.options.name,
symbol: this.model.options.symbol,
baseURI: this.model.options.base_uri,
} as NFTContractOptions;
}
return this.model.options as NFTContractOptions;
}

/**
Expand Down Expand Up @@ -279,4 +290,18 @@ export class SmartContract {
`type: '${this.getType()}'}`
);
}

/**
* Type guard for checking if the smart contract is an ERC20.
*
* @param type - The type of the smart contract.
* @param options - The options of the smart contract.
* @returns True if the smart contract is an ERC20, false otherwise.
*/
private isERC20(
type: SmartContractType,
options: SmartContractOptionsModel,
): options is TokenContractOptionsModel {
return type === SmartContractType.ERC20;
}
}
10 changes: 10 additions & 0 deletions src/coinbase/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,7 @@ export enum SmartContractType {
export type NFTContractOptions = {
name: string;
symbol: string;
baseURI: string;
};

/**
Expand Down Expand Up @@ -976,6 +977,15 @@ export type CreateERC20Options = {
totalSupply: Amount;
};

/**
* Options for creating a ERC721.
*/
export type CreateERC721Options = {
name: string;
symbol: string;
baseURI: string;
};

/**
* Options for listing historical balances of an address.
*/
Expand Down
15 changes: 15 additions & 0 deletions src/coinbase/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
WalletCreateOptions,
WalletData,
CreateERC20Options,
CreateERC721Options,
} from "./types";
import { convertStringToHex, delay, formatDate, getWeekBackDate } from "./utils";
import { StakingOperation } from "./staking_operation";
Expand Down Expand Up @@ -783,6 +784,20 @@ export class Wallet {
return (await this.getDefaultAddress()).deployToken(options);
}

/**
* Deploys an ERC721 token contract.
*
* @param options - The options for creating the ERC721 token.
* @param options.name - The name of the ERC721 token.
* @param options.symbol - The symbol of the ERC721 token.
* @param options.baseURI - The base URI of the ERC721 token.
* @returns A Promise that resolves to the deployed SmartContract object.
* @throws {APIError} If the private key is not loaded when not using server signer.
*/
public async deployNFT(options: CreateERC721Options): Promise<SmartContract> {
return (await this.getDefaultAddress()).deployNFT(options);
}

/**
* Returns a String representation of the Wallet.
*
Expand Down
19 changes: 16 additions & 3 deletions src/examples/solana_list_rewards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,24 @@ async function listSolanaStakingRewards() {

const startTime = new Date(2024, 5).toISOString();

const rewards = await StakingReward.list(NetworkIdentifier.SolanaMainnet, Coinbase.assets.Sol, ["beefKGBWeSpHzYBHZXwp5So7wdQGX6mu4ZHCsH3uTar"], startTime, new Date().toISOString());
const rewards = await StakingReward.list(
NetworkIdentifier.SolanaMainnet,
Coinbase.assets.Sol,
["beefKGBWeSpHzYBHZXwp5So7wdQGX6mu4ZHCsH3uTar"],
startTime,
new Date().toISOString(),
);
console.log(rewards);

const addr = new Address(NetworkIdentifier.SolanaMainnet, "beefKGBWeSpHzYBHZXwp5So7wdQGX6mu4ZHCsH3uTar");
const balances = await addr.historicalStakingBalances(Coinbase.assets.Sol, startTime, new Date().toISOString());
const addr = new Address(
NetworkIdentifier.SolanaMainnet,
"beefKGBWeSpHzYBHZXwp5So7wdQGX6mu4ZHCsH3uTar",
);
const balances = await addr.historicalStakingBalances(
Coinbase.assets.Sol,
startTime,
new Date().toISOString(),
);
console.log(balances);
}

Expand Down
52 changes: 26 additions & 26 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
export * from "./coinbase/address";
export * from "./coinbase/address/external_address";
export * from "./coinbase/address/wallet_address";
export * from './coinbase/api_error';
export * from './coinbase/asset';
export * from './coinbase/authenticator';
export * from './coinbase/balance';
export * from './coinbase/balance_map';
export * from './coinbase/coinbase';
export * from './coinbase/constants';
export * from './coinbase/contract_event';
export * from './coinbase/contract_invocation';
export * from './coinbase/errors';
export * from './coinbase/faucet_transaction';
export * from './coinbase/hash';
export * from './coinbase/historical_balance';
export * from './coinbase/payload_signature';
export * from './coinbase/server_signer';
export * from './coinbase/smart_contract';
export * from './coinbase/staking_balance';
export * from './coinbase/staking_operation';
export * from './coinbase/staking_reward';
export * from './coinbase/trade';
export * from './coinbase/transaction';
export * from './coinbase/transfer';
export * from './coinbase/types';
export * from './coinbase/validator';
export * from './coinbase/wallet';
export * from './coinbase/webhook';
export * from "./coinbase/api_error";
export * from "./coinbase/asset";
export * from "./coinbase/authenticator";
export * from "./coinbase/balance";
export * from "./coinbase/balance_map";
export * from "./coinbase/coinbase";
export * from "./coinbase/constants";
export * from "./coinbase/contract_event";
export * from "./coinbase/contract_invocation";
export * from "./coinbase/errors";
export * from "./coinbase/faucet_transaction";
export * from "./coinbase/hash";
export * from "./coinbase/historical_balance";
export * from "./coinbase/payload_signature";
export * from "./coinbase/server_signer";
export * from "./coinbase/smart_contract";
export * from "./coinbase/staking_balance";
export * from "./coinbase/staking_operation";
export * from "./coinbase/staking_reward";
export * from "./coinbase/trade";
export * from "./coinbase/transaction";
export * from "./coinbase/transfer";
export * from "./coinbase/types";
export * from "./coinbase/validator";
export * from "./coinbase/wallet";
export * from "./coinbase/webhook";
12 changes: 9 additions & 3 deletions src/tests/address_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ describe("Address", () => {
const result = await address.listTransactions({ limit: 2, page: "page" });
expect(result.transactions.length).toEqual(2);
expect(result.transactions[0].blockHeight()).toEqual("12345");
expect(Coinbase.apiClients.transactionHistory!.listAddressTransactions).toHaveBeenCalledTimes(1);
expect(Coinbase.apiClients.transactionHistory!.listAddressTransactions).toHaveBeenCalledTimes(
1,
);
expect(Coinbase.apiClients.transactionHistory!.listAddressTransactions).toHaveBeenCalledWith(
address.getNetworkId(),
address.getId(),
Expand Down Expand Up @@ -98,7 +100,9 @@ describe("Address", () => {
const result = await address.listTransactions({});
expect(result.transactions.length).toEqual(1);
expect(result.transactions[0].blockHeight()).toEqual("12348");
expect(Coinbase.apiClients.transactionHistory!.listAddressTransactions).toHaveBeenCalledTimes(1);
expect(Coinbase.apiClients.transactionHistory!.listAddressTransactions).toHaveBeenCalledTimes(
1,
);
expect(Coinbase.apiClients.transactionHistory!.listAddressTransactions).toHaveBeenCalledWith(
address.getNetworkId(),
address.getId(),
Expand All @@ -116,7 +120,9 @@ describe("Address", () => {
});
const result = await address.listTransactions({});
expect(result.transactions.length).toEqual(0);
expect(Coinbase.apiClients.transactionHistory!.listAddressTransactions).toHaveBeenCalledTimes(1);
expect(Coinbase.apiClients.transactionHistory!.listAddressTransactions).toHaveBeenCalledTimes(
1,
);
expect(Coinbase.apiClients.transactionHistory!.listAddressTransactions).toHaveBeenCalledWith(
address.getNetworkId(),
address.getId(),
Expand Down
Loading
Loading