Web3.swift
Web3.swift copied to clipboard
Bug: Insufficient funds error when there are funds available
Hi there
I'm using a dynamic contract and can make calls to it successfully. However when using 'contract.createTransaction' methods on the same contract, I keep receiving the error:
Web3.RPCResponse<Web3.EthereumData>.Error(code: -32010, message: "Insufficient funds. The account you tried to send transaction from does not have enough funds. Required 2000000000000000 and got: 0."
I'm signing the 'contract.createTransaction' with my privateKey and the correct ETH address (with sufficient balance) is being shown for privateKey.address.
I'm not sure what else to try as the transaction seems to be correctly created (as per instructions for creating dynamic contract transactions), and the ETH address definitely has a sufficient balance.
Hey @mrdavey
Could you please create a quick sample project with this bug and send us a link or a zip file?
Sorry for the delay @Ybrin . See https://www.dropbox.com/s/ylk74487foanv90/test.zip?dl=0
To get the same error, complete the 'privateKeyString' in the ViewController file (with an address with some amount of ETH), then run in simulator and hit the button. I've tested this on mainnet with both infura and myetherapi and they return similar errors.
@pixelmatrix Can you reproduce this?
Hmm, that's a weird one. I'm wondering if somehow the from and to are swapped in the signed raw transaction's RLP. Or perhaps one of the other values are being input where the from should be. If that were the case then it would mean it's checking the balance of the wrong address.
Btw looks like this error code is a generic transaction error from Parity, so we'll just have to go off of the message: https://github.com/paritytech/parity-ethereum/blob/master/rpc/src/v1/helpers/errors.rs#L37
Thanks for investigating. What are the potential solutions to this? (I'd really like to use this library in production and not have to go back to Web3.js) 😅
@mrdavey I can look into this at some point. Currently swamped with some other work but i'd like to get to the bottom of this!
Guys, FYI, I was having the same issue, but the error was
pub const UNSUPPORTED_REQUEST: i64 = -32000;
(from the link above ☝️ )
I managed to get it to work by going into https://www.myetherwallet.com/#offline-transaction, putting my sender address (preceded by 0x
) in the "from address" field, filling the "to address", value, and leaving "data" blank. I signed it, and read the Raw Transaction data, which included a "chainId": 3
. I wasn't sending the chainId before when signing the transaction (which defaults to 0) and that fixed my problem.
So the issue is that it's looking up at the balance of the address in the wrong network. My setup uses an Infura API in the Ropsten Network, so I thought this would be handled automatically. Apparently not.
Until now I had no idea what was the chain ID tbh, but googling showed me that it's the network ID. See https://ethereum.stackexchange.com/questions/17051/how-to-select-a-network-id-or-is-there-a-list-of-network-ids
What is the behavior when 0
is sent, and why not make this an enum?
Hope to have helped you guys debug this, and to help others who face the same error. 👍
Good spotting @rogerluan ! That solved the issue.
I.e. replaced let signedTx = try tx?.sign(with: myKey)
with let signedTx = try tx?.sign(with: myKey, chainId: 1)
I made this an enum in my project so it's type-safe, and also so that I can alternate it based on the environment (e.g. sandbox, dev, staging, production) alongside other API keys and URLs e.g. Infura 👍
Also @mrdavey I still don't get what's the behavior when the default 0
is used? 🤔 I think this parameter should have no default value, or default to 1 since it's the main net? :)
Good idea on making it typesafe 👍 I think the default 0
was a mistake, as it isn't really used for replay protection, as far as i know. See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
@Ybrin @pixelmatrix I've created a PR that should clarify the 'fix' for this issue #61
My understanding is that providing a '0' value SHOULD work, but it doesn't give you the simple replay protection that passing a chainId would give you (The protection is against submitting the same transaction on another chain).
My guess is that something is wrong with the RLP encoding for the 0 value here (causing the node to see a different address), but passing a chainId is probably for the best anyway.
@Ybrin any thoughts?
@pixelmatrix Please see https://github.com/Boilertalk/Web3.swift/pull/61#issuecomment-412616514 for my thoughts regarding this issue.