UNPKG

micro-sol-signer

Version:

Create, sign & decode Solana transactions with minimum deps

679 lines 28 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.swapProgram = exports.TokenAccount = exports.COMMON_TOKENS = exports.associatedToken = exports.ASSOCIATED_TOKEN_PROGRAM = exports.NonceAccount = exports.token = exports.TOKEN_PROGRAM = exports.sys = exports.SYS_PROGRAM = exports.SYS_RENT = exports.SYS_RECENT_BLOCKHASHES = exports.Transaction = exports.TransactionRaw = exports.Message = exports.shortVec = exports.Decimal = exports.PRECISION = void 0; exports.validateAddress = validateAddress; exports.defineProgram = defineProgram; exports.parseInstruction = parseInstruction; exports.isOnCurve = isOnCurve; exports.programAddress = programAddress; exports.tokenAddress = tokenAddress; exports.tokenFromSymbol = tokenFromSymbol; exports.verifyTx = verifyTx; exports.getPublicKey = getPublicKey; exports.getAddress = getAddress; exports.getAddressFromPublicKey = getAddressFromPublicKey; exports.formatPrivate = formatPrivate; exports.createTxComplex = createTxComplex; exports.createTx = createTx; exports.signTx = signTx; const ed25519_1 = require("@noble/curves/ed25519"); const base_1 = require("@scure/base"); const sha256_1 = require("@noble/hashes/sha256"); const P = require("micro-packed"); exports.PRECISION = 9; exports.Decimal = P.coders.decimal(exports.PRECISION); // first bit -- terminator (1 -- continue, 0 -- last) exports.shortVec = P.wrap({ encodeStream: (w, value) => { if (!value) return w.byte(0); for (; value; value >>= 7) { w.bits(value > 0x7f ? 1 : 0, 1); w.bits(value & 0x7f, 7); } }, decodeStream: (r) => { let len = 0; for (let pos = 0; !r.isEnd(); pos++) { const last = !r.bits(1); len |= r.bits(7) << (pos * 7); if (last) break; } return len; }, }); const rustString = P.string(P.padRight(8, P.U32LE, undefined)); const b58 = () => { const inner = P.bytes(32); return P.wrap({ size: inner.size, encodeStream: (w, value) => inner.encodeStream(w, base_1.base58.decode(value)), decodeStream: (r) => base_1.base58.encode(inner.decodeStream(r)), }); }; const pubKey = b58(); exports.Message = P.struct({ requiredSignatures: P.U8, readSigned: P.U8, readUnsigned: P.U8, keys: P.array(exports.shortVec, pubKey), blockhash: pubKey, instructions: P.array(exports.shortVec, P.struct({ programIdx: P.U8, keys: P.array(exports.shortVec, P.U8), data: P.bytes(exports.shortVec) })), }); function validateAddress(address) { const pubkey = base_1.base58.decode(address); if (pubkey.length !== 32) throw new Error('Invalid Solana address'); } const keyParams = (i, req, signed, unsigned, total) => ({ sign: i < req ? true : false, write: i < req - signed || (i >= req && i < total - unsigned) ? true : false, }); exports.TransactionRaw = P.struct({ signatures: P.array(exports.shortVec, P.bytes(64)), msg: exports.Message, }); // Keys position is implementation specific, Transaction.encode(Transaction.decode(tx)) not neccessary equals to tx, // since there is information loss for readability purposes. Use TransactionRaw in case you need exactly same encoding exports.Transaction = P.wrap({ encodeStream: (w, value) => { const { msg, signatures } = value; const accounts = {}; const add = (address, sign, write) => { let acc = accounts[address] || (accounts[address] = { sign: false, write: false }); acc.write || (acc.write = write); acc.sign || (acc.sign = sign); }; add(msg.feePayer, true, true); for (let i of msg.instructions) for (let k of i.keys) add(k.address, k.sign, k.write); // Same loop as above, but cannot be merged since it will change implementation specific key positions inside transaction. // This doesn't invalidate transaction, but can be used for fingerprinting. for (let i of msg.instructions) add(i.program, false, false); const _keys = Object.keys(accounts); // [feePayer, ...sign+write, ...sign+read, ...nosign+write, ...nosign+read] const keys = [ msg.feePayer, ..._keys.filter((i) => accounts[i].sign && accounts[i].write && i !== msg.feePayer), ..._keys.filter((i) => accounts[i].sign && !accounts[i].write), ..._keys.filter((i) => !accounts[i].sign && accounts[i].write), ..._keys.filter((i) => !accounts[i].sign && !accounts[i].write), ]; let requiredSignatures = 0; let readSigned = 0; let readUnsigned = 0; for (let k of keys) { if (accounts[k].sign) requiredSignatures++; if (accounts[k].write) continue; if (accounts[k].sign) readSigned++; else readUnsigned++; } exports.TransactionRaw.encodeStream(w, { signatures: keys .filter((i) => accounts[i].sign) .map((i) => signatures[i] || new Uint8Array(64)), msg: { requiredSignatures, readSigned, readUnsigned, keys, // indexOf potentially can be slow, but for most tx there will be ~3-5 keys, so doesn't matter much instructions: msg.instructions.map((i) => ({ programIdx: keys.indexOf(i.program), keys: i.keys.map((j) => keys.indexOf(j.address)), data: i.data, })), blockhash: msg.blockhash, }, }); }, decodeStream: (r) => { const { signatures, msg } = exports.TransactionRaw.decodeStream(r); if (signatures.length !== msg.requiredSignatures) throw new Error('SOL.tx: wrong signatures length'); if (msg.keys.length < signatures.length) throw new Error('SOL.tx: invalid keys length'); const sigs = {}; for (let i = 0; i < signatures.length; i++) sigs[msg.keys[i]] = signatures[i]; let accounts = []; for (let i = 0; i < msg.keys.length; i++) { accounts.push({ address: msg.keys[i], ...keyParams(i, msg.requiredSignatures, msg.readSigned, msg.readUnsigned, msg.keys.length), }); } if (!accounts.length) throw new Error('SOL.tx: empty accounts array'); return { msg: { feePayer: accounts[0].address, blockhash: msg.blockhash, instructions: msg.instructions.map((i) => ({ program: accounts[i.programIdx].address, keys: i.keys.map((j) => accounts[j]), data: i.data, })), }, signatures: sigs, }; }, }); const registry = {}; // Basic ABI thing. There is IDL which is kinda ABI, but not official and system accounts doesn't have offical types for it. // Later we can add support to conversion IDL -> defineProgram function defineProgram(address, tagType, methods) { if (registry[address]) throw new Error('SOL: program for this address already defined'); const variants = P.map(tagType, Object.keys(methods).reduce((acc, k, i) => ({ ...acc, [k]: i }), {})); const coders = Object.keys(methods).reduce((acc, k) => ({ ...acc, [k]: methods[k].coder }), {}); const mainCoder = P.tag(variants, coders); registry[address] = (instr, tl) => { if (instr.program !== address) throw new Error('SOL.parseInstruction: Wrong instruction program address'); const { TAG, data } = mainCoder.decode(instr.data); // Should be close to node parser (https://github.com/solana-labs/solana/tree/master/transaction-status/src) const res = { type: TAG, info: data }; const keys = Object.keys(methods[TAG].keys); if (keys.length !== instr.keys.length) throw new Error('SOL.parseInstruction: Keys length mismatch'); for (let i = 0; i < keys.length; i++) { const key = keys[i]; if (methods[TAG].keys[key].address) { if (methods[TAG].keys[key].address !== instr.keys[i].address) { throw new Error(`SOL.parseInstruction(${address}/${TAG}): Invalid constant address for key exp=${methods[TAG].keys[key].address} got=${instr.keys[i].address}`); } continue; } res.info[keys[i]] = instr.keys[i].address; } if (methods[TAG].hint) res.hint = methods[TAG].hint(data, tl); return res; }; const program = {}; for (const m in methods) { program[m] = (data) => ({ program: address, data: mainCoder.encode({ TAG: m, data }), keys: Object.keys(methods[m].keys).map((name) => { let { sign, write, address } = methods[m].keys[name]; address || (address = data[name]); validateAddress(address); return { address, sign, write }; }), }); } return program; } function parseInstruction(instr, tl) { if (!registry[instr.program]) return; return registry[instr.program](instr, tl); } exports.SYS_RECENT_BLOCKHASHES = 'SysvarRecentB1ockHashes11111111111111111111'; exports.SYS_RENT = 'SysvarRent111111111111111111111111111111111'; exports.SYS_PROGRAM = '11111111111111111111111111111111'; exports.sys = defineProgram(exports.SYS_PROGRAM, P.U32LE, { createAccount: { coder: P.struct({ lamports: P.U64LE, space: P.U64LE, owner: pubKey }), keys: { source: { sign: true, write: true }, newAccount: { sign: true, write: true }, }, hint: (o) => `Create new account=${o.newAccount} with balance of ${exports.Decimal.encode(o.lamports)} and owner program ${o.owner}, using funding account ${o.source}`, }, assign: { coder: P.struct({ owner: pubKey }), keys: { account: { sign: true, write: true } }, hint: (o) => `Assign account=${o.account} to owner program=${o.owner}`, }, transfer: { coder: P.struct({ lamports: P.U64LE }), keys: { source: { sign: true, write: true }, destination: { sign: false, write: true } }, hint: (o) => `Transfer ${exports.Decimal.encode(o.lamports)} SOL from ${o.source} to ${o.destination}`, }, createAccountWithSeed: { coder: P.struct({ base: pubKey, seed: rustString, lamports: P.U64LE, space: P.U64LE, owner: pubKey, }), keys: { source: { sign: true, write: true }, newAccount: { sign: false, write: true }, base: { sign: true, write: false }, }, }, advanceNonce: { coder: P.struct({}), keys: { nonceAccount: { sign: false, write: true }, _recent_bh: { address: exports.SYS_RECENT_BLOCKHASHES, sign: false, write: false }, nonceAuthority: { sign: true, write: false }, }, hint: (o) => `Consume nonce in nonce account=${o.nonceAccount} (owner: ${o.nonceAuthority})`, }, withdrawFromNonce: { coder: P.struct({ lamports: P.U64LE }), keys: { nonceAccount: { sign: false, write: true }, destination: { sign: false, write: true }, _recent_bh: { address: exports.SYS_RECENT_BLOCKHASHES, sign: false, write: false }, _rent: { address: exports.SYS_RENT, sign: false, write: false }, nonceAuthority: { sign: true, write: false }, }, hint: (o) => `Withdraw ${exports.Decimal.encode(o.lamports)} SOL from nonce account=${o.nonceAccount} (owner: ${o.nonceAuthority}) to ${o.destination}`, }, initializeNonce: { coder: P.struct({ nonceAuthority: pubKey }), keys: { nonceAccount: { sign: false, write: true }, _recent_bh: { address: exports.SYS_RECENT_BLOCKHASHES, sign: false, write: false }, _rent: { address: exports.SYS_RENT, sign: false, write: false }, }, }, authorizeNonce: { coder: P.struct({ newAuthorized: pubKey }), keys: { nonceAccount: { sign: false, write: true }, nonceAuthority: { sign: true, write: false }, }, hint: (o) => `Change owner of nonce account=${o.nonceAccount} from ${o.nonceAuthority} to ${o.newAuthorized}`, }, allocate: { coder: P.struct({ space: P.U64LE }), keys: { account: { sign: true, write: true }, }, }, allocateWithSeed: { coder: P.struct({ base: pubKey, seed: rustString, space: P.U64LE, owner: pubKey, }), keys: { account: { sign: false, write: true }, base: { sign: true, write: false }, }, }, assignWithSeed: { coder: P.struct({ base: pubKey, seed: rustString, owner: pubKey, }), keys: { account: { sign: false, write: true }, base: { sign: true, write: false }, }, }, transferWithSeed: { coder: P.struct({ lamports: P.U64LE, sourceSeed: rustString, sourceOwner: pubKey, }), keys: { source: { sign: false, write: true }, sourceBase: { sign: true, write: false }, destination: { sign: false, write: true }, }, }, }); // Type tests const assertType = (_value) => { }; assertType(exports.sys.transfer); assertType(exports.sys.advanceNonce); const authorityType = P.map(P.U8, { MintTokens: 0, FreezeAccount: 1, AccountOwner: 2, CloseAccount: 3, }); const tokenName = (address, tl) => tl[address]?.symbol || address; exports.TOKEN_PROGRAM = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'; exports.token = defineProgram(exports.TOKEN_PROGRAM, P.U8, { initializeMint: { coder: P.struct({ decimals: P.U8, mintAuthority: pubKey, freezeAuthority: P.optional(P.bool, pubKey, '11111111111111111111111111111111'), }), keys: { mint: { sign: false, write: true }, _rent: { address: exports.SYS_RENT, sign: false, write: false }, }, }, initializeAccount: { coder: P.struct({}), keys: { account: { sign: false, write: true }, mint: { sign: false, write: false }, owner: { sign: false, write: false }, _rent: { address: exports.SYS_RENT, sign: false, write: false }, }, hint: (o, tl) => `Initialize token account=${o.account} with owner=${o.owner} token=${tokenName(o.mint, tl)}`, }, // TODO: multisig support? initializeMultisig: { coder: P.struct({ m: P.U8 }), keys: { account: { sign: false, write: true }, _rent: { address: exports.SYS_RENT, sign: false, write: false }, }, hint: (o, _) => `Initialize multi-sig token account=${o.account} with signatures=${o.m}`, }, transfer: { coder: P.struct({ amount: P.U64LE }), keys: { source: { sign: false, write: true }, destination: { sign: false, write: true }, owner: { sign: true, write: false }, }, hint: (o, _) => `Transfer ${o.amount} from token account=${o.source} of owner=${o.owner} to ${o.destination}`, }, approve: { coder: P.struct({ amount: P.U64LE }), keys: { account: { sign: false, write: true }, delegate: { sign: false, write: false }, owner: { sign: true, write: false }, }, hint: (o, _) => `Approve authority of delegate=${o.delegate} over tokens on account=${o.account} on behalf of owner=${o.owner}`, }, revoke: { coder: P.struct({}), keys: { account: { sign: false, write: true }, owner: { sign: true, write: false }, }, hint: (o, _) => `Revoke delegate's authority over tokens on account=${o.account} on behalf of owner=${o.owner}`, }, setAuthority: { coder: P.struct({ authorityType, newAuthority: P.optional(P.bool, pubKey, '11111111111111111111111111111111'), }), keys: { account: { sign: false, write: true }, currentAuthority: { sign: true, write: false }, }, hint: (o, _) => `Sets a new authority=${o.newAuthority} of a mint or account=${o.account}. Current authority=${o.currentAuthority}. Authority Type: ${o.authorityType}`, }, mintTo: { coder: P.struct({ amount: P.U64LE }), keys: { mint: { sign: false, write: true }, dest: { sign: false, write: true }, authority: { sign: true, write: false }, }, }, burn: { coder: P.struct({ amount: P.U64LE }), keys: { account: { sign: false, write: true }, mint: { sign: false, write: true }, owner: { sign: true, write: false }, }, hint: (o, _) => `Burn ${o.amount} tokens from account=${o.account} of owner=${o.owner} mint=${o.mint}`, }, closeAccount: { coder: P.struct({}), keys: { account: { sign: false, write: true }, dest: { sign: false, write: true }, owner: { sign: true, write: false }, }, hint: (o, _) => `Close token account=${o.account} of owner=${o.owner}, transferring all its SOL to destionation account=${o.dest}`, }, freezeAccount: { coder: P.struct({}), keys: { account: { sign: false, write: true }, mint: { sign: false, write: true }, authority: { sign: true, write: false }, }, hint: (o, _) => `Freeze token account=${o.account} of mint=${o.mint} using freeze_authority=${o.authority}`, }, thawAccount: { coder: P.struct({}), keys: { account: { sign: false, write: true }, mint: { sign: false, write: false }, authority: { sign: true, write: false }, }, hint: (o, _) => `Thaw a frozne token account=${o.account} of mint=${o.mint} using freeze_authority=${o.authority}`, }, transferChecked: { coder: P.struct({ amount: P.U64LE, decimals: P.U8 }), keys: { source: { sign: false, write: true }, mint: { sign: false, write: false }, destination: { sign: false, write: true }, owner: { sign: true, write: false }, }, hint: (o, tl) => `Transfer ${P.coders.decimal(o.decimals).encode(o.amount)} ${tokenName(o.mint, tl)} from token account=${o.source} of owner=${o.owner} to ${o.destination}`, }, approveChecked: { coder: P.struct({ amount: P.U64LE, decimals: P.U8 }), keys: { source: { sign: false, write: true }, mint: { sign: false, write: false }, delegate: { sign: false, write: false }, owner: { sign: true, write: false }, }, hint: (o, tl) => `Approve delgate=${o.delegate} authority on behalf account=${o.source} owner=${o.owner} over ${P.coders.decimal(o.decimals).encode(o.amount)} ${tokenName(o.mint, tl)}`, }, mintToChecked: { coder: P.struct({ amount: P.U64LE, decimals: P.U8 }), keys: { mint: { sign: false, write: true }, dest: { sign: false, write: true }, authority: { sign: true, write: false }, }, hint: (o, tl) => `Mint new tokens (${P.coders.decimal(o.decimals).encode(o.amount)} ${tokenName(o.mint, tl)}) to account=${o.dest} using authority=${o.authority}`, }, burnChecked: { coder: P.struct({ amount: P.U64LE, decimals: P.U8 }), keys: { mint: { sign: false, write: true }, account: { sign: false, write: true }, owner: { sign: true, write: false }, }, hint: (o, tl) => `Burn tokens (${P.coders.decimal(o.decimals).encode(o.amount)} ${tokenName(o.mint, tl)}) on account=${o.account} of owner=${o.owner}`, }, initializeAccount2: { coder: P.struct({ owner: pubKey }), keys: { account: { sign: false, write: true }, mint: { sign: false, write: false }, _rent: { address: exports.SYS_RENT, sign: false, write: false }, }, hint: (o, tl) => `Initialize token account=${o.account} with owner=${o.owner} token=${tokenName(o.mint, tl)}`, }, syncNative: { coder: P.struct({}), keys: { nativeAccount: { sign: false, write: true } }, hint: (o) => `Sync SOL balance for wrapped account ${o.nativeAccount}`, }, }); exports.NonceAccount = P.struct({ version: P.U32LE, state: P.U32LE, authority: pubKey, nonce: pubKey, lamportPerSignature: P.U64LE, }); function mod(a, b = ed25519_1.ed25519.CURVE.Fp.ORDER) { const res = a % b; return res >= 0n ? res : b + res; } function isOnCurve(bytes) { if (typeof bytes === 'string') bytes = base_1.base58.decode(bytes); try { // noble-ed25519 checks that publicKey is < P, but dalek (ed25519-dalek.CompressedEdwardsY) is not, so we do modulo here. // first bit in last byte is x oddity flag const last = bytes[31]; const normedLast = last & ~0x80; const normed = Uint8Array.from(Array.from(bytes.slice(0, 31)).concat(normedLast)); const modBytes = P.U256LE.encode(mod(P.U256LE.decode(normed))); if ((last & 0x80) !== 0) modBytes[31] |= 0x80; ed25519_1.ed25519.ExtendedPoint.fromHex(modBytes); return true; } catch (e) { return false; } } function programAddress(program, ...seeds) { let seed = P.utils.concatBytes(...seeds); const noncePos = seed.length; seed = P.utils.concatBytes(seed, new Uint8Array([0]), base_1.base58.decode(program), base_1.utf8.decode('ProgramDerivedAddress')); for (let i = 255; i >= 0; i--) { seed[noncePos] = i; const hash = (0, sha256_1.sha256)(seed); if (isOnCurve(hash)) continue; return base_1.base58.encode(hash); } throw new Error('SOL.programAddress: nonce exhausted, cannot find program address'); } exports.ASSOCIATED_TOKEN_PROGRAM = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'; exports.associatedToken = defineProgram(exports.ASSOCIATED_TOKEN_PROGRAM, P.constant(0), { create: { coder: P.struct({}), keys: { source: { sign: true, write: true }, account: { sign: false, write: true }, wallet: { sign: false, write: false }, mint: { sign: false, write: false }, _sys: { address: exports.SYS_PROGRAM, sign: false, write: false }, _token: { address: exports.TOKEN_PROGRAM, sign: false, write: false }, _rent: { address: exports.SYS_RENT, sign: false, write: false }, }, hint: (o, tl) => `Initialize associated token account=${o.account} with owner=${o.wallet} for token=${tokenName(o.mint, tl)}, payed by ${o.source}`, }, }); function tokenAddress(mint, owner, allowOffCurveOwner = false) { if (!allowOffCurveOwner && !isOnCurve(owner)) throw new Error('Owner is off curve (cannot sign)'); return programAddress(exports.ASSOCIATED_TOKEN_PROGRAM, ...[owner, exports.TOKEN_PROGRAM, mint].map((i) => base_1.base58.decode(i))); } // https://raw.githubusercontent.com/solana-labs/token-list/main/src/tokens/solana.tokenlist.json exports.COMMON_TOKENS = { So11111111111111111111111111111111111111112: { decimals: 9, symbol: 'SOL' }, // Wrapped SOL Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB: { decimals: 6, symbol: 'USDT', price: 1 }, EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v: { decimals: 6, symbol: 'USDC', price: 1 }, }; function tokenFromSymbol(symbol, tokens = exports.COMMON_TOKENS) { for (let c in tokens) if (tokens[c].symbol === symbol) return { ...tokens[c], contract: c }; return; } // [1, 0, 0, 0] -> true // [0, 0, 0, 0] -> false const U32LEBOOL = P.padRight(4, P.bool, () => 0); exports.TokenAccount = P.struct({ mint: pubKey, owner: pubKey, amount: P.U64LE, delegate: P.optional(U32LEBOOL, pubKey, '11111111111111111111111111111111'), state: P.map(P.U8, { uninitialized: 0, initialized: 1, frozen: 2, }), isNative: P.optional(U32LEBOOL, P.U64LE, 0n), delegateAmount: P.U64LE, closeAuthority: P.optional(U32LEBOOL, pubKey, '11111111111111111111111111111111'), }); exports.swapProgram = 'SwaPpA9LAaLfeLi3a68M4DjnLqgtticKg6CnyNwgAC8'; function verifyTx(tx) { if (typeof tx === 'string') tx = base_1.base64.decode(tx); if (tx.length > 1280 - 40 - 8) throw new Error('sol: transaction too big'); const parsed = exports.Transaction.decode(tx); const raw = exports.TransactionRaw.decode(tx); const msg = exports.Message.encode(exports.TransactionRaw.decode(tx).msg); for (let i = 0; i < raw.msg.requiredSignatures; i++) { const address = raw.msg.keys[i]; const pubKey = base_1.base58.decode(address); const sig = parsed.signatures[address]; if (!ed25519_1.ed25519.verify(sig, msg, pubKey)) throw new Error(`sol: invalid signature sig=${sig} msg=${msg}`); } } function getPublicKey(privateKey) { return ed25519_1.ed25519.getPublicKey(privateKey); } function getAddress(privateKey) { const publicKey = getPublicKey(privateKey); return base_1.base58.encode(publicKey); } function getAddressFromPublicKey(publicKey) { return base_1.base58.encode(publicKey); } function formatPrivate(privateKey, format = 'base58') { const publicKey = getPublicKey(privateKey); const fullKey = P.utils.concatBytes(privateKey, publicKey); switch (format) { case 'base58': { return base_1.base58.encode(fullKey); } case 'hex': { return base_1.hex.encode(fullKey); } case 'array': { return Array.from(fullKey); } default: { throw new Error('sol: unsupported format'); } } } function createTxComplex(address, instructions, blockhash) { if (!instructions.length) throw new Error('SOLPublic: empty instructions array'); return base_1.base64.encode(exports.Transaction.encode({ msg: { feePayer: address, blockhash, instructions }, signatures: {}, })); } function createTx(from, to, amount, _fee, blockhash) { const amountNum = exports.Decimal.decode(amount); return createTxComplex(from, [exports.sys.transfer({ source: from, destination: to, lamports: amountNum })], blockhash); } function signTx(privateKey, data) { if (typeof data === 'string') data = base_1.base64.decode(data); const address = getAddress(privateKey); const raw = exports.TransactionRaw.decode(data); const reqSignatures = raw.msg.keys.slice(0, raw.msg.requiredSignatures); if (!reqSignatures.filter((i) => i == address).length) throw new Error(`SOLPrivate: tx doesn't require signature for address=${address}`); const sig = ed25519_1.ed25519.sign(exports.Message.encode(raw.msg), privateKey); for (let i = 0; i < reqSignatures.length; i++) if (reqSignatures[i] === address) raw.signatures[i] = sig; // Base58 encoding for tx is deprecated const tx = base_1.base64.encode(exports.TransactionRaw.encode(raw)); // first signature is txHash return [base_1.base58.encode(sig), tx]; } //# sourceMappingURL=index.js.map