sender.ts 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import BN = require('bn.js');
  2. import { ApiPromise } from '@polkadot/api';
  3. import { Index } from '@polkadot/types/interfaces';
  4. import { SubmittableExtrinsic } from '@polkadot/api/types';
  5. import { KeyringPair } from '@polkadot/keyring/types';
  6. export class Sender {
  7. private readonly api: ApiPromise;
  8. private static nonceMap: Map<string, BN> = new Map();
  9. constructor(api: ApiPromise) {
  10. this.api = api;
  11. }
  12. private async getNonce(address: string): Promise<BN> {
  13. let oncahinNonce: BN = new BN(0);
  14. if (!Sender.nonceMap.get(address)) {
  15. oncahinNonce = await this.api.query.system.accountNonce<Index>(address);
  16. }
  17. let nonce: BN | undefined = Sender.nonceMap.get(address);
  18. if (!nonce) {
  19. nonce = oncahinNonce;
  20. }
  21. const nextNonce: BN = nonce.addn(1);
  22. Sender.nonceMap.set(address, nextNonce);
  23. return nonce;
  24. }
  25. private clearNonce(address: string): void {
  26. Sender.nonceMap.delete(address);
  27. }
  28. public async signAndSend(
  29. tx: SubmittableExtrinsic<'promise'>,
  30. account: KeyringPair,
  31. expectFailure = false
  32. ): Promise<void> {
  33. return new Promise(async (resolve, reject) => {
  34. const nonce: BN = await this.getNonce(account.address);
  35. console.log('sending transaction from ' + account.address + ' with nonce ' + nonce);
  36. const signedTx = tx.sign(account, { nonce });
  37. await signedTx
  38. .send(async result => {
  39. if (result.status.isFinalized === true && result.events !== undefined) {
  40. result.events.forEach(event => {
  41. if (event.event.method === 'ExtrinsicFailed') {
  42. if (expectFailure) {
  43. resolve();
  44. } else {
  45. reject(new Error('Extrinsic failed unexpectedly'));
  46. }
  47. }
  48. });
  49. resolve();
  50. }
  51. if (result.status.isFuture) {
  52. console.log('nonce ' + nonce + ' for account ' + account.address + ' is in future');
  53. this.clearNonce(account.address);
  54. reject(new Error('Extrinsic nonce is in future'));
  55. }
  56. })
  57. .catch(error => {
  58. reject(error);
  59. });
  60. });
  61. }
  62. }