Skip to content

Commit 3c8a5e3

Browse files
committed
create token
1 parent aba8654 commit 3c8a5e3

File tree

7 files changed

+333
-7
lines changed

7 files changed

+333
-7
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[
2+
"function initialize(string _name, string _symbol, string _contractURI, uint256 _maxSupply, address _owner) external"
3+
]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const DEFAULT_MAX_SUPPLY_ERC20 = 10_000_000n;
2+
3+
export const IMPLEMENTATIONS: Record<number, Record<string, string>> = {
4+
[84532]: {
5+
AssetEntrypointERC20: "0x79C1236cFe59f1f088A15Da08b0D8667387d9703",
6+
},
7+
};
Lines changed: 109 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,111 @@
1-
export type CreateTokenArgs = {}
1+
import type { Hex } from "viem";
2+
import type { ThirdwebClient } from "../client/client.js";
3+
import { ZERO_ADDRESS } from "../constants/addresses.js";
4+
import { getContract } from "../contract/contract.js";
5+
import { createAsset } from "../extensions/assets/__generated__/AssetEntrypointERC20/write/createAsset.js";
6+
import { encodeInitialize } from "../extensions/assets/__generated__/ERC20Asset/write/initialize.js";
7+
import { eth_blockNumber } from "../rpc/actions/eth_blockNumber.js";
8+
import { getRpcClient } from "../rpc/rpc.js";
9+
import { upload } from "../storage/upload.js";
10+
import type { FileOrBufferOrString } from "../storage/upload/types.js";
11+
import { sendTransaction } from "../transaction/actions/send-transaction.js";
12+
import { keccakId } from "../utils/any-evm/keccak-id.js";
13+
import { toHex } from "../utils/encoding/hex.js";
14+
import type { ClientAndChainAndAccount } from "../utils/types.js";
15+
import { DEFAULT_MAX_SUPPLY_ERC20 } from "./constants.js";
16+
import { getEntrypointERC20 } from "./get-entrypoint-erc20.js";
217

3-
export function createToken(params: CreateTokenArgs) {
18+
export type TokenParams = {
19+
name: string;
20+
description?: string;
21+
image?: FileOrBufferOrString;
22+
external_link?: string;
23+
social_urls?: Record<string, string>;
24+
symbol?: string;
25+
contractURI?: string;
26+
maxSupply?: bigint;
27+
owner?: string;
28+
};
429

5-
}
30+
export type CreateTokenOptions = ClientAndChainAndAccount & {
31+
salt?: string;
32+
params: TokenParams;
33+
};
34+
35+
export async function createToken(options: CreateTokenOptions) {
36+
const { chain, client, account, params } = options;
37+
38+
const creator = params.owner || account.address;
39+
40+
const encodedInitData = await encodeInitParams({
41+
client,
42+
params,
43+
creator,
44+
});
45+
46+
const rpcRequest = getRpcClient({
47+
...options,
48+
});
49+
const blockNumber = await eth_blockNumber(rpcRequest);
50+
const salt = options.salt
51+
? options.salt.startsWith("0x") && options.salt.length === 66
52+
? (options.salt as `0x${string}`)
53+
: keccakId(options.salt)
54+
: toHex(blockNumber, {
55+
size: 32,
56+
});
57+
58+
const entrypointAddress = await getEntrypointERC20(chain);
59+
const entrypoint = getContract({
60+
client,
61+
address: entrypointAddress,
62+
chain,
63+
});
64+
65+
const transaction = createAsset({
66+
contract: entrypoint,
67+
creator,
68+
createParams: {
69+
amount: params.maxSupply || DEFAULT_MAX_SUPPLY_ERC20,
70+
referrer: ZERO_ADDRESS,
71+
salt,
72+
data: encodedInitData,
73+
hookData: "0x",
74+
},
75+
});
76+
77+
return await sendTransaction({ account, transaction });
78+
}
79+
80+
async function encodeInitParams(options: {
81+
client: ThirdwebClient;
82+
params: TokenParams;
83+
creator: string;
84+
}): Promise<Hex> {
85+
const { client, params, creator } = options;
86+
87+
const contractURI =
88+
options.params.contractURI ||
89+
(await upload({
90+
client,
91+
files: [
92+
{
93+
name: params.name,
94+
description: params.description,
95+
symbol: params.symbol,
96+
image: params.image,
97+
external_link: params.external_link,
98+
social_urls: params.social_urls,
99+
},
100+
],
101+
})) ||
102+
"";
103+
104+
return encodeInitialize({
105+
name: params.name,
106+
symbol: params.symbol || params.name,
107+
contractURI,
108+
maxSupply: params.maxSupply || DEFAULT_MAX_SUPPLY_ERC20,
109+
owner: creator,
110+
});
111+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { Chain } from "../chains/types.js";
2+
import { IMPLEMENTATIONS } from "./constants.js";
3+
4+
export async function getEntrypointERC20(chain: Chain): Promise<string> {
5+
// TODO: bootstrap all infra
6+
7+
const implementations = IMPLEMENTATIONS[chain.id];
8+
9+
if (!implementations) {
10+
throw new Error(`Entrypoint not found for chain: ${chain.id}`);
11+
}
12+
13+
const entrypointAddress = implementations.AssetEntrypointERC20;
14+
15+
if (!entrypointAddress) {
16+
throw new Error(`Entrypoint not found for chain: ${chain.id}`);
17+
}
18+
19+
return entrypointAddress;
20+
}
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export {
2-
createToken,
3-
type CreateTokenArgs,
4-
} from "./create-token.js";
2+
createToken,
3+
type CreateTokenOptions,
4+
type TokenParams,
5+
} from "./create-token.js";
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export * from "../assets/index.js";
1+
export * from "../assets/index.js";

packages/thirdweb/src/extensions/assets/__generated__/ERC20Asset/write/initialize.ts

Lines changed: 189 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)