diff --git a/goat.code-workspace b/goat.code-workspace index 314240ad8..e3c863b66 100644 --- a/goat.code-workspace +++ b/goat.code-workspace @@ -12,6 +12,7 @@ "name": "🌋 Core", "path": "./typescript/packages/core" }, + // Adapters { "name": "[Adapter] 🎧 eleven-labs", "path": "./typescript/packages/adapters/eleven-labs" @@ -28,6 +29,7 @@ "name": "[Adapter] 🤖 vercel-ai", "path": "./typescript/packages/adapters/vercel-ai" }, + // Plugins { "name": "[Plugin] 💰 erc20", "path": "./typescript/packages/plugins/erc20" @@ -40,6 +42,11 @@ "name": "[Plugin] 💰 coingecko", "path": "./typescript/packages/plugins/coingecko" }, + { + "name": "[Plugin] 🌐 Solana NFTs", + "path": "./typescript/packages/plugins/solana-nfts" + }, + // Wallets { "name": "[Wallet] 🍀 crossmint", "path": "./typescript/packages/wallets/crossmint" @@ -48,22 +55,16 @@ "name": "[Wallet] 🌞 solana", "path": "./typescript/packages/wallets/solana" }, - { - "name": "[Plugin] 🌐 Solana NFTs", - "path": "./typescript/packages/plugins/solana-nfts" - }, - { - "name": "[Plugin] 🌐 Minting API", - "path": "./typescript/packages/plugins/minting-api" - }, { "name": "[Wallet] 💳 viem", "path": "./typescript/packages/wallets/viem" }, + // Docs { "name": "📚 Docs", "path": "./docs" }, + // Examples { "name": "🚀 Examples", "path": "./typescript/examples" diff --git a/typescript/examples/vercel-ai/crossmint-solana-custodial-wallets/index.ts b/typescript/examples/vercel-ai/crossmint-solana-custodial-wallets/index.ts index 7bbc35b4b..0b6295541 100644 --- a/typescript/examples/vercel-ai/crossmint-solana-custodial-wallets/index.ts +++ b/typescript/examples/vercel-ai/crossmint-solana-custodial-wallets/index.ts @@ -21,7 +21,6 @@ const { custodial } = crossmint(apiKey); wallet: await custodial({ chain: "solana", email: email, - env: "staging", connection: new Connection("https://api.devnet.solana.com", "confirmed"), }), }); diff --git a/typescript/examples/vercel-ai/viem/index.ts b/typescript/examples/vercel-ai/viem/index.ts index 1aba20f3a..f4164edd4 100644 --- a/typescript/examples/vercel-ai/viem/index.ts +++ b/typescript/examples/vercel-ai/viem/index.ts @@ -32,7 +32,7 @@ const walletClient = createWalletClient({ model: openai("gpt-4o-mini"), tools: tools, maxSteps: 5, - prompt: "Get my balance in USDC", + prompt: "Get the balance of the USDC token", }); console.log(result.text); diff --git a/typescript/packages/wallets/crossmint/package.json b/typescript/packages/wallets/crossmint/package.json index f84bbe713..74bbf173d 100644 --- a/typescript/packages/wallets/crossmint/package.json +++ b/typescript/packages/wallets/crossmint/package.json @@ -2,7 +2,11 @@ "name": "@goat-sdk/crossmint", "version": "0.1.7", "sideEffects": false, - "files": ["dist/**/*", "README.md", "package.json"], + "files": [ + "dist/**/*", + "README.md", + "package.json" + ], "scripts": { "build": "tsup", "clean": "rm -rf dist", @@ -12,6 +16,7 @@ "module": "./dist/index.mjs", "types": "./dist/index.d.ts", "dependencies": { + "@crossmint/common-sdk-base": "0.3.1", "@goat-sdk/core": "workspace:*", "@solana/web3.js": "catalog:", "abitype": "^1.0.6", @@ -31,5 +36,9 @@ "bugs": { "url": "https://github.com/goat-sdk/goat/issues" }, - "keywords": ["ai", "agents", "web3"] + "keywords": [ + "ai", + "agents", + "web3" + ] } diff --git a/typescript/packages/wallets/crossmint/src/api.ts b/typescript/packages/wallets/crossmint/src/api.ts index 8b64f1d62..643dbe88f 100644 --- a/typescript/packages/wallets/crossmint/src/api.ts +++ b/typescript/packages/wallets/crossmint/src/api.ts @@ -1,5 +1,6 @@ import type { EVMTypedData } from "@goat-sdk/core"; import type { SupportedSmartWalletChains } from "./chains"; +import type { CrossmintApiClient } from "@crossmint/common-sdk-base"; type CoreSignerType = | "evm-keypair" @@ -191,10 +192,8 @@ type APIResponse = | SignTypedDataResponse | ApproveSignatureResponse; -export function createCrossmintAPI(apiKey: string, env: "staging" | "production") { - const baseUrl = - env === "staging" ? "https://staging.crossmint.com/api/v1-alpha2" : "https://wwww.crossmint.com/api/v1-alpha2"; - +export function createCrossmintAPI(crossmintClient: CrossmintApiClient) { + const baseUrl = `${crossmintClient.baseUrl}/api/v1-alpha2`; /** * Makes an HTTP request to the Crossmint API. * @@ -208,8 +207,7 @@ export function createCrossmintAPI(apiKey: string, env: "staging" | "production" // Set default headers and merge with any additional headers const headers = new Headers({ - "X-API-KEY": apiKey, - "Content-Type": "application/json", + ...crossmintClient.authHeaders, ...(options.headers || {}), }); diff --git a/typescript/packages/wallets/crossmint/src/chains.ts b/typescript/packages/wallets/crossmint/src/chains.ts index 6f11fdc9e..713634d6b 100644 --- a/typescript/packages/wallets/crossmint/src/chains.ts +++ b/typescript/packages/wallets/crossmint/src/chains.ts @@ -12,7 +12,21 @@ import { sepolia, skaleNebulaTestnet, victionTestnet, + astarZkEVM, + bsc, + chiliz, + mainnet, + shape, + shapeSepolia, + skaleNebula, + xai, + xaiTestnet, + astarZkyoto, + zora, + zoraSepolia, + avalanche, } from "viem/chains"; +import type { Chain as GoatChain } from "@goat-sdk/core"; const faucetChains = [ "arbitrum-sepolia", @@ -40,22 +54,77 @@ const smartWalletChains = [ export type SupportedSmartWalletChains = (typeof smartWalletChains)[number]; -const chainMap: Record = { - arbitrum: arbitrum, +export const mintingChains = [ + "arbitrum", + "arbitrum-sepolia", + "astar-zkevm", + "avalanche", + "avalanche-fuji", + "base", + "base-sepolia", + "bsc", + "chiliz", + "chiliz-spicy-testnet", + "ethereum", + "ethereum-sepolia", + "optimism", + "optimism-sepolia", + "polygon", + "polygon-amoy", + "shape", + "shape-sepolia", + "skale-nebula", + "skale-nebula-testnet", + "soneium-minato-testnet", + "xai", + "xai-sepolia-testnet", + "zkyoto", + "zora", + "zora-sepolia", +] as const; + +export type SupportedMintingChains = (typeof mintingChains)[number]; + +const chainMap: Record< + SupportedFaucetChains | SupportedSmartWalletChains | SupportedMintingChains, + Chain +> = { + arbitrum, "arbitrum-sepolia": arbitrumSepolia, - base: base, + "astar-zkevm": astarZkEVM, + avalanche, + "avalanche-fuji": avalancheFuji, + base, "base-sepolia": baseSepolia, - optimism: optimism, + bsc, + chiliz, + ethereum: mainnet, + optimism, "optimism-sepolia": optimismSepolia, - polygon: polygon, + polygon, "polygon-amoy": polygonAmoy, - "avalanche-fuji": avalancheFuji, "ethereum-sepolia": sepolia, + shape, + "shape-sepolia": shapeSepolia, + "skale-nebula": skaleNebula, "skale-nebula-testnet": skaleNebulaTestnet, "viction-testnet": victionTestnet, + xai, + "xai-sepolia-testnet": xaiTestnet, + zkyoto: astarZkyoto, + zora, + "zora-sepolia": zoraSepolia, + "chiliz-spicy-testnet": { + id: 88882, + } as Chain, + "soneium-minato-testnet": { + id: 88882, + } as Chain, }; -export function getViemChain(chain: SupportedSmartWalletChains | SupportedFaucetChains): Chain { +export function getViemChain( + chain: SupportedSmartWalletChains | SupportedFaucetChains +): Chain { const viemChain = chainMap[chain]; if (!viemChain) { throw new Error(`Unsupported chain: ${chain}`); @@ -63,14 +132,48 @@ export function getViemChain(chain: SupportedSmartWalletChains | SupportedFaucet return viemChain; } -const testnetChains = ["arbitrum-sepolia", "base-sepolia", "optimism-sepolia", "polygon-amoy"] as const; +export function getCrossmintChainString(chain: GoatChain): string { + if (chain.type === "solana") { + return "solana"; + } + if (chain.type === "aptos") { + return "aptos"; + } + + if (chain.type === "evm") { + // from chain.id figure out the chain name + const chainName = Object.keys(chainMap).find( + (key): key is keyof typeof chainMap => + chainMap[key as keyof typeof chainMap].id === chain.id + ); + if (!chainName) { + throw new Error(`Unsupported chain: ${chain.id}`); + } + return chainName; + } -export function getEnv(chain: SupportedSmartWalletChains): "staging" | "production" { - return (testnetChains as readonly string[]).includes(chain) ? "staging" : "production"; + throw new Error(`Unsupported chain: ${chain.type}`); } -const faucetChainIds = new Set(faucetChains.map((chainName) => chainMap[chainName].id)); +const testnetChains = [ + "arbitrum-sepolia", + "base-sepolia", + "optimism-sepolia", + "polygon-amoy", +] as const; + +const faucetChainIds = new Set( + faucetChains.map((chainName) => chainMap[chainName].id) +); export function isChainSupportedByFaucet(chainId: number): boolean { return faucetChainIds.has(chainId); } + +const mintingChainIds = new Set( + mintingChains.map((chainName) => chainMap[chainName].id) +); + +export function isChainSupportedByMinting(chainId: number): boolean { + return mintingChainIds.has(chainId); +} diff --git a/typescript/packages/wallets/crossmint/src/custodial.ts b/typescript/packages/wallets/crossmint/src/custodial.ts index 6734cee89..1bdafcdb3 100644 --- a/typescript/packages/wallets/crossmint/src/custodial.ts +++ b/typescript/packages/wallets/crossmint/src/custodial.ts @@ -2,11 +2,11 @@ import type { SolanaReadRequest, SolanaTransaction, SolanaWalletClient } from "@ import { type Connection, PublicKey, TransactionMessage, VersionedTransaction } from "@solana/web3.js"; import bs58 from "bs58"; import { createCrossmintAPI } from "./api"; +import type { CrossmintApiClient } from "@crossmint/common-sdk-base"; type CommonParameters = { chain: "solana"; connection: Connection; - env?: "staging" | "production"; }; type EmailLocatorParameters = CommonParameters & { @@ -38,12 +38,12 @@ function getLocator(params: CustodialOptions): string | number { return `userId:${params.userId}:solana-custodial-wallet`; } -export function custodialFactory(apiKey: string) { +export function custodialFactory(crossmintClient: CrossmintApiClient) { return async function custodial(params: CustodialOptions): Promise { - const { connection, env = "staging" } = params; + const { connection } = params; const locator = `${getLocator(params)}`; - const client = createCrossmintAPI(apiKey, env); + const client = createCrossmintAPI(crossmintClient); const { address } = await client.getWallet(locator); return { @@ -102,7 +102,6 @@ export function custodialFactory(apiKey: string) { const latestTransaction = await client.checkTransactionStatus(locator, transactionId); if (latestTransaction.status === "success") { - console.log(`Transaction ${latestTransaction.status}`); return { hash: latestTransaction.onChain?.txId ?? "", }; diff --git a/typescript/packages/wallets/crossmint/src/faucet.ts b/typescript/packages/wallets/crossmint/src/faucet.ts index 25ba1f4ef..3580c70b8 100644 --- a/typescript/packages/wallets/crossmint/src/faucet.ts +++ b/typescript/packages/wallets/crossmint/src/faucet.ts @@ -1,13 +1,14 @@ import type { Chain, EVMWalletClient, Plugin } from "@goat-sdk/core"; import { z } from "zod"; import { isChainSupportedByFaucet } from "./chains"; +import type { CrossmintApiClient } from "@crossmint/common-sdk-base"; export const topUpBalanceParametersSchema = z.object({ wallet: z.string().optional().describe("The address to top up the balance of"), amount: z.number().min(1).max(100).describe("The amount of tokens to top up"), }); -export function faucetFactory(apiKey: string) { +export function faucetFactory(client: CrossmintApiClient) { return function faucet(): Plugin { return { name: "Crossmint Faucet", @@ -51,10 +52,7 @@ export function faucetFactory(apiKey: string) { const options = { method: "POST", - headers: { - "Content-Type": "application/json", - "X-API-KEY": apiKey, - }, + headers: client.authHeaders, body: JSON.stringify({ amount: parameters.amount, currency: "usdc", @@ -63,7 +61,7 @@ export function faucetFactory(apiKey: string) { }; const response = await fetch( - `https://staging.crossmint.com/api/v1-alpha2/wallets/${resolvedWalletAddress}/balances`, + `${client.baseUrl}/api/v1-alpha2/wallets/${resolvedWalletAddress}/balances`, options, ); diff --git a/typescript/packages/wallets/crossmint/src/index.ts b/typescript/packages/wallets/crossmint/src/index.ts index fd90c47a9..a82766e2d 100644 --- a/typescript/packages/wallets/crossmint/src/index.ts +++ b/typescript/packages/wallets/crossmint/src/index.ts @@ -1,14 +1,29 @@ import { custodialFactory } from "./custodial"; import { faucetFactory } from "./faucet"; -import { mintingAPIFactory } from "./mintingAPI"; +import { mintingFactory } from "./mint"; import { smartWalletFactory } from "./smart-wallet"; +import { Crossmint, CrossmintApiClient } from "@crossmint/common-sdk-base"; function crossmint(apiKey: string) { + const apiClient = new CrossmintApiClient( + { + apiKey, + }, + { + internalConfig: { + sdkMetadata: { + name: "crossmint-sdk-base", + version: "0.1.0", + }, + }, + } + ); + return { - custodial: custodialFactory(apiKey), - smartwallet: smartWalletFactory(apiKey), - faucet: faucetFactory(apiKey), - mintingAPI: mintingAPIFactory(apiKey), + custodial: custodialFactory(apiClient), + smartwallet: smartWalletFactory(apiClient), + faucet: faucetFactory(apiClient), + mint: mintingFactory(apiClient), }; } diff --git a/typescript/packages/wallets/crossmint/src/mint.ts b/typescript/packages/wallets/crossmint/src/mint.ts new file mode 100644 index 000000000..19f90e665 --- /dev/null +++ b/typescript/packages/wallets/crossmint/src/mint.ts @@ -0,0 +1,261 @@ +import type { Plugin, WalletClient } from "@goat-sdk/core"; +import { z } from "zod"; +import { getCrossmintChainString, isChainSupportedByMinting } from "./chains"; +import type { CrossmintApiClient } from "@crossmint/common-sdk-base"; + +export const mintingFactory = ( + client: CrossmintApiClient +): (() => Plugin) => { + return () => ({ + name: "minting", + supportsSmartWallets: () => true, + supportsChain: (chain) => { + if (chain.type === "evm") { + return isChainSupportedByMinting(chain.id ?? 0); + } + + if (chain.type === "aptos" || chain.type === "solana") { + return true; + } + + return false; + }, + getTools: async () => { + return [ + { + name: "create_nft_collection", + description: + "This {{tool}} creates an NFT collection and returns the ID of the collection.", + parameters: createCollectionParametersSchema, + method: createCollectionMethod(client), + }, + { + name: "get_all_collections", + description: + "This {{tool}} gets all the collections created by the user.", + parameters: getAllCollectionsParametersSchema, + method: getAllCollectionsMethod(client), + }, + { + name: "mint_nft", + description: + "This {{tool}} mints an NFT to a recipient from a collection and returns the transaction hash. Requires a collection ID of an already deployed collection.", + parameters: mintNFTParametersSchema, + method: mintNFTMethod(client), + }, + ]; + }, + }); +}; + +const createCollectionParametersSchema = z.object({ + metadata: z + .object({ + name: z.string().describe("The name of the collection"), + description: z + .string() + .describe("A description of the NFT collection"), + image: z + .string() + .optional() + .describe( + "URL pointing to an image that represents the collection" + ), + symbol: z + .string() + .optional() + .describe( + "Shorthand identifier for the NFT collection (Max length: 10). Defaults to 'TOKEN'" + ), + }) + .default({ + name: "My first Minting API Collection", + description: + "An NFT Collection created with the Crossmint Minting API - learn more at https://www.crossmint.com/products/nft-minting-api", + image: "https://www.crossmint.com/assets/crossmint/logo.png", + }) + .describe("The metadata of the collection"), + fungibility: z + .enum(["semi-fungible", "non-fungible"]) + .optional() + .default("non-fungible") + .describe( + "Whether or not this collection is fungible (e.g ERC-1155 vs ERC-721)" + ), + transferable: z + .boolean() + .optional() + .default(true) + .describe( + "Whether or not the NFTs in this collection are transferable" + ), +}); + +const getAllCollectionsParametersSchema = z.object({}); + +const mintNFTParametersSchema = z.object({ + collectionId: z + .string() + .describe("The ID of the collection to mint the NFT in"), + recipient: z + .string() + .describe( + "A locator for the recipient of the NFT, in the format `
` if it's a wallet or `email:` if it's an email" + ), + metadata: z + .object({ + name: z.string().describe("The name of the NFT"), + description: z + .string() + .max(64) + .describe("The description of the NFT"), + image: z.string().describe("URL pointing to the NFT image"), + animation_url: z + .string() + .optional() + .describe("URL pointing to the NFT animation"), + attributes: z + .array( + z.object({ + display_type: z + .enum([ + "number", + "boost_number", + "boost_percentage", + ]) + .describe( + "The type of the attribute, if it's a number or a percentage" + ), + value: z.string().describe("The trait value"), + }) + ) + .optional() + .describe("The attributes of the NFT"), + }) + .describe("The metadata of the NFT"), +}); + +function getAllCollectionsMethod(client: CrossmintApiClient) { + return async (walletClient: WalletClient) => { + const response = await fetch(`${client.baseUrl}/collections/`, { + headers: client.authHeaders, + }); + + return await response.json(); + }; +} + +function createCollectionMethod(client: CrossmintApiClient) { + return async ( + walletClient: WalletClient, + parameters: z.infer + ) => { + const response = await fetch( + `${client.baseUrl}/api/2022-06-09/collections/`, + { + method: "POST", + body: JSON.stringify({ + ...parameters, + chain: getCrossmintChainString(walletClient.getChain()), + }), + headers: client.authHeaders, + } + ); + + const result = await response.json(); + + if (result.error) { + throw new Error(result.message); + } + + const { id, actionId } = result; + + const action = await waitForAction(actionId, client); + + const chain = getCrossmintChainString(walletClient.getChain()); + + return { + collectionId: id, + chain, + contractAddress: action.data.collection.contractAddress, + }; + }; +} + +function mintNFTMethod(client: CrossmintApiClient) { + return async ( + walletClient: WalletClient, + parameters: z.infer + ) => { + let recipient: string; + + if (parameters.recipient.startsWith("email:")) { + recipient = `${parameters.recipient}:${getCrossmintChainString( + walletClient.getChain() + )}`; + } else { + recipient = `${getCrossmintChainString( + walletClient.getChain())}:${parameters.recipient}` + } + + const response = await fetch( + `${client.baseUrl}/api/2022-06-09/collections/${parameters.collectionId}/nfts`, + { + method: "POST", + body: JSON.stringify({ + recipient, + metadata: parameters.metadata, + }), + headers: { + ...client.authHeaders, + "Content-Type": "application/json", + }, + } + ); + + const result = await response.json(); + + if (result.error) { + throw new Error(result.message); + } + + const { id, actionId, onChain } = result; + + const action = await waitForAction(actionId, client); + + return { + id: id, + collectionId: parameters.collectionId, + contractAddress: onChain.contractAddress, + chain: action.data.chain, + }; + }; +} + +async function waitForAction( + actionId: string, + client: CrossmintApiClient +) { + let attempts = 0; + while (true) { + attempts++; + const response = await fetch( + `${client.baseUrl}/api/2022-06-09/actions/${actionId}`, + { + headers: client.authHeaders, + } + ); + + const body = await response.json(); + + if (response.status === 200 && body.status === "succeeded") { + return body; + } + await new Promise((resolve) => setTimeout(resolve, 1000)); + if (attempts >= 60) { + throw new Error( + `Timed out waiting for action ${actionId} after ${attempts} attempts` + ); + } + } +} diff --git a/typescript/packages/wallets/crossmint/src/mintingAPI.ts b/typescript/packages/wallets/crossmint/src/mintingAPI.ts deleted file mode 100644 index bc2ff50f2..000000000 --- a/typescript/packages/wallets/crossmint/src/mintingAPI.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { Plugin, WalletClient } from "@goat-sdk/core"; -import { z } from "zod"; - -export const mintingAPIFactory = ( - apiKey: string, -): ((options: { env: "production" | "staging" }) => Plugin) => { - return ({ env }) => ({ - name: "minting_api", - supportsSmartWallets: () => true, - supportsChain: (chain) => chain.type === "solana" || chain.type === "evm" || chain.type === "aptos", - getTools: async () => { - return [ - { - name: "create_nft_collection", - description: "This {{tool}} creates an NFT collection and returns the ID of the collection.", - parameters: createCollectionParametersSchema, - method: createCollectionMethod(apiKey, env), - }, - { - name: "mint_nft", - description: - "This {{tool}} mints an NFT to a recipient from a collection and returns the transaction hash. Requires a collection ID of an already deployed collection.", - parameters: mintNFTParametersSchema, - method: mintNFTMethod(apiKey, env), - }, - ]; - }, - }); -}; - -const createCollectionParametersSchema = z.object({ - metadata: z - .object({ - name: z.string().describe("The name of the collection"), - description: z.string().describe("The description of the collection"), - image: z.string().describe("The image of the collection"), - }) - .optional() - .default({ - name: "My first Minting API Collection", - description: - "An NFT Collection created with the Crossmint Minting API - learn more at https://www.crossmint.com/products/nft-minting-api", - image: "https://www.crossmint.com/assets/crossmint/logo.png", - }) - .describe("The metadata of the collection"), - chain: z.string().describe("The name of the blockchain that the collection is being created on"), -}); - -const mintNFTParametersSchema = z.object({ - collectionId: z.string().describe("The ID of the collection to mint the NFT in"), - recipient: z.string().describe("A locator for the recipient of the NFT, in the format :
"), - metadata: z - .object({ - name: z.string().describe("The name of the NFT"), - description: z.string().describe("The description of the NFT"), - image: z.string().describe("The image of the NFT"), - }) - .describe("The metadata of the NFT"), -}); - -function createCollectionMethod(apiKey: string, env: "staging" | "production") { - return async (_walletClient: WalletClient, parameters: z.infer) => { - const id = randomUUID().toString(); - await fetch(`${getBaseUrl(env)}/collections/${id}`, { - method: "PUT", - body: JSON.stringify({ - ...parameters, - }), - headers: { - "x-api-key": apiKey, - "Content-Type": "application/json", - }, - }); - const body = await waitForAction(id, apiKey, env); - return { - collectionId: id, - chain: parameters.chain, - contractAddress: body.data.collection.contractAddress, - }; - }; -} - -function mintNFTMethod(apiKey: string, env: "staging" | "production") { - return async (_walletClient: WalletClient, parameters: z.infer) => { - const id = randomUUID().toString(); - await fetch(`${getBaseUrl(env)}/collections/${parameters.collectionId}/nfts/${id}`, { - method: "PUT", - body: JSON.stringify({ - recipient: parameters.recipient, - metadata: parameters.metadata, - }), - headers: { - "x-api-key": apiKey, - "Content-Type": "application/json", - }, - }); - const body = await waitForAction(id, apiKey, env); - return body.data.txId as string; - }; -} - -async function waitForAction(actionId: string, apiKey: string, env: "staging" | "production") { - let attempts = 0; - while (true) { - attempts++; - const response = await fetch(`${getBaseUrl(env)}/actions/${actionId}`, { - headers: { - "x-api-key": apiKey, - }, - }); - const body = await response.json(); - - if (response.status === 200 && body.status === "succeeded") { - return body; - } - await new Promise((resolve) => setTimeout(resolve, 1000)); - if (attempts >= 60) { - throw new Error(`Timed out waiting for action ${actionId} after ${attempts} attempts`); - } - } -} - -function getBaseUrl(env: "staging" | "production") { - return env === "staging" - ? "https://staging.crossmint.com/api/2022-06-09" - : "https://www.crossmint.com/api/2022-06-09"; -} diff --git a/typescript/packages/wallets/crossmint/src/smart-wallet.ts b/typescript/packages/wallets/crossmint/src/smart-wallet.ts index a26931493..2c6a68583 100644 --- a/typescript/packages/wallets/crossmint/src/smart-wallet.ts +++ b/typescript/packages/wallets/crossmint/src/smart-wallet.ts @@ -6,7 +6,8 @@ import { privateKeyToAccount } from "viem/accounts"; import { mainnet } from "viem/chains"; import { normalize } from "viem/ens"; import { createCrossmintAPI } from "./api"; -import { type SupportedSmartWalletChains, getEnv, getViemChain } from "./chains"; +import { type SupportedSmartWalletChains, getViemChain } from "./chains"; +import type { CrossmintApiClient } from "@crossmint/common-sdk-base"; export type CustodialSigner = `0x${string}`; @@ -37,7 +38,7 @@ export type SmartWalletOptions = { }; }; -export function smartWalletFactory(apiKey: string) { +export function smartWalletFactory(crossmintClient: CrossmintApiClient) { return async function smartwallet(params: SmartWalletOptions): Promise { const { signer, linkedUser, chain, provider, address: providedAddress } = params; @@ -63,7 +64,7 @@ export function smartWalletFactory(apiKey: string) { }; const locator = getLocator(); - const client = createCrossmintAPI(apiKey, getEnv(chain)); + const client = createCrossmintAPI(crossmintClient); const { address } = await client.getWallet(locator); const viemClient = createPublicClient({ @@ -79,7 +80,6 @@ export function smartWalletFactory(apiKey: string) { }); const resolveAddressImpl = async (address: string) => { - console.log("Address", address); if (/^0x[a-fA-F0-9]{40}$/.test(address)) { return address as `0x${string}`; } diff --git a/typescript/pnpm-lock.yaml b/typescript/pnpm-lock.yaml index 5c95550f3..f16b0d376 100644 --- a/typescript/pnpm-lock.yaml +++ b/typescript/pnpm-lock.yaml @@ -324,6 +324,9 @@ importers: '@goat-sdk/core': specifier: workspace:* version: link:../../../packages/core + '@goat-sdk/crossmint': + specifier: workspace:* + version: link:../../../packages/wallets/crossmint '@goat-sdk/plugin-erc20': specifier: workspace:* version: link:../../../packages/plugins/erc20 @@ -471,6 +474,9 @@ importers: packages/wallets/crossmint: dependencies: + '@crossmint/common-sdk-base': + specifier: 0.3.1 + version: 0.3.1 '@goat-sdk/core': specifier: workspace:* version: link:../../core @@ -933,6 +939,9 @@ packages: '@coinbase/wallet-sdk@4.2.3': resolution: {integrity: sha512-BcyHZ/Ec84z0emORzqdXDv4P0oV+tV3a0OirfA8Ko1JGBIAVvB+hzLvZzCDvnuZx7MTK+Dd8Y9Tjlo446BpCIg==} + '@crossmint/common-sdk-base@0.3.1': + resolution: {integrity: sha512-07M1epHTEfvsbsu7BoBrHgH6ou2LUEymWyQUiSKn8zChmRPNG1ZFGiBQpqkfhyp3zGvLn2L9GzEbqk9dNwrFfw==} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -2432,6 +2441,9 @@ packages: base-x@3.0.10: resolution: {integrity: sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==} + base-x@4.0.0: + resolution: {integrity: sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==} + base-x@5.0.0: resolution: {integrity: sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==} @@ -2498,6 +2510,9 @@ packages: bs58@4.0.1: resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + bs58@5.0.0: + resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==} + bs58@6.0.0: resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} @@ -5789,6 +5804,11 @@ snapshots: eventemitter3: 5.0.1 preact: 10.25.1 + '@crossmint/common-sdk-base@0.3.1': + dependencies: + bs58: 5.0.0 + tweetnacl: 1.0.3 + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -7587,6 +7607,8 @@ snapshots: dependencies: safe-buffer: 5.2.1 + base-x@4.0.0: {} + base-x@5.0.0: {} base64-js@1.5.1: {} @@ -7657,6 +7679,10 @@ snapshots: dependencies: base-x: 3.0.10 + bs58@5.0.0: + dependencies: + base-x: 4.0.0 + bs58@6.0.0: dependencies: base-x: 5.0.0