I have generated a ScriptTransaction
from typescript sdk and want to generate signature separately without using the wallet client (basically generate ECDSA signature from txn data hash separately) and then send signature and txn to the network.
Is there a method that supports sending raw txn hash/bytes and signature to the network ?
Hey @singhparshant, did you see the docs around signing transactions?
You can also find the source code example (unit test) here.
Please let me know if that helps.
@anderson Thanks for the reply.
Yes, I checked this, but i don’t see the option to add a from
address, i think it uses the wallet address as the sender.
I want to assemble a custom transaction.
Hello @singhparshant, how are you?
I am unsure If I understand what you are trying to achieve.
But I assume that is to get the hash of a ScriptTransaction
and use it to generate an ECDSA signature, then add this signature to the ScriptTransaction
before submitting it.
If so this can be achieved by the following approach:
import { splitSignature } from '@ethersproject/bytes';
import { hexToBytes } from '@ethereumjs/util';
import Web3 from 'web3';
const provider = await Provider.create(FUEL_NETWORK_URL);
const chainId = provider.getChainId();
// Transaction Hash (ID)
const hashedTransaction = scriptTransactionRequest.getTransactionId(chainId);
// If you are using web3
const web3 = new Web3('https://provider.url.here');
const privateKey = '0xYOUR_PRIVATE_KEY';
const account = web3.eth.accounts.privateKeyToAccount(privateKey);
web3.eth.accounts.wallet.add(account);
const signature = await web3.eth.personal.sign(hashedTransaction, account.address, account.privateKey)
// Transform the signature into compact form for Sway to understand, in case it will be used within a Sway program
const compactSignature = splitSignature(hexToBytes(signature)).compact;
// Add signature to the transaction witnesses
scriptTransactionRequest.witnesses.push(compactSignature);
const tx = await fuelWallet.sendTransaction(scriptTransactionRequest)
const response = await tx.waitForResult()
Please let me know if I misunderstood your request.
thank you. I think this is what i require. Will give it a try.
Quick question :
const compactSignature = splitSignature(hexToBytes(signature)).compact;
Is this functionality present in fuel-ts somewhere ?
No, we don’t have this functionality explicit defined on the fuels-ts.
But you can use the following NPM packages:
import { splitSignature } from '@ethersproject/bytes';
import { hexToBytes } from '@ethereumjs/util';
@Torres-ssf Looks like the hexToBytes
method is deprecated:
export const hexToBytes = (hex: string): Uint8Array => {
......
return _unprefixedHexToBytes(hex)
}
The signature '(hex: string): Uint8Array' of '_unprefixedHexToBytes' is deprecated.ts(6387)
Also, in this unit test, request.updateWitnessByOwner
is being used, as opposed to the one that you suggested scriptTransactionRequest.witnesses.push(compactSignature)
Are they both same, do these results in similar transaction request ?
Hello @singhparshant
You can use arrayify
(which can be imported from fuels
) instead of hexToBytes
.
import { arrayify } from 'fuels'
The request.updateWitnessByOwner
replaces a placeholder zeroed witness entry that was added on behalf of one account. It will extract the witness index from the resources added to the transaction request. It is a different use case.
Did the proposed solution here solved your problem?
I am still working on it. I have some issues with React-Native currently.
Issue
@Torres-ssf I am assembling the txn and trying to send to the network, however i am getting NoSpendableInput
error. I am not adding anything in the inputs array of the txn request, just pushing the signature. What should i push to the input array to make it work ? I don’t want to use wallet and the fee should be deducted from the sender’s input.
My code:
signTxInformation.addCoinOutput(
new Address(toBech32(B256)),
transferAmount.toString(),
this.client.getBaseAssetId()
);
const provider = this.core.client;
const signature = new secp256k1.Signature(
BigInt(bufferToHex(signatures[0].slice(0, 32))), // r
BigInt(bufferToHex(signatures[0].slice(32, 64))) // s
);
console.log("after signture");
const recoveryId = recoveryIdKeccak256(
publicKey,
messages[0],
signatures[0]
);
console.log("After recoverId");
// https://github.com/FuelLabs/fuels-ts/blob/e165e37307d65deda99f675723ea26470bf807d8/packages/account/src/signer/signer.ts#L54
const r = toBytes(`0x${signature.r.toString(16)}`, 32);
const s = toBytes(`0x${signature.s.toString(16)}`, 32);
console.log("After r and s");
// add recoveryParam to first s byte
s[0] |= (recoveryId || 0) << 7;
const finalSignature = hexlify(hexlify(concat([r, s])));
console.log("After final signature");
const recoveredAddress = Signer.recoverAddress(
signTxInformation.getTransactionId(this.core.client.getChainId()),
finalSignature
);
console.log("After recovered address", recoveredAddress);
// Add the signature to the transaction
// signTxInformation.updateWitnessByOwner(recoveredAddress, finalSignature);
signTxInformation.witnesses.push(finalSignature);
// Send transaction to the network
const res = await provider.sendTransaction(signTxInformation);
// Return the transaction hash
console.log("Exxxx: ", res);
return res.id;
Nevermind, found this getResourcesToSpend
method in provider.
But the signature is invalid for some reason. Not sure if my signature generation is correct.
@singhparshant Can you give me a better context about the Transaction that you are trying to submit?
Is this a simple transfer? A contract call? Or you have simply created a script that will use the signature?
The code of the Sway project can also help us understand your problem.
Thanks in advance
This is resolved now. It was typo on my end.
Thanks.
This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.