@mayaprotocol/zcash-js
Version:
Zcash JavaScript library for Maya Protocol - Build and sign Zcash transparent transactions with memo support
106 lines (105 loc) • 5.79 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const blake2b_wasm_1 = __importDefault(require("blake2b-wasm"));
const _1 = require(".");
const rpc_1 = require("./rpc");
// For ex, http://172.0.0.1:8232 for mainnet, port 18232 for regnet
const host = process.env.ZCASHD_URL;
const config = {
server: {
host: host,
user: 'mayachain',
password: 'password'
},
mainnet: false
};
const address = 'tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW';
// Helper to wait for next block
async function waitForNextBlock(ms = 3000) {
await new Promise(resolve => setTimeout(resolve, ms));
}
test('get address of pubkey', () => {
const addr = (0, _1.pkToAddr)(Buffer.from('02aa7ef4b1958837763303a675dea8f63eaf264494072f086acdbc78d0decb0d0f', 'hex'), Buffer.from(_1.testnetPrefix));
expect(addr).toBe('tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW');
});
test('tx fee', async () => {
const utxos = await (0, rpc_1.getUTXOS)('tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW', config);
const utx = await (0, _1.buildTx)(0, 'tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW', 'tmGys6dBuEGjch5LFnhdo5gpSa7jiNRWse6', 1000000, utxos, false);
expect(utx.fee).toBe(15000);
});
test('not enough funds', async () => {
const utxos = await (0, rpc_1.getUTXOS)('tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW', config);
await expect((0, _1.buildTx)(0, 'tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW', 'tmGys6dBuEGjch5LFnhdo5gpSa7jiNRWse6', 1000000000000, utxos, false, 'MEMO')).rejects.toThrow('Not enough funds');
});
test('invalid address', () => {
expect((0, _1.isValidAddr)('tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW', Buffer.from(_1.testnetPrefix))).toBeTruthy();
expect((0, _1.isValidAddr)('t1R97mnhVqcE7Yq8p7yL4E29gy8etq9V9pG', Buffer.from(_1.testnetPrefix))).toBeFalsy();
expect((0, _1.isValidAddr)('t1R97mnhVqcE7Yq8p7yL4E29gy8etq9V9pG', Buffer.from(_1.mainnetPrefix))).toBeTruthy();
expect((0, _1.isValidAddr)('tminvalidaddress', Buffer.from(_1.testnetPrefix))).toBeFalsy();
});
test('invalid t2t tx', async () => {
// "from" address is from the wrong network (mainnet)
await expect((0, rpc_1.getUTXOS)('t1R97mnhVqcE7Yq8p7yL4E29gy8etq9V9pG', config)).rejects.toThrow();
});
test('create/send t2t tx', async () => {
try {
await blake2b_wasm_1.default.ready();
const utxos = await (0, rpc_1.getUTXOS)('tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW', config);
const utx = await (0, _1.buildTx)(0, 'tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW', 'tmGys6dBuEGjch5LFnhdo5gpSa7jiNRWse6', 1000000, utxos, false);
const txb = await (0, _1.signAndFinalize)(utx.height, '458e7fb32f0f0f4b7df08b6eb1e269d59366920f5f800f907e7746b600cf516c', utx.inputs, utx.outputs);
const txid = await (0, _1.sendRawTransaction)(txb, config);
expect(typeof txid).toBe('string');
console.log(txid);
// Wait for transaction to be mined
await (0, rpc_1.waitForTransaction)(txid, config);
// Wait for next block to avoid UTXO conflicts
await waitForNextBlock();
}
catch (error) {
throw error;
}
});
test('create/send t2t tx with memo', async () => {
await blake2b_wasm_1.default.ready();
const utxos = await (0, rpc_1.getUTXOS)('tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW', config);
const utx = await (0, _1.buildTx)(0, 'tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW', 'tmGys6dBuEGjch5LFnhdo5gpSa7jiNRWse6', 1000000, utxos, false, 'swap:cacao:maya1a7gg93dgwlulsrqf6qtage985ujhpu068zllw7');
const txb = await (0, _1.signAndFinalize)(utx.height, '458e7fb32f0f0f4b7df08b6eb1e269d59366920f5f800f907e7746b600cf516c', utx.inputs, utx.outputs);
const txid = await (0, _1.sendRawTransaction)(txb, config);
expect(typeof txid).toBe('string');
console.log('TX with memo:', txid);
// Wait for transaction to be mined
await (0, rpc_1.waitForTransaction)(txid, config);
// Wait for next block to avoid UTXO conflicts
await waitForNextBlock();
});
test('send tx with memo and insufficient fee', async () => {
await blake2b_wasm_1.default.ready();
const utxos = await (0, rpc_1.getUTXOS)('tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW', config);
// Build transaction with memo
const utx = await (0, _1.buildTx)(0, 'tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW', 'tmGys6dBuEGjch5LFnhdo5gpSa7jiNRWse6', 1000000, utxos, false, 'swap:cacao:maya1a7gg93dgwlulsrqf6qtage985ujhpu068zllw7');
// Verify the correct fee is 25000 (max(2, 1+3+2) * 5000 = max(2,6) * 5000 = 30000)
expect(utx.fee).toBe(30000);
// Manually reduce the change output to simulate insufficient fee
const modifiedOutputs = [...utx.outputs];
// Find the change output (first output to our own address)
const changeIndex = modifiedOutputs.findIndex(o => o.type === 'pkh' && o.address === 'tmUzzEDRjvE3QC8RBUFD7DTi5LLL4zAEvKW');
if (changeIndex >= 0) {
const changeOutput = modifiedOutputs[changeIndex];
if (changeOutput.type === 'pkh') {
// Increase change by 25000 sats (reducing fee from 30000 to 5000)
// This should be below the minimum relay fee
modifiedOutputs[changeIndex] = {
type: 'pkh',
address: changeOutput.address,
amount: changeOutput.amount + 25000
};
}
}
// Try to sign and send with insufficient fee
const txb = await (0, _1.signAndFinalize)(utx.height, '458e7fb32f0f0f4b7df08b6eb1e269d59366920f5f800f907e7746b600cf516c', utx.inputs, modifiedOutputs);
// This should fail due to insufficient fee
await expect((0, _1.sendRawTransaction)(txb, config)).rejects.toThrow('66: tx unpaid action limit exceeded');
});