Can't make dryRun with wallet that doesn't have ETH on balance

Requests with simulate or dryRun fail when I provide a wallet instance without ETH on balance.

Error: not enough coins to fit the target: {"response":{"data":null,"errors":[{"message":"not enough coins to fit the target","locations":[{"line":2,"column":3}],"path":["coinsToSpend"]}],"status":200,"headers":{"map":{"content-type":"application/json"}}},"request":{"query":"query getCoinsToSpend($owner: Address!, $queryPerAsset: [SpendQueryElementInput!]!, $excludedIds: ExcludeInput) {\n  coinsToSpend(\n    owner: $owner\n    queryPerAsset: $queryPerAsset\n    excludedIds: $excludedIds\n  ) {\n    ...coinFragment\n    ...messageCoinFragment\n  }\n}\n\nfragment coinFragment on Coin {\n  __typename\n  utxoId\n  owner\n  amount\n  assetId\n  maturity\n  blockCreated\n  txCreatedIdx\n}\n\nfragment messageCoinFragment on MessageCoin {\n  __typename\n  sender\n  recipient\n  nonce\n  amount\n  assetId\n  daHeight\n}","variables":{"owner":"0x689a861c0f215ebad8a51b1e0332b3967f47a8ae1e698805811683339673d137","queryPerAsset":[{"assetId":"0x0000000000000000000000000000000000000000000000000000000000000000","amount":"1"}],"excludedIds":{"messages":[],"utxos":[]}}}}
    at makeRequest (index.ts:441:1)
    at async Provider.getResourcesToSpend (provider.ts:632:1)
    at async FunctionInvocationScope.fundWithRequiredCoins (base-invocation-scope.ts:227:1)
    at async FunctionInvocationScope.prepareTransaction (base-invocation-scope.ts:183:1)
    at async FunctionInvocationScope.getTransactionRequest (base-invocation-scope.ts:269:1)
    at async FunctionInvocationScope.simulate (base-invocation-scope.ts:313:1)
    at async Promise.all (:3000/index 6)
    at async PricesStore.updateTokenPrices (PricesStore.ts:54:1)

Here is code that I use

let provider = new Provider(NODE_URL);
      const wallet = Wallet.generate({ provider });
      const oracleContract = OracleAbi__factory.connect(priceOracle, wallet);

      const response = await Promise.all(
        TOKENS_LIST.map((token) =>
          oracleContract.functions.get_price(token.assetId).simulate()
        )
      );

Hi there!
As seen in the fuels-ts docs

Note: Although a simulate() call won’t modify the blockchain’s state and does not spend resources, the transaction must still meet its requirements to be considered valid.

So it seems that “get_price” does consume resources. Simulate won’t spend these resources but will evaluate if you have balance to run the call.

Let me know if this works for you

2 Likes

This was introduced in Fuel VM v0.33.0 where script/create transactions require a spendable input to be considered valid - more info here. This was introduced in TS SDK v0.46.0, further TS specific info here.

4 Likes

Are you sure sir? This function just gets the value from storage

2 Likes

@sway yes correct, please take a look at our simulate() vs call() documentation:

Although a simulate() call won’t modify the blockchain’s state and does not spend resources, the transaction must still meet its requirements to be considered valid.

This was one of the motivations behind deprecating get(). The fuel specs also echo this information by stating:

No inputs are of type InputType.Coin or InputType.Message with input.dataLength == 0

Meaning a spendable input is required for a valid transaction, even for a readonly transaction.

Are you able to dump the transaction to confirm no spendable inputs?

Just adding to the above, I’ve just added some further test cases that replicate the above detailing that we are expecting the above to throw.