paritytech / txwrapper-core

Tools for FRAME chain builders to publish chain specific offline transaction generation libraries.
https://paritytech.github.io/txwrapper-core/
Apache License 2.0
77 stars 28 forks source link

Usage with Bittensor TAO #402

Open TheTrunk opened 2 weeks ago

TheTrunk commented 2 weeks ago

For Polkadot, Kusama we can use @substrate/txwrapper-polkadot and follow https://github.com/paritytech/txwrapper-core/blob/main/packages/txwrapper-examples/polkadot/src/polkadot.ts

Since Bittensor TAO is based on Substrate, I thought that transactions would follow the same with changing to Bittensor parameters. However we obtain a following error:

"Transaction has a bad signature" error while submitting the extrinsic.

Thank you for your advice

bee344 commented 1 day ago

Hi @TheTrunk , sorry for the delay, could you share some more details of your script?

TheTrunk commented 1 day ago

Hi @TheTrunk , sorry for the delay, could you share some more details of your script?

Hi sure!

  const blocksData = { id: Math.floor(Math.random() * (1000000)) + 1, jsonrpc: "2.0", method: "chain_getHeader" };
  const runtimeData = { id: Math.floor(Math.random() * (1000000)) + 1, jsonrpc: "2.0", method: "state_getRuntimeVersion" };
  const metadataData = { id: Math.floor(Math.random() * (1000000)) + 1, jsonrpc: "2.0", method: "state_getMetadata" };
  const nonceData = {
    id: Math.floor(Math.random() * (1000000)) + 1, jsonrpc: "2.0", method: "account_nextIndex", params: [senderAddress],
  };

  const responseRuntime = await self.$http.post(nodeEndpoint, runtimeData, axiosConfig);
  const responseMetadata = await self.$http.post(nodeEndpoint, metadataData, axiosConfig);
  const responseBlocks = await self.$http.post(nodeEndpoint, blocksData, axiosConfig);
  const responseNonce = await self.$http.post(nodeEndpoint, nonceData, axiosConfig);

  const metadataRpc = responseMetadata.data.result;
  const {
    specVersion, transactionVersion, specName, implName,
  } = responseRuntime.data.result;
  const blockNumberHex = responseBlocks.data.result.number;
  const lastBlockHash = responseBlocks.data.result.parentHash;
  const lastBlockNumber = Number.parseInt(blockNumberHex, 16);
  const nonce = responseNonce.data.result;

  const registry = substrateTxWrappergetRegistry({
    specName,
    chainName: implName,
    specVersion,
    metadataRpc,
    // properties: {
    //   ss58Format: 42,
    //   tokenDecimals: 9,
    //   tokenSymbol: "TAO",
    // },
  });
  console.log(registry);

  const unsigned = substrateTxWrappermethods.balances.transferKeepAlive(
    {
      value,
      dest: address,
    },
    {
      address: senderAddress,
      blockHash: lastBlockHash,
      blockNumber: Number(lastBlockNumber),
      eraPeriod: 88, // valid for 88 blocks
      genesisHash,
      metadataRpc,
      nonce,
      specVersion,
      tip,
      transactionVersion,
    },
    {
      metadataRpc,
      registry,
    },
  );
  console.log(unsigned);

  // Construct the signing payload from an unsigned transaction.
  const signingPayload = substrateTxWrapperconstruct.signingPayload(unsigned, { registry });
  console.log(signingPayload);

  const importedKeyring = substrateTxWrapperimportPrivateKey(pk, ss58prefix);
  const EXTRINSIC_VERSION = 4;
  const { signature } = registry
    .createType("ExtrinsicPayload", signingPayload, {
      version: EXTRINSIC_VERSION,
    })
    .sign(importedKeyring);

  console.log(`\nSignature: ${signature}`);

  // Serialize a signed transaction.
  const tx = substrateTxWrapperconstruct.signedTx(unsigned, signature, { metadataRpc, registry });
  console.log(`\nTransaction to Submit: ${tx}`);

  // Derive the tx hash of a signed transaction offline.
  const expectedTxHash = substrateTxWrapperconstruct.txHash(tx);
  console.log(`\nExpected Tx Hash: ${expectedTxHash}`);

  const txData = {
    id: Math.floor(Math.random() * (1000000)) + 1, jsonrpc: "2.0", method: "author_submitExtrinsic", params: [tx],
  };
  const submitTx = await self.$http.post(nodeEndpoint, txData, axiosConfig);
  if (submitTx.data.error) {
    throw submitTx.data.error;
  }
  const txid = submitTx.data.result;`

Thank you for reviewing it!

bee344 commented 1 day ago

@TheTrunk I'd need some more info to work with: