@ledgerhq/coin-tezos
Version:
145 lines • 5.61 kB
JavaScript
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
// SPDX-License-Identifier: Apache-2.0
import { OpKind } from '@taquito/rpc';
import { UnsupportedTransactionMode } from '../types/errors';
import { createMockSigner } from '../utils';
import { estimateRevealLimits } from './estimateRevealLimits';
import { getTezosToolkit } from './tezosToolkit';
export async function craftTransaction(context, account, transaction, publicKey) {
const config = await context.config();
const { address } = account;
const transactionFees = {
fee: transaction.fee.fees ?? '0',
gas_limit: transaction.fee.gasLimit ?? '0',
storage_limit: transaction.fee.storageLimit ?? '0',
};
const tezosToolkit = getTezosToolkit(config);
// Configure signer for Taquito operations (same as in estimateFees)
if (publicKey) {
tezosToolkit.setProvider({
signer: createMockSigner(publicKey.publicKeyHash, publicKey.publicKey),
});
}
const sourceData = await tezosToolkit.rpc.getContract(address);
const counter = account.counter ?? Number(sourceData.counter);
const contents = [];
if (publicKey !== undefined) {
const feesConfig = config.fees;
const reveal = await estimateRevealLimits(tezosToolkit, address, feesConfig);
contents.push({
kind: OpKind.REVEAL,
fee: reveal.fee.toString(),
gas_limit: reveal.gasLimit.toString(),
storage_limit: reveal.storageLimit.toString(),
source: publicKey.publicKeyHash,
counter: (counter + 1 + contents.length).toString(),
public_key: publicKey.publicKey,
});
}
let type;
switch (transaction.type) {
case 'send': {
type = 'OUT';
contents.push({
kind: OpKind.TRANSACTION,
amount: transaction.amount.toString(),
destination: transaction.recipient,
source: address,
counter: (counter + 1 + contents.length).toString(),
...transactionFees,
});
break;
}
case 'send_token': {
if (!transaction.contractAddress || transaction.tokenId === undefined) {
throw new Error('FA2 transfer requires contractAddress and tokenId');
}
type = 'OUT';
const tokenContract = await tezosToolkit.contract.at(transaction.contractAddress);
const transferParams = tokenContract.methods
.transfer([
{
from_: address,
txs: [
{
to_: transaction.recipient,
token_id: transaction.tokenId,
amount: transaction.amount,
},
],
},
])
.toTransferParams({ mutez: true });
contents.push({
kind: OpKind.TRANSACTION,
source: address,
destination: transaction.contractAddress,
amount: '0',
counter: (counter + 1 + contents.length).toString(),
parameters: transferParams.parameter,
...transactionFees,
});
break;
}
case 'delegate': {
type = 'DELEGATE';
contents.push({
kind: OpKind.DELEGATION,
source: address,
counter: (counter + 1 + contents.length).toString(),
delegate: transaction.recipient,
...transactionFees,
});
break;
}
case 'undelegate': {
// we undelegate as there's no "delegate" field
// OpKind is still "DELEGATION"
type = 'UNDELEGATE';
contents.push({
kind: OpKind.DELEGATION,
source: address,
counter: (counter + 1).toString(),
...transactionFees,
});
break;
}
case 'stake':
case 'unstake':
case 'finalize_unstake': {
const typeMap = {
stake: 'STAKE',
unstake: 'UNSTAKE',
finalize_unstake: 'FINALIZE_UNSTAKE',
};
type = typeMap[transaction.type];
contents.push({
kind: OpKind.TRANSACTION,
amount: transaction.type === 'finalize_unstake' ? '0' : transaction.amount.toString(),
destination: address,
source: address,
counter: (counter + 1 + contents.length).toString(),
parameters: { entrypoint: transaction.type, value: { prim: 'Unit' } },
...transactionFees,
});
break;
}
default:
throw new UnsupportedTransactionMode('unsupported mode', { mode: transaction.type });
}
return { type, contents };
}
/**
* Return transaction in raw encoded format (i.e. hexa)
*/
export async function rawEncode(config, contents) {
const tezosToolkit = getTezosToolkit(config);
const block = await tezosToolkit.rpc.getBlock();
const forgedBytes = await tezosToolkit.rpc.forgeOperations({
branch: block.hash,
contents,
});
// 0x03 is a conventional prefix (aka a watermark) for tezos transactions
return Buffer.concat([Buffer.from('03', 'hex'), Buffer.from(forgedBytes, 'hex')]).toString('hex');
}
//# sourceMappingURL=craftTransaction.js.map