Commit 4637b153 authored by Amaury Martiny's avatar Amaury Martiny
Browse files

refactor: Nicer interface for users

parent a616fe15
import metadataRpc from '@polkadot/metadata/Metadata/v9/static';
import { balanceTransfer } from './balanceTransfer';
import { TEST_TX_INFO } from './util/testUtil';
describe('balanceTransfer', () => {
it('should work', () => {
const call = balanceTransfer(
metadataRpc,
'Fy2rsYCoowQBtuFXqLE65ehAY9T6KWcGiNCQAyPDCkfpm4s',
12
);
const unsigned = balanceTransfer(TEST_TX_INFO);
expect(call).toBe(
(['address', 'blockHash', 'genesisHash'] as const).forEach(key =>
expect(unsigned[key]).toBe(TEST_TX_INFO[key])
);
expect(unsigned.blockNumber).toBe('0x0041a58e');
expect(unsigned.era).toBe('0xeb58');
expect(unsigned.method).toBe(
'0x0600ff96074594cccf1cd185fa8a72ceaeefd86648f8d45514f3ce33c31bdd07e4655d30'
);
expect(unsigned.nonce).toBe('0x00000002');
expect(unsigned.specVersion).toBe('0x000003fb');
expect(unsigned.tip).toBe('0x00000000000000000000000000000000');
expect(unsigned.version).toBe(4);
});
});
import Metadata from '@polkadot/metadata';
import { TypeRegistry } from '@polkadot/types';
import { createType, TypeRegistry } from '@polkadot/types';
import { SignerPayloadJSON } from '@polkadot/types/types';
/**
* JSON format for an unsigned transaction
*/
export type UnsignedTransaction = SignerPayloadJSON;
export interface TxInfo {
/**
* The ss-58 encoded address
*/
address: string;
/**
* The amount to send
*/
amount: number;
/**
* The checkpoint hash of the block, in hex
*/
blockHash: string;
/**
* The checkpoint block number (u32), in hex
*/
blockNumber: number;
/**
* The genesis hash of the chain, in hex
*/
genesisHash: string;
/**
* The SCALE-encoded metadata, as a hex string. Can be retrieved via the RPC
* call `state_getMetadata`
*/
metadataRpc: string;
/**
* The nonce for this transaction,
*/
nonce: number;
/**
* The current spec version for the runtime
*/
specVersion: number;
/**
* The tip for this transaction, in hex
*/
tip: number;
/**
* The recipient address, ss-58 encoded
*/
to: string;
}
// Calculting Era. The default here allows for 240min mortal eras.
const BLOCKTIME = 6;
const ONE_MINUTE = 60 / BLOCKTIME;
const DEFAULT_MORTAL_LENGTH = 240 * ONE_MINUTE;
/**
* Construct a balance transfer transaction offline
*
* @param metadataRpc - The SCALE-encoded metadata, as a hex string. Can be
* retrieved via the RPC all `state_getMetadata`
* @param to - The recipient of the transfer
* @param amount - The amount to send
* @param info - Information required to construct the transaction
* @param amount -
*/
export function balanceTransfer(
metadataRpc: string,
to: string,
amount: number
): string {
export function balanceTransfer(info: TxInfo): UnsignedTransaction {
const registry = new TypeRegistry();
const metadata = new Metadata(registry, metadataRpc);
const metadata = new Metadata(registry, info.metadataRpc);
const method = metadata.tx.balances.transfer(info.to, info.amount).toHex();
return metadata.tx.balances.transfer(to, amount).toHex();
return {
address: info.address,
blockHash: info.blockHash,
blockNumber: createType(registry, 'BlockNumber', info.blockNumber).toHex(),
era: createType(registry, 'ExtrinsicEra', {
current: info.blockNumber,
period: DEFAULT_MORTAL_LENGTH
}).toHex(),
genesisHash: info.genesisHash,
method,
nonce: createType(registry, 'Compact<Index>', info.nonce).toHex(),
specVersion: createType(registry, 'u32', info.specVersion).toHex(),
tip: createType(registry, 'Compact<Balance>', info.tip).toHex(),
version: 4
};
}
import { Keyring } from '@polkadot/api';
import { createType, TypeRegistry } from '@polkadot/types';
import { cryptoWaitReady } from '@polkadot/util-crypto';
import { createSignedTx } from './createSignedTx';
import { createSigningPayload } from './createSigningPayload';
import { TEST_TX_INFO } from './util/testUtil';
import { balanceTransfer } from './balanceTransfer';
describe('createSignedTx', () => {
it('should work', async done => {
// We're creating an Alice account that will sign the payload
// Wait for the promise to resolve async WASM
await cryptoWaitReady();
const registry = new TypeRegistry();
// Use ed25519 because it has deterministic signatures
const keyring = new Keyring({ type: 'ed25519' });
const alice = keyring.addFromUri('//Alice', { name: 'Alice default' });
const unsigned = balanceTransfer(TEST_TX_INFO);
const signingPayload = createSigningPayload(unsigned);
const { signature } = createType(
registry,
'ExtrinsicPayload',
signingPayload,
{
version: unsigned.version
}
).sign(alice);
expect(signature).toEqual(
'0x003d0fdf8b55e6712b2766d80e9a4f527c3deb3d728a815db77df52d766643cdab3170e25ccd867a4d16c0a8f648b753cd95fed0b46ace6cc4e6e5942712409908'
);
const tx = createSignedTx(unsigned, signature);
expect(tx).toBe('1324');
done();
});
});
import { createType, TypeRegistry } from '@polkadot/types';
import { UnsignedTransaction } from './balanceTransfer';
/**
* Create the signing payload (i.e. the payload that needs to be signed) from
* an unsigned transaction.
*
* @param unsigned - The JSON representing the unsigned transaction
* @param signature - Signature of the signing payload produced by the remote signer
*/
export function createSignedTx(
unsigned: UnsignedTransaction,
signature: string
): string {
const registry = new TypeRegistry();
const extrinsic = createType(
registry,
'Extrinsic',
{ method: unsigned.method },
{ version: unsigned.version }
);
extrinsic.addSignature(unsigned.address, signature, unsigned);
return extrinsic.toHex();
}
import { createSigningPayload } from './createSigningPayload';
import { balanceTransfer } from './balanceTransfer';
import { TEST_TX_INFO } from './util/testUtil';
describe('createSigningPayload', () => {
it('should work', () => {
const signingPayload = createSigningPayload(balanceTransfer(TEST_TX_INFO));
expect(signingPayload).toEqual(
'0x900600ff96074594cccf1cd185fa8a72ceaeefd86648f8d45514f3ce33c31bdd07e4655d30eb580800fb030000e3777fa922cafbff200cadeaea1a76bd7898ad5b89f7848999058b50e715f6361fc7493f3c1e9ac758a183839906475f8363aafb1b1d3e910fe16fab4ae1b582'
);
});
});
import { createType, TypeRegistry } from '@polkadot/types';
import { UnsignedTransaction } from './balanceTransfer';
/**
* Create the signing payload (i.e. the payload that needs to be signed) from
* an unsigned transaction.
*
* @param unsigned - The JSON representing the unsigned transaction
*/
export function createSigningPayload(unsigned: UnsignedTransaction): string {
const registry = new TypeRegistry();
return createType(registry, 'ExtrinsicPayload', unsigned, {
version: unsigned.version
}).toHex();
}
import { Keyring } from '@polkadot/api';
import { createType, TypeRegistry } from '@polkadot/types';
import { cryptoWaitReady } from '@polkadot/util-crypto';
import { createSignedTx } from './createSignedTx';
import { createSigningPayload } from './createSigningPayload';
import { TEST_TX_INFO } from './util/testUtil';
import { balanceTransfer } from './balanceTransfer';
import { decodeTx } from './decodeTx';
describe('parseTx', () => {
it('should work', async done => {
// We're creating an Alice account that will sign the payload
// Wait for the promise to resolve async WASM
await cryptoWaitReady();
const registry = new TypeRegistry();
// Use ed25519 because it has deterministic signatures
const keyring = new Keyring({ type: 'ed25519' });
const alice = keyring.addFromUri('//Alice', { name: 'Alice default' });
const unsigned = balanceTransfer(TEST_TX_INFO);
const signingPayload = createSigningPayload(unsigned);
const { signature } = createType(
registry,
'ExtrinsicPayload',
signingPayload,
{
version: unsigned.version
}
).sign(alice);
const tx = createSignedTx(unsigned, signature);
const txInfo = decodeTx(tx);
expect(txInfo).toEqual(TEST_TX_INFO);
});
});
import { createType, TypeRegistry } from '@polkadot/types';
import { hexToU8a } from '@polkadot/util';
import { TxInfo } from './balanceTransfer';
/**
* Parse a signed transaction, and extract information about the transaction
*
* @param unsigned - The JSON representing the unsigned transaction
*/
export function decodeTx(signedTx: string): TxInfo {
const registry = new TypeRegistry();
const tx = createType(registry, 'Extrinsic', hexToU8a(signedTx), {
isSigned: true
});
console.log('AAA', tx.method.argsDef);
return {
address: tx.nonce.
};
}
import metadataRpc from '@polkadot/metadata/Metadata/v9/static';
import { TxInfo } from '../balanceTransfer';
export const TEST_TX_INFO: TxInfo = {
address: 'HgWWnAXFGikrPVD2FrZ6CRk7KnYdVDn7zVyye8hqFPMc5g1',
amount: 12,
blockHash:
'0x1fc7493f3c1e9ac758a183839906475f8363aafb1b1d3e910fe16fab4ae1b582',
blockNumber: 4302222,
genesisHash:
'0xe3777fa922cafbff200cadeaea1a76bd7898ad5b89f7848999058b50e715f636',
metadataRpc,
nonce: 2,
specVersion: 1019,
tip: 0,
to: 'Fy2rsYCoowQBtuFXqLE65ehAY9T6KWcGiNCQAyPDCkfpm4s'
};
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment