@coinbase/agentkit
Version:
Coinbase AgentKit core primitives
295 lines (294 loc) • 12.9 kB
JavaScript
"use strict";
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 _CdpSolanaWalletProvider_connection, _CdpSolanaWalletProvider_cdp, _CdpSolanaWalletProvider_network, _CdpSolanaWalletProvider_serverAccount;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CdpSolanaWalletProvider = void 0;
const cdp_sdk_1 = require("@coinbase/cdp-sdk");
const web3_js_1 = require("@solana/web3.js");
const bs58_1 = __importDefault(require("bs58"));
const svm_1 = require("../network/svm");
const svmWalletProvider_1 = require("./svmWalletProvider");
/**
* A wallet provider that uses the Coinbase SDK.
*/
class CdpSolanaWalletProvider extends svmWalletProvider_1.SvmWalletProvider {
/**
* Constructs a new CdpSolanaWalletProvider.
*
* @param config - The configuration options for the CdpSolanaWalletProvider.
*/
constructor(config) {
super();
_CdpSolanaWalletProvider_connection.set(this, void 0);
_CdpSolanaWalletProvider_cdp.set(this, void 0);
_CdpSolanaWalletProvider_network.set(this, void 0);
_CdpSolanaWalletProvider_serverAccount.set(this, void 0);
__classPrivateFieldSet(this, _CdpSolanaWalletProvider_serverAccount, config.serverAccount, "f");
__classPrivateFieldSet(this, _CdpSolanaWalletProvider_cdp, config.cdp, "f");
__classPrivateFieldSet(this, _CdpSolanaWalletProvider_connection, config.connection, "f");
__classPrivateFieldSet(this, _CdpSolanaWalletProvider_network, config.network, "f");
}
/**
* Configures a new CdpSolanaWalletProvider with a wallet.
*
* @param config - Optional configuration parameters
* @returns A Promise that resolves to a new CdpSolanaWalletProvider instance
* @throws Error if required environment variables are missing or wallet initialization fails
*/
static async configureWithWallet(config = {}) {
const apiKeyId = config.apiKeyId || process.env.CDP_API_KEY_ID;
const apiKeySecret = config.apiKeySecret || process.env.CDP_API_KEY_SECRET;
const walletSecret = config.walletSecret || process.env.CDP_WALLET_SECRET;
const idempotencyKey = config.idempotencyKey || process.env.IDEMPOTENCY_KEY;
if (!apiKeyId || !apiKeySecret || !walletSecret) {
throw new Error("Missing required environment variables. CDP_API_KEY_ID, CDP_API_KEY_SECRET, CDP_WALLET_SECRET are required.");
}
const networkId = config.networkId || process.env.NETWORK_ID || "solana-devnet";
let network;
let rpcUrl;
switch (networkId) {
case svm_1.SOLANA_MAINNET_NETWORK_ID:
network = svm_1.SOLANA_MAINNET_NETWORK;
rpcUrl = (0, web3_js_1.clusterApiUrl)("mainnet-beta");
break;
case svm_1.SOLANA_DEVNET_NETWORK_ID:
network = svm_1.SOLANA_DEVNET_NETWORK;
rpcUrl = (0, web3_js_1.clusterApiUrl)("devnet");
break;
case svm_1.SOLANA_TESTNET_NETWORK_ID:
network = svm_1.SOLANA_TESTNET_NETWORK;
rpcUrl = (0, web3_js_1.clusterApiUrl)("testnet");
break;
default:
throw new Error(`${networkId} is not a valid SVM networkId`);
}
const cdpClient = new cdp_sdk_1.CdpClient({
apiKeyId,
apiKeySecret,
walletSecret,
});
const connection = new web3_js_1.Connection(rpcUrl);
const serverAccount = await (config.address
? cdpClient.solana.getAccount({ address: config.address })
: cdpClient.solana.createAccount({ idempotencyKey }));
return new CdpSolanaWalletProvider({
connection,
cdp: cdpClient,
serverAccount,
network,
});
}
/**
* Exports the wallet.
*
* @returns The wallet's data.
*/
async exportWallet() {
return {
name: __classPrivateFieldGet(this, _CdpSolanaWalletProvider_serverAccount, "f").name,
address: __classPrivateFieldGet(this, _CdpSolanaWalletProvider_serverAccount, "f").address,
};
}
/**
* Get the connection instance
*
* @returns The Solana connection instance
*/
getConnection() {
return __classPrivateFieldGet(this, _CdpSolanaWalletProvider_connection, "f");
}
/**
* Get the public key of the wallet
*
* @returns The wallet's public key
*/
getPublicKey() {
return new web3_js_1.PublicKey(__classPrivateFieldGet(this, _CdpSolanaWalletProvider_serverAccount, "f").address);
}
/**
* Get the address of the wallet
*
* @returns The base58 encoded address of the wallet
*/
getAddress() {
return __classPrivateFieldGet(this, _CdpSolanaWalletProvider_serverAccount, "f").address;
}
/**
* Get the network
*
* @returns The network
*/
getNetwork() {
return __classPrivateFieldGet(this, _CdpSolanaWalletProvider_network, "f");
}
/**
* Gets the name of the wallet provider.
*
* @returns The name of the wallet provider.
*/
getName() {
return "cdp_solana_wallet_provider";
}
/**
* Sign a transaction
*
* @param transaction - The transaction to sign
* @returns The signed transaction
*/
async signTransaction(transaction) {
const serializedTransaction = transaction.serialize();
const encodedSerializedTransaction = Buffer.from(serializedTransaction).toString("base64");
const signedTransactionResponse = await __classPrivateFieldGet(this, _CdpSolanaWalletProvider_cdp, "f").solana.signTransaction({
transaction: encodedSerializedTransaction,
address: __classPrivateFieldGet(this, _CdpSolanaWalletProvider_serverAccount, "f").address,
});
const signedTransactionBytes = Buffer.from(signedTransactionResponse.signedTransaction, "base64");
const signedTransaction = web3_js_1.VersionedTransaction.deserialize(signedTransactionBytes);
return signedTransaction;
}
/**
* Send a transaction
*
* @param transaction - The transaction to send
* @returns The signature
*/
async sendTransaction(transaction) {
const signature = await __classPrivateFieldGet(this, _CdpSolanaWalletProvider_connection, "f").sendTransaction(transaction);
await this.waitForSignatureResult(signature);
return signature;
}
/**
* Sign and send a transaction
*
* @param transaction - The transaction to sign and send
* @returns The signature
*/
async signAndSendTransaction(transaction) {
const signedTransaction = await this.signTransaction(transaction);
return this.sendTransaction(signedTransaction);
}
/**
* Get the status of a transaction
*
* @param signature - The signature
* @param options - The options for the status
* @returns The status
*/
async getSignatureStatus(signature, options) {
return __classPrivateFieldGet(this, _CdpSolanaWalletProvider_connection, "f").getSignatureStatus(signature, options);
}
/**
* Wait for signature receipt
*
* @param signature - The signature
* @returns The confirmation response
*/
async waitForSignatureResult(signature) {
const { blockhash, lastValidBlockHeight } = await __classPrivateFieldGet(this, _CdpSolanaWalletProvider_connection, "f").getLatestBlockhash();
return __classPrivateFieldGet(this, _CdpSolanaWalletProvider_connection, "f").confirmTransaction({
signature: signature,
lastValidBlockHeight,
blockhash,
});
}
/**
* Get the balance of the wallet
*
* @returns The balance of the wallet
*/
getBalance() {
return __classPrivateFieldGet(this, _CdpSolanaWalletProvider_connection, "f").getBalance(this.getPublicKey()).then(balance => BigInt(balance));
}
/**
* Gets the CDP client.
*
* @returns The CDP client.
*/
getClient() {
return __classPrivateFieldGet(this, _CdpSolanaWalletProvider_cdp, "f");
}
/**
* Sign a message.
*
* @param message - The message to sign as a Uint8Array
* @returns The signature as a Uint8Array
*/
async signMessage(message) {
// Convert Uint8Array to string for CDP SDK
const messageString = Buffer.from(message).toString("utf8");
const { signature } = await __classPrivateFieldGet(this, _CdpSolanaWalletProvider_cdp, "f").solana.signMessage({
address: __classPrivateFieldGet(this, _CdpSolanaWalletProvider_serverAccount, "f").address,
message: messageString,
});
// Convert signature string back to Uint8Array
// CDP returns signature as a hex string, convert to bytes
return new Uint8Array(Buffer.from(signature, "hex"));
}
/**
* Transfer SOL from the wallet to another address
*
* @param to - The base58 encoded address to transfer the SOL to
* @param value - The amount to transfer in atomic units (Lamports)
* @returns The signature
*/
async nativeTransfer(to, value) {
const initialBalance = await this.getBalance();
const lamports = BigInt(value);
// Check if we have enough balance (including estimated fees)
if (initialBalance < lamports + BigInt(5000)) {
throw new Error(`Insufficient balance. Have ${Number(initialBalance)} lamports, need ${Number(lamports) + 5000} lamports (including fees)`);
}
const toPubkey = new web3_js_1.PublicKey(to);
const instructions = [
web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({
microLamports: 10000,
}),
web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
units: 2000,
}),
web3_js_1.SystemProgram.transfer({
fromPubkey: this.getPublicKey(),
toPubkey: toPubkey,
lamports: lamports,
}),
];
const tx = new web3_js_1.VersionedTransaction(web3_js_1.MessageV0.compile({
payerKey: this.getPublicKey(),
instructions: instructions,
recentBlockhash: (await __classPrivateFieldGet(this, _CdpSolanaWalletProvider_connection, "f").getLatestBlockhash()).blockhash,
}));
const signature = await this.signAndSendTransaction(tx);
await this.waitForSignatureResult(signature);
return signature;
}
/**
* Get the keypair signer for this wallet.
*
* @returns The KeyPairSigner
*/
async getKeyPairSigner() {
// Export the private key from CDP
const exportedPrivateKey = await __classPrivateFieldGet(this, _CdpSolanaWalletProvider_cdp, "f").solana.exportAccount({
address: __classPrivateFieldGet(this, _CdpSolanaWalletProvider_serverAccount, "f").address,
});
// Decode the base58 encoded private key to get the full 64-byte key
const fullKeyBytes = bs58_1.default.decode(exportedPrivateKey);
// Create and return the KeyPairSigner using the full key bytes
return (0, svmWalletProvider_1.createSignerFromBytes)(fullKeyBytes);
}
}
exports.CdpSolanaWalletProvider = CdpSolanaWalletProvider;
_CdpSolanaWalletProvider_connection = new WeakMap(), _CdpSolanaWalletProvider_cdp = new WeakMap(), _CdpSolanaWalletProvider_network = new WeakMap(), _CdpSolanaWalletProvider_serverAccount = new WeakMap();