Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions example/multisig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
const { v4 } = require('uuid');
const { MixinApi, buildMultiSigsTransaction, sleep, encodeScript } = require('..');
const keystore = require('../keystore.json');

keystore.user_id = keystore.client_id;
const client = MixinApi({
requestConfig: {
responseCallback: err => {
console.log(err);
},
},
keystore,
});

const readOutput = async (hash, members, threshold, offset = '') => {
let new_offset = offset;
const outputs = await client.multisig.outputs({
members,
threshold,
offset,
limit: 10,
});

// eslint-disable-next-line no-restricted-syntax
for (const output of outputs) {
new_offset = output.updated_at;
if (output.transaction_hash === hash) return output;
}

await sleep(1000 * 5);
return readOutput(hash, members, threshold, new_offset);
};

const main = async () => {
const bot = await client.user.profile();
const asset_id = '965e5c6e-434c-3fa9-b780-c50f43cd955c';
const amount = '0.0001';
const members = [bot.app.creator_id, keystore.user_id];
const threshold = 1;

// 1. send to multisig account
// should have balance in your bot
const sendTxReceipt = await client.transfer.toAddress(keystore.pin, {
asset_id,
amount,
trace_id: v4(),
memo: 'send to multisig',
opponent_multisig: {
threshold,
receivers: members,
},
});
console.log('send to multi-signature account');
console.log('transaction hash:', sendTxReceipt.transaction_hash);

// 2. wait tx complete
console.log('read transaction output...');
const utxo = await readOutput(sendTxReceipt.transaction_hash, members, threshold, '');
console.log(utxo);

// 3. refund
console.log('refund to bot:');
const asset = await client.asset.fetch(asset_id);
const receivers = await client.transfer.outputs([
{
receivers: [keystore.user_id],
index: 0,
},
]);
console.log('generate raw transaction');
const raw = buildMultiSigsTransaction({
version: 2,
asset: asset.mixin_id,
inputs: [
{
hash: utxo.transaction_hash,
index: utxo.output_index,
},
],
outputs: [
{
amount,
mask: receivers[0].mask,
keys: receivers[0].keys,
script: encodeScript(threshold),
},
],
extra: 'refund',
});

// Generate a multi-signature
console.log('generate a multi-signature request...');
const multisig = await client.multisig.create('sign', raw);

// Sign a multi-signature
console.log('sign...');
const signed = await client.multisig.sign(keystore.pin, multisig.request_id);
console.log(signed);

// Send signed tx to mainnet
console.log('send to mainnet...');
const res = await client.external.proxy({
method: 'sendrawtransaction',
params: [signed.raw_transaction],
});
console.log(res);
};

main();
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@
"@ethersproject/abi": "^5.6.3",
"@ethersproject/providers": "^5.6.8",
"@types/axios": "^0.14.0",
"@types/bn.js": "^5.1.0",
"@types/jsonwebtoken": "^8.5.8",
"@types/node-forge": "^1.0.2",
"@types/serialize-javascript": "^5.0.2",
"@types/uuid": "^8.3.4",
Expand Down
7 changes: 7 additions & 0 deletions src/client/external.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ export const ExternalKeystoreClient = (axiosInstance: AxiosInstance) => ({
*/
exchangeRates: (): Promise<ExchangeRateResponse[]> => axiosInstance.get<unknown, ExchangeRateResponse[]>('/external/fiats'),

/**
* Submit a raw transaction to a random mainnet node
* {
* method: 'sendrawtransaction',
* params: array of transaction hash
* }
* */
proxy: (params: ProxyRequest): Promise<any> => axiosInstance.post<unknown, any>('/external/proxy', params),
});

Expand Down
6 changes: 2 additions & 4 deletions src/client/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ import {
TransferMessageRequest,
RecallMessageRequest,
} from './types/message';
import { base64url } from '../mixin/sign';
import { uniqueConversationID } from './utils/uniq';
import { buildClient } from './utils/client';
import { uniqueConversationID, base64RawURLEncode, buildClient } from './utils';

/**
* Methods to send messages
Expand All @@ -41,7 +39,7 @@ export const MessageKeystoreClient = (axiosInstance: AxiosInstance, keystore: Ke
recipient_id: recipientID,
conversation_id: uniqueConversationID(keystore!.user_id, recipientID),
message_id: uuid(),
data: base64url(Buffer.from(data)),
data: base64RawURLEncode(Buffer.from(data)),
};
await send(messageRequest);
return messageRequest;
Expand Down
12 changes: 12 additions & 0 deletions src/client/types/multisig.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Input, Output } from '../../mvm';

export type UTXOState = 'unspent' | 'signed' | 'spent';

export type MultisigInitAction = 'sign' | 'unlock';
Expand Down Expand Up @@ -55,3 +57,13 @@ export interface MultisigRequestResponse {
updated_at: string;
code_id: string;
}

export interface MultisigTransaction {
/** 2 */
version: number;
/** mixin_id of asset */
asset: string;
inputs: Input[];
outputs: Output[];
extra: string;
}
2 changes: 1 addition & 1 deletion src/client/types/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface RawTransactionRequest {
export interface GhostInputRequest {
receivers: string[];
index: number;
hint: string;
hint?: string;
}

export interface GhostKeysResponse {
Expand Down
1 change: 1 addition & 0 deletions src/client/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './auth';
export * from './base64';
export * from './client';
export * from './multisigs';
export * from './nfo';
export * from './pin';
export * from './sleep';
Expand Down
54 changes: 54 additions & 0 deletions src/client/utils/multisigs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { MultisigTransaction } from '../types';
import { Encoder, magic } from '../../mvm';

export const TxVersion = 0x02;

export const encodeScript = (threshold: number) => {
let s = threshold.toString(16);
if (s.length === 1) s = `0${s}`;
if (s.length > 2) throw new Error(`INVALID THRESHOLD ${threshold}`);

return `fffe${s}`;
};

export const encodeTx = (tx: MultisigTransaction) => {
const enc = new Encoder(Buffer.from([]));

enc.write(magic);
enc.write(Buffer.from([0x00, tx.version]));
enc.write(Buffer.from(tx.asset, 'hex'));

enc.writeInt(tx.inputs.length);
tx.inputs.forEach(input => {
enc.encodeInput(input);
});

enc.writeInt(tx.outputs.length);
tx.outputs.forEach(output => {
enc.encodeOutput(output);
});

const extra = Buffer.from(tx.extra);
enc.writeInt(extra.byteLength);
enc.write(extra);

enc.writeInt(0);
enc.write(Buffer.from([]));

return enc.buf.toString('hex');
};

/**
* Generate raw for multi-signature transaction.
* The total amount of input utxos should be equal to the total amount of output utxos.
* */
export const buildMultiSigsTransaction = (transaction: MultisigTransaction) => {
if (transaction.version !== TxVersion) throw new Error('Invalid Version!');

const tx = {
...transaction,
outputs: transaction.outputs.filter(output => !!output.mask),
extra: Buffer.from(transaction.extra).toString('hex'),
};
return encodeTx(tx);
};
2 changes: 1 addition & 1 deletion src/client/utils/nfo.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { parse as UUIDParse, stringify } from 'uuid';
import { NFOMemo } from '../types';
import { newHash } from './uniq';
import { base64RawURLEncode } from './base64';
import { newHash } from './uniq';
import { Encoder, Decoder } from '../../mvm';

const Prefix = 'NFO';
Expand Down
1 change: 0 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export * from './client';
export * from './mvm';
export * from './webview';
export * from './mixin/dump_transacion';
export * from './constant';
43 changes: 0 additions & 43 deletions src/mixin/dump_transacion.ts

This file was deleted.

Loading