UNPKG

@keyban/sdk-base

Version:

Keyban Javascript SDK provides core functionalities for the MPC wallet solution, supporting web and Node.js apps with TypeScript, custom storage, and Ethereum blockchain integration.

279 lines (276 loc) 8.88 kB
import { KeybanClientBase, KeybanAccount } from './chunk-XOGOIR6D.js'; import './chunk-5DFR5Z62.js'; import './chunk-7H2SLR6W.js'; import { RpcProvider, Account, encode, typedData, transaction, hash, stark, CallData, uint256, num } from 'starknet'; import { secp256k1 } from '@noble/curves/secp256k1.js'; // src/starknet/account.ts var StarknetAccount = class extends KeybanAccount { #account; address; publicKey; constructor(api, account, publicKey) { super(api); this.#account = account; this.address = account.address; this.publicKey = publicKey; } /** * Sign a message using Starknet typed-data format. * @param message - The message string to include in the typed data. * @returns Signature array formatted for Starknet. * @example * const sig = await account.signMessage("hello"); * console.log(sig); */ async signMessage(message) { const typedMessage = { types: { StarknetDomain: [ { name: "name", type: "shortstring" }, { name: "version", type: "shortstring" }, { name: "chainId", type: "shortstring" }, { name: "revision", type: "shortstring" } ], Message: [{ name: "message", type: "string" }] }, primaryType: "Message", domain: { name: "StarkNet Message", version: "1", chainId: "1", revision: "1" }, message: { message } }; const signedMessage = await this.#account.signMessage( typedMessage ); return signedMessage; } /** * Not implemented. * @param _to - Recipient address. * @param _value - Amount. * @param _fees - Fee details. * @throws {Error} Always throws. */ async transfer(_to, _value, _fees) { throw new Error("Unimplemented"); } /** * Not implemented. * @param _to - Recipient address. * @throws {Error} Always throws. */ async estimateTransfer(_to) { throw new Error("Unimplemented"); } /** * Not implemented. * @param _params - ERC-20 transfer parameters. * @throws {Error} Always throws. */ async transferERC20(_params) { throw new Error("Unimplemented"); } /** * Not implemented. * @param _params - ERC-20 estimation parameters. * @throws {Error} Always throws. */ async estimateERC20Transfer(_params) { throw new Error("Unimplemented"); } /** * Not implemented. * @param _params - NFT transfer parameters. * @throws {Error} Always throws. */ async transferNft(_params) { throw new Error("Unimplemented"); } /** * Not implemented. * @param _params - NFT estimation parameters. * @throws {Error} Always throws. */ async estimateNftTransfer(_params) { throw new Error("Unimplemented"); } }; var ETransactionVersion = { V3: "0x3", F3: "0x100000000000000000000000000000003" }; var ETransactionVersion3 = { V3: ETransactionVersion.V3, F3: ETransactionVersion.F3 }; var StarknetSigner = class { #api; #clientShare; #publicKey; /** * Create a StarknetSigner bound to the given API and key material. * @param api - Keyban API facade. * @param clientShare - Client share identifier for signing. * @param publicKey - Starknet-style hex public key (0x...). */ constructor(api, clientShare, publicKey) { this.#api = api; this.#clientShare = clientShare; this.#publicKey = publicKey; } /** * Get the public key used by the signer. * @returns Hex public key string prefixed with 0x. */ async getPubKey() { return this.#publicKey; } async #signHashedMessage(hashedMessage) { return this.#api.ecdsa.sign( this.#clientShare, encode.removeHexPrefix(encode.sanitizeHex(hashedMessage)) ).then(formatSignature); } /** * Sign Starknet typed data message for an account. * @param typedData - Typed data payload. * @param accountAddress - Account address that scopes the signature. * @returns Starknet signature array [rLow, rHigh, sLow, sHigh, yParity]. */ async signMessage(typedData$1, accountAddress) { const msgHash = typedData.getMessageHash(typedData$1, accountAddress); return this.#signHashedMessage(msgHash); } /** * Sign an invoke transaction consisting of one or more calls. * @param transactions - Calls to execute. * @param details - Invocation signer details (version/cairo, etc.). * @returns Starknet signature array. */ async signTransaction(transactions, details) { const compiledCalldata = transaction.getExecuteCalldata( transactions, details.cairoVersion ); let msgHash; const supportedVersions = Object.values(ETransactionVersion3); if (supportedVersions.includes(details.version)) { const det = details; msgHash = hash.calculateInvokeTransactionHash({ ...det, senderAddress: det.walletAddress, compiledCalldata, version: det.version, nonceDataAvailabilityMode: stark.intDAM(det.nonceDataAvailabilityMode), feeDataAvailabilityMode: stark.intDAM(det.feeDataAvailabilityMode) }); } else { throw Error("unsupported signTransaction version"); } return this.#signHashedMessage(msgHash); } /** * Sign a Deploy Account transaction. * @param details - Deploy signer details. * @returns Starknet signature array. */ async signDeployAccountTransaction(details) { const compiledConstructorCalldata = CallData.compile( details.constructorCalldata ); let msgHash; const supportedVersions = Object.values(ETransactionVersion3); if (supportedVersions.includes(details.version)) { const det = details; msgHash = hash.calculateDeployAccountTransactionHash({ ...det, salt: det.addressSalt, compiledConstructorCalldata, version: det.version, nonceDataAvailabilityMode: stark.intDAM(det.nonceDataAvailabilityMode), feeDataAvailabilityMode: stark.intDAM(det.feeDataAvailabilityMode) }); } else { throw Error("unsupported signDeployAccountTransaction version"); } return this.#signHashedMessage(msgHash); } /** * Sign a Declare transaction. * @param details - Declare signer details. * @returns Starknet signature array. */ async signDeclareTransaction(details) { let msgHash; const supportedVersions = Object.values(ETransactionVersion3); if (supportedVersions.includes(details.version)) { const det = details; msgHash = hash.calculateDeclareTransactionHash({ ...det, version: det.version, nonceDataAvailabilityMode: stark.intDAM(det.nonceDataAvailabilityMode), feeDataAvailabilityMode: stark.intDAM(det.feeDataAvailabilityMode) }); } else { throw Error("unsupported signDeclareTransaction version"); } return this.#signHashedMessage(msgHash); } }; function formatSignature(signatureHex) { const { r, s } = secp256k1.Signature.fromHex(signatureHex.slice(2, 130)); const yParity = Number(`0x${signatureHex.slice(130)}`); if (yParity !== 0 && yParity !== 1) { throw new Error("Invalid yParity value"); } const bigIntR = uint256.bnToUint256(r); const bigIntS = uint256.bnToUint256(s); if (yParity === void 0) throw Error("yParity is required"); return [ num.toHex(bigIntR.low), num.toHex(bigIntR.high), num.toHex(bigIntS.low), num.toHex(bigIntS.high), num.toHex(yParity) ]; } // src/starknet/client.ts var StarknetClient = class extends KeybanClientBase { #rpcProvider; constructor(config, metadataConfig) { super(config, metadataConfig); this.#rpcProvider = this.metadataConfig.then( (config2) => new RpcProvider({ nodeUrl: config2.network.rpcUrl }) ); } /** * Initialize the Starknet account for the configured network. * Provisions an ECDSA client share for Cairo-compatible signing. * @returns A ready-to-use {@link StarknetAccount}. * @example * const account = await starknetClient.initialize(); * console.log(account.address); */ async initialize() { const key = `ecdsa:${this.network}`; let clientShare = await this.clientShareProvider.get(key); if (!clientShare) { clientShare = await this.api.ecdsa.dkg(); await this.clientShareProvider.set(key, clientShare); } const [provider, publicKey, address] = await Promise.all([ this.#rpcProvider, this.api.ecdsa.publicKey(clientShare).then((ethPublicKey) => `0x${ethPublicKey.slice(4)}`), this.api.account.getAddress() ]); const signer = new StarknetSigner(this.api, clientShare, publicKey); const account = new Account(provider, address, signer); return new StarknetAccount(this.api, account, publicKey); } }; export { StarknetClient }; //# sourceMappingURL=starknet-6BK2DQFX.js.map //# sourceMappingURL=starknet-6BK2DQFX.js.map