micro-sol-signer
Version:
Create, sign & decode Solana transactions with minimum deps
679 lines • 28 kB
JavaScript
"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