Web3.swift icon indicating copy to clipboard operation
Web3.swift copied to clipboard

Bug: Insufficient funds error when there are funds available

Open mrdavey opened this issue 6 years ago • 15 comments

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.

mrdavey avatar Jul 17 '18 10:07 mrdavey

Hey @mrdavey

Could you please create a quick sample project with this bug and send us a link or a zip file?

koraykoska avatar Jul 18 '18 14:07 koraykoska

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.

mrdavey avatar Jul 20 '18 22:07 mrdavey

@pixelmatrix Can you reproduce this?

koraykoska avatar Jul 22 '18 22:07 koraykoska

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.

pixelmatrix avatar Jul 23 '18 17:07 pixelmatrix

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

pixelmatrix avatar Jul 23 '18 17:07 pixelmatrix

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 avatar Jul 24 '18 16:07 mrdavey

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

pixelmatrix avatar Jul 27 '18 20:07 pixelmatrix

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

rogerluan avatar Aug 13 '18 01:08 rogerluan

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)

mrdavey avatar Aug 13 '18 14:08 mrdavey

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 👍

rogerluan avatar Aug 13 '18 15:08 rogerluan

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? :)

rogerluan avatar Aug 13 '18 15:08 rogerluan

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

mrdavey avatar Aug 13 '18 16:08 mrdavey

@Ybrin @pixelmatrix I've created a PR that should clarify the 'fix' for this issue #61

mrdavey avatar Aug 13 '18 16:08 mrdavey

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 avatar Aug 13 '18 18:08 pixelmatrix

@pixelmatrix Please see https://github.com/Boilertalk/Web3.swift/pull/61#issuecomment-412616514 for my thoughts regarding this issue.

koraykoska avatar Aug 13 '18 18:08 koraykoska