@coinbase/agentkit
Version:
Coinbase AgentKit core primitives
439 lines (438 loc) • 19.6 kB
JavaScript
;
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _PrivyEvmDelegatedEmbeddedWalletProvider_walletId, _PrivyEvmDelegatedEmbeddedWalletProvider_address, _PrivyEvmDelegatedEmbeddedWalletProvider_appId, _PrivyEvmDelegatedEmbeddedWalletProvider_appSecret, _PrivyEvmDelegatedEmbeddedWalletProvider_authKey, _PrivyEvmDelegatedEmbeddedWalletProvider_network, _PrivyEvmDelegatedEmbeddedWalletProvider_publicClient;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PrivyEvmDelegatedEmbeddedWalletProvider = void 0;
const canonicalize_1 = __importDefault(require("canonicalize"));
const crypto_1 = __importDefault(require("crypto"));
const viem_1 = require("viem");
const network_1 = require("../network/network");
const privyShared_1 = require("./privyShared");
const walletProvider_1 = require("./walletProvider");
/**
* A wallet provider that uses Privy's embedded wallets with delegation.
* This provider extends the EvmWalletProvider to provide Privy-specific wallet functionality
* while maintaining compatibility with the base wallet provider interface.
*/
class PrivyEvmDelegatedEmbeddedWalletProvider extends walletProvider_1.WalletProvider {
/**
* Private constructor to enforce use of factory method.
*
* @param config - The configuration options for the wallet provider
*/
constructor(config) {
super();
_PrivyEvmDelegatedEmbeddedWalletProvider_walletId.set(this, void 0);
_PrivyEvmDelegatedEmbeddedWalletProvider_address.set(this, void 0);
_PrivyEvmDelegatedEmbeddedWalletProvider_appId.set(this, void 0);
_PrivyEvmDelegatedEmbeddedWalletProvider_appSecret.set(this, void 0);
_PrivyEvmDelegatedEmbeddedWalletProvider_authKey.set(this, void 0);
_PrivyEvmDelegatedEmbeddedWalletProvider_network.set(this, void 0);
_PrivyEvmDelegatedEmbeddedWalletProvider_publicClient.set(this, void 0);
__classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_walletId, config.walletId, "f");
__classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, config.address, "f");
__classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_appId, config.appId, "f");
__classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_appSecret, config.appSecret, "f");
__classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_authKey, config.authorizationPrivateKey || "", "f");
const networkId = config.networkId || "base-sepolia";
const chainId = config.chainId || network_1.NETWORK_ID_TO_CHAIN_ID[networkId];
__classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, {
protocolFamily: "evm",
networkId: networkId,
chainId: chainId,
}, "f");
// Create a public client for read operations
const chain = (0, network_1.getChain)(chainId);
if (!chain) {
throw new Error(`Chain with ID ${chainId} not found`);
}
__classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_publicClient, (0, viem_1.createPublicClient)({
chain,
transport: (0, viem_1.http)(),
}), "f");
}
/**
* Creates and configures a new PrivyEvmDelegatedEmbeddedWalletProvider instance.
*
* @param config - The configuration options for the Privy wallet
* @returns A configured PrivyEvmDelegatedEmbeddedWalletProvider instance
*
* @example
* ```typescript
* const provider = await PrivyEvmDelegatedEmbeddedWalletProvider.configureWithWallet({
* appId: "your-app-id",
* appSecret: "your-app-secret",
* authorizationPrivateKey: "your-auth-key",
* walletId: "privy-wallet-id",
* networkId: "base-mainnet"
* });
* ```
*/
static async configureWithWallet(config) {
try {
if (!config.walletId) {
throw new Error("walletId is required for PrivyEvmDelegatedEmbeddedWalletProvider");
}
if (!config.appId || !config.appSecret) {
throw new Error("appId and appSecret are required for PrivyEvmDelegatedEmbeddedWalletProvider");
}
if (!config.authorizationPrivateKey) {
throw new Error("authorizationPrivateKey is required for PrivyEvmDelegatedEmbeddedWalletProvider");
}
const privyClient = (0, privyShared_1.createPrivyClient)(config);
const user = await privyClient.getUser(config.walletId);
const embeddedWallets = user.linkedAccounts.filter((account) => account.type === "wallet" && account.walletClientType === "privy");
if (embeddedWallets.length === 0) {
throw new Error(`Could not find wallet address for wallet ID ${config.walletId}`);
}
const walletAddress = embeddedWallets[0].address;
// Verify the network/chain ID if provided
if (config.chainId) {
const chain = (0, network_1.getChain)(config.chainId);
if (!chain) {
throw new Error(`Chain with ID ${config.chainId} not found`);
}
}
return new PrivyEvmDelegatedEmbeddedWalletProvider({
...config,
address: walletAddress,
});
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Failed to configure Privy embedded wallet provider: ${error.message}`);
}
throw new Error("Failed to configure Privy embedded wallet provider");
}
}
/**
* Gets the address of the wallet.
*
* @returns The address of the wallet.
*/
getAddress() {
return __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f");
}
/**
* Gets the network of the wallet.
*
* @returns The network of the wallet.
*/
getNetwork() {
return __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, "f");
}
/**
* Gets the name of the wallet provider.
*
* @returns The name of the wallet provider.
*/
getName() {
return "privy_evm_embedded_wallet_provider";
}
/**
* Gets the balance of the wallet.
*
* @returns The balance of the wallet in wei
*/
async getBalance() {
try {
const balance = await __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_publicClient, "f").getBalance({
address: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"),
});
return balance;
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Error getting balance: ${error.message}`);
}
throw new Error("Error getting balance");
}
}
/**
* Signs a message.
*
* @param message - The message to sign.
* @returns The signed message.
*/
async signMessage(message) {
const body = {
address: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"),
chain_type: "ethereum",
method: "personal_sign",
params: {
message,
encoding: "utf-8",
},
};
try {
const response = await this.executePrivyRequest(body);
return response.data?.signature;
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Message signing failed: ${error.message}`);
}
throw new Error("Message signing failed");
}
}
/**
* Signs typed data according to EIP-712.
*
* @param typedData - The typed data object to sign
* @param typedData.domain - The domain object containing contract and chain information
* @param typedData.types - The type definitions for the structured data
* @param typedData.primaryType - The primary type being signed
* @param typedData.message - The actual data to sign
* @returns A Address that resolves to the signed typed data as a hex string
*/
async signTypedData(typedData) {
const body = {
address: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"),
chain_type: "ethereum",
chain_id: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, "f").chainId,
...typedData,
};
try {
const response = await this.executePrivyRequest({
method: "eth_signTypedData_v4",
params: body,
});
return response.signature;
}
catch (error) {
if (error instanceof Error) {
throw new Error("Typed data signing failed: " + error.message);
}
throw new Error("Typed data signing failed with unknown error");
}
}
/**
* Signs a transaction.
*
* @param transaction - The transaction to sign.
* @returns The signed transaction.
*/
async signTransaction(transaction) {
const body = {
address: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"),
chain_type: "ethereum",
method: "eth_signTransaction",
params: {
transaction: {
...transaction,
from: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"),
},
},
};
try {
const response = await this.executePrivyRequest(body);
return response.data?.signed_transaction;
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Transaction signing failed: ${error.message}`);
}
throw new Error("Transaction signing failed");
}
}
/**
* Sends a transaction.
*
* @param transaction - The transaction to send.
* @returns The hash of the transaction.
*/
async sendTransaction(transaction) {
const body = {
address: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"),
chain_type: "ethereum",
method: "eth_sendTransaction",
caip2: `eip155:${__classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, "f").chainId}`,
params: {
transaction: {
...transaction,
from: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"),
},
},
};
try {
const response = await this.executePrivyRequest(body);
return response.data?.hash;
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Transaction sending failed: ${error.message}`);
}
throw new Error("Transaction sending failed");
}
}
/**
* Waits for a transaction receipt.
*
* @param txHash - The hash of the transaction to wait for.
* @returns The transaction receipt.
*/
async waitForTransactionReceipt(txHash) {
return await __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_publicClient, "f").waitForTransactionReceipt({
hash: txHash,
});
}
/**
* Reads data from a smart contract.
*
* @param params - Parameters for reading the contract
* @param params.address - The address of the contract
* @param params.abi - The ABI of the contract
* @param params.functionName - The name of the function to call
* @param params.args - The arguments to pass to the function
* @returns A Address that resolves to the contract function's return value
*/
async readContract(params) {
return __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_publicClient, "f").readContract(params);
}
/**
* Transfer the native asset of the network.
*
* @param to - The destination address.
* @param value - The amount to transfer in Wei.
* @returns The transaction hash.
*/
async nativeTransfer(to, value) {
const valueInWei = (0, viem_1.parseEther)(value);
const valueHex = `0x${valueInWei.toString(16)}`;
const body = {
address: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"),
chain_type: "ethereum",
method: "eth_sendTransaction",
caip2: `eip155:${__classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, "f").chainId}`,
params: {
transaction: {
to,
value: valueHex,
},
},
};
try {
const response = await this.executePrivyRequest(body);
const receipt = await this.waitForTransactionReceipt(response.data.hash);
if (!receipt) {
throw new Error("Transaction failed");
}
return receipt.transactionHash;
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Native transfer failed: ${error.message}`);
}
throw new Error("Native transfer failed");
}
}
/**
* Exports the wallet information.
*
* @returns The wallet data
*/
exportWallet() {
return {
walletId: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_walletId, "f"),
authorizationPrivateKey: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_authKey, "f"),
networkId: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, "f").networkId,
chainId: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, "f").chainId,
};
}
/**
* Generate Privy authorization signature for API requests
*
* @param url - The URL for the request
* @param body - The request body
* @returns The generated signature
*/
generatePrivySignature(url, body) {
try {
const payload = {
version: 1,
method: "POST",
url,
body,
headers: {
"privy-app-id": __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_appId, "f"),
},
};
const serializedPayload = (0, canonicalize_1.default)(payload);
if (!serializedPayload)
throw new Error("Failed to canonicalize payload");
const serializedPayloadBuffer = Buffer.from(serializedPayload);
const privateKeyAsString = __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_authKey, "f").replace("wallet-auth:", "");
const privateKeyAsPem = `-----BEGIN PRIVATE KEY-----\n${privateKeyAsString}\n-----END PRIVATE KEY-----`;
const privateKey = crypto_1.default.createPrivateKey({
key: privateKeyAsPem,
format: "pem",
});
const signatureBuffer = crypto_1.default.sign("sha256", serializedPayloadBuffer, privateKey);
return signatureBuffer.toString("base64");
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Error generating Privy authorization signature: ${error.message}`);
}
throw new Error("Error generating Privy authorization signature");
}
}
/**
* Get Privy headers for API requests
*
* @param url - The URL for the request
* @param body - The request body
* @returns The headers for the request
*/
getPrivyHeaders(url, body) {
return {
"Content-Type": "application/json",
Authorization: `Basic ${Buffer.from(`${__classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_appId, "f")}:${__classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_appSecret, "f")}`).toString("base64")}`,
"privy-app-id": __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_appId, "f"),
"privy-authorization-signature": this.generatePrivySignature(url, body),
};
}
/**
* Execute a Privy API request.
*
* @param body - The request body to send to the Privy API
* @returns A promise that resolves to the response data
* @throws Error if the request fails
*/
async executePrivyRequest(body) {
const url = `https://api.privy.io/v1/wallets/rpc`;
const headers = this.getPrivyHeaders(url, body);
try {
const response = await fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
}
catch (error) {
if (error instanceof Error) {
throw new Error("Privy request failed: " + error.message);
}
throw new Error("Privy request failed with unknown error");
}
}
}
exports.PrivyEvmDelegatedEmbeddedWalletProvider = PrivyEvmDelegatedEmbeddedWalletProvider;
_PrivyEvmDelegatedEmbeddedWalletProvider_walletId = new WeakMap(), _PrivyEvmDelegatedEmbeddedWalletProvider_address = new WeakMap(), _PrivyEvmDelegatedEmbeddedWalletProvider_appId = new WeakMap(), _PrivyEvmDelegatedEmbeddedWalletProvider_appSecret = new WeakMap(), _PrivyEvmDelegatedEmbeddedWalletProvider_authKey = new WeakMap(), _PrivyEvmDelegatedEmbeddedWalletProvider_network = new WeakMap(), _PrivyEvmDelegatedEmbeddedWalletProvider_publicClient = new WeakMap();