@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
JavaScript
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