Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

insufficient funds for gas * price + value #103

Open
AndreyNovikov2909 opened this issue Apr 29, 2021 · 6 comments
Open

insufficient funds for gas * price + value #103

AndreyNovikov2909 opened this issue Apr 29, 2021 · 6 comments

Comments

@AndreyNovikov2909
Copy link

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

    firstly {
        self.contract["balanceOf"]!(self.myWallet).call()
    }.done { (data) in
        print("mint:", data) // ok
    }.catch { (error) in
        print("mint:", error) 
    }
    
    let transaction =  self.contract["mint"]!(self.contractAddress, BigInt(10000000000)).createTransaction(nonce: 4,
                                                                                     from: self.myWallet,
                                                                                     value: 0,
                                                                                     gas: 300000,
                                                                                     gasPrice: EthereumQuantity(quantity: 80.gwei))!
            
    let sign = try! transaction.sign(with: self.privateKey)
            
    firstly {
        self.web3.eth.sendRawTransaction(transaction: sign)
    }.done { (v) in
        print(v)
    }.catch { (error) in
        print(error) // always "insufficient funds for gas * price + value"
    }

// the transfer method of the smatr contract

  let transaction = contract["transfer"]!(toSendWallet, BigUInt(10000)).createTransaction(nonce: 0,
                                                                                            from: privateKey.address,
                                                                                            value: 0,
                                                                                            gas: 1000000,
                                                                                            gasPrice: EthereumQuantity(quantity: 80.gwei))!

    // I think there is a problem here when I sign a transaction
    let signedTx = try! transaction.sign(with: privateKey)
    
    firstly {
        web3.eth.sendRawTransaction(transaction: signedTx)
    }.done { txHash in
        print(txHash)
        fatalError()
    }.catch { error in
        print(error) // always "insufficient funds for gas * price + value"
    }


     firstly {
        self.contract["mint"]!(self.contractAddress, BigInt(10000000000)).send(from: self.myWallet,
                                                   value: 0,
                                                   gas: 300000,
                                                   gasPrice: EthereumQuantity(quantity: 80.gwei))
    }.done { (value) in
        print(value)
    }.catch { (error) in
        print(error) // always The method eth_sendTransaction does not exist/is not available
    }
@mudilajaganios
Copy link

@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.

@mudilajaganios
Copy link

mudilajaganios commented Jun 12, 2021

@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)
        )
    }
}

@podkovyrin
Copy link

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
}

@mudilajaganios
Copy link

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.

@podkovyrin
Copy link

@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

@mudilajaganios
Copy link

mudilajaganios commented Jul 15, 2021

@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)
        )
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants