Open AndreyNovikov2909 opened 3 years ago
@AndreyNovikov2909 Did you fix the issue? I am also facing the same problem. Signing transaction is not working well it seems. I checked the same values with javascript code the hash of signed transaction is different from the swift code.I believe the r s v values are not calculated properly in the swift code. Please let me know if you have any developments.
@AndreyNovikov2909
I got rid off the issue by extending the EthereumTransaction
struct also I had to extend RLPItem
struct too.
It worked for me, try for yourself. Please suggest me any better approach.
I have compared it with the Web3.js javascript implementation. Only 6 properties to be used for signing the transaction they are as below:
none
gasPrice
gasLimit
to
value - <To-be empty string>
data
extension EthereumTransaction {
public func signX(with privateKey: EthereumPrivateKey, chainId: EthereumQuantity = 0) throws -> EthereumSignedTransaction {
// These values are required for signing
guard let nonce = nonce, let gasPrice = gasPrice, let gasLimit = gas, let value = value else {
throw EthereumSignedTransaction.Error.transactionInvalid
}
let rlp = RLPItem(
nonce: nonce,
gasPrice: gasPrice,
gasLimit: gasLimit,
to: to,
data: data
)
let rawRlp = try RLPEncoder().encode(rlp)
guard let signedTransaction = try? privateKey.sign(message: rawRlp) else { throw EthereumSignedTransaction.Error.transactionInvalid }
let v: BigUInt
if chainId.quantity == 0 {
v = BigUInt(signedTransaction.v) + BigUInt(27)
} else {
let sigV = BigUInt(signedTransaction.v)
let big27 = BigUInt(27)
let chainIdCalc = (chainId.quantity * BigUInt(2) + BigUInt(8))
v = sigV + big27 + chainIdCalc
}
return EthereumSignedTransaction(
nonce: nonce,
gasPrice: gasPrice,
gasLimit: gasLimit,
to: to,
value: value,
data: data,
v: EthereumQuantity(quantity: v),
r: EthereumQuantity(quantity: BigUInt(signedTransaction.r)),
s: EthereumQuantity(quantity: BigUInt(signedTransaction.s)),
chainId: chainId
)
}
}
extension RLPItem {
/**
* Create an RLPItem representing a transaction. The RLPItem must be an array of 9 items in the proper order.
*
* - parameter nonce: The nonce of this transaction.
* - parameter gasPrice: The gas price for this transaction in wei.
* - parameter gasLimit: The gas limit for this transaction.
* - parameter to: The address of the receiver.
* - parameter data: Input data for this transaction.
* - parameter v: EC signature parameter v, or a EIP155 chain id for an unsigned transaction.
* - parameter r: EC signature parameter r.
* - parameter s: EC recovery ID.
*/
init(
nonce: EthereumQuantity,
gasPrice: EthereumQuantity,
gasLimit: EthereumQuantity,
to: EthereumAddress?,
data: EthereumData
) {
self = .array(
.bigUInt(nonce.quantity),
.bigUInt(gasPrice.quantity),
.bigUInt(gasLimit.quantity),
.bytes(to?.rawAddress ?? Bytes()),
.string(""),
.bytes(data.bytes)
)
}
}
You need to estimate gas before sending tx to the network.
let call = EthereumCall(from: from, to: to, gasPrice: gasPrice, value: value, data: data)
eth.estimateGas(call: call, block: .latest) { response in
// use gas limit from response
}
You need to estimate gas before sending tx to the network.
let call = EthereumCall(from: from, to: to, gasPrice: gasPrice, value: value, data: data) eth.estimateGas(call: call, block: .latest) { response in // use gas limit from response }
Thanks @podkovyrin I am through with this issue. As I mentioned in my previous reply. There is an issue with the Transaction signature. So, Implemented the changes.
@mudilajaganios
let rlp = RLPItem(
nonce: nonce,
gasPrice: gasPrice,
gasLimit: gasLimit,
to: to,
data: data
)
This looks kinda dangerous, you need to include chain id in the signature otherwise it might lead to replay attacks. See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
@podkovyrin
Hey sorry, the code was not updated. I faced the issue with the chain id too. I changed the method to include it.
func signX(with privateKey: EthereumPrivateKey, chainId: Int = 0) throws -> EthereumSignedTransaction {
// These values are required for signing
guard let nonce = nonce, let gasPrice = gasPrice, let gasLimit = gas, let value = value else {
throw EthereumSignedTransaction.Error.transactionInvalid
}
let rlp = RLPItem(
nonce: nonce,
gasPrice: gasPrice,
gasLimit: gasLimit,
to: to,
data: data,
chainId: UInt(chainId)
)
let rawRlp = try RLPEncoder().encode(rlp)
guard let signedTransaction = try? privateKey.sign(message: rawRlp) else { throw EthereumSignedTransaction.Error.transactionInvalid }
let v: BigUInt
if chainId == 0 {
v = BigUInt(signedTransaction.v) + BigUInt(27)
} else {
let sigV = BigUInt(signedTransaction.v)
let big27 = BigUInt(27)
let chainIdCalc = (BigUInt(chainId) * BigUInt(2) + BigUInt(8))
v = sigV + big27 + chainIdCalc
}
return EthereumSignedTransaction(
nonce: nonce,
gasPrice: gasPrice,
gasLimit: gasLimit,
to: to,
value: value,
data: data,
v: EthereumQuantity(quantity: v),
r: EthereumQuantity(quantity: BigUInt(signedTransaction.r)),
s: EthereumQuantity(quantity: BigUInt(signedTransaction.s)),
chainId: EthereumQuantity(quantity: BigUInt(chainId))
)
}
RLPItem needs to be as below.
extension RLPItem {
/**
* Create an RLPItem representing a transaction. The RLPItem must be an array of 6 items in the proper order.
*
* - parameter nonce: The nonce of this transaction.
* - parameter gasPrice: The gas price for this transaction in wei.
* - parameter gasLimit: The gas limit for this transaction.
* - parameter to: The address of the receiver.
* - parameter data: Input data for this transaction.
*/
init(
nonce: EthereumQuantity,
gasPrice: EthereumQuantity,
gasLimit: EthereumQuantity,
to: EthereumAddress?,
data: EthereumData,
chainId: UInt
) {
self = .array(
.bigUInt(nonce.quantity),
.bigUInt(gasPrice.quantity),
.bigUInt(gasLimit.quantity),
.bytes(to?.rawAddress ?? Bytes()),
.string(""),
.bytes(data.bytes),
.init(integerLiteral: chainId),
.init(integerLiteral: 0),
.init(integerLiteral: 0)
)
}
}
Hello I always get this error when signing the transaction "insufficient funds for gas * price + value" I understand that the problem is not with gas, but in the private key with which I sign the transaction, what could be the problem? Methods that do not require gas are successful, I can say for sure that there is a sufficient amount on my wallet - 0x92Ddc4493d6839811F047D7729b2cFcB4DA3780F. if i don't sign the transaction i call the send method directly i get this error - "The method eth_sendTransaction does not exist/is not available"
// code // the mint method of the smatr contract
// the transfer method of the smatr contract