スマートコントラクトをFlutterから実行したときのエラー

## Unhandled Exception: RangeError: Value not in range: 32

### 解決策
結論から言うと、

\
RPCノードに接続するときのendPointを確かめる。

\
これに至った経緯を知りたい方は続きを。
### コード

```dart
Future<Web3Client> connectClient() async {
  http.Client httpClient = http.Client();
  Web3Client ethClient = Web3Client(
      "[MyEndPoint]",
      httpClient);

  return ethClient;
}

Future<DeployedContract> loadContract() async {
  String abi = await rootBundle.loadString("[jsonFile]");
  String contractAddress = "[MyContractAddress]";
  final contract = DeployedContract(ContractAbi.fromJson(abi, "abi"),
      EthereumAddress.fromHex(contractAddress));
  return contract;
}

Future<List<dynamic>> query(String functionName, List<dynamic> args) async {
  final contract = await loadContract();
  final ethFunction = contract.function(functionName);
  Web3Client ethClient = await connectClient();
  final result = await ethClient.call(
      contract: contract, function: ethFunction, params: args);
  return result;
}

Future<String> getURI(int tokenId) async {
  List<dynamic> result = await query('uri', [tokenId]);
  print("result: $result");
  return result[0];
}
```

### やったこと① tokenIdのtypeを変える

Value not in range: 32とあるからtokenIdを32bytesにしないといけないのかな？

`tokenId → BigInt.from(tokenId).toUnsigned(256)`

結果、うまくいかない。

tokenIdは2とかに設定しているから、まあ当たり前か。

### やったこと② ネットで記事を探してみる

あえて文献は載せないけど、

```dart
Future<String> getURI(String targetAddress) async {
  // EthereumAddress address = EthereumAddress.fromHex(targetAddress);
  List<dynamic> result = await query('uri', [BigInt.from(2).toUnsigned(256)]);
  print("result: $result");
  return result[0];
}
```

こんな感じでgetURIを定義して同じエラーを出している人がいた（targetAddressどこで使うんかい）。

これに対するAnswerで「2行目のコメントアウトを消しなさい」と書いてある。

?? そんなわけ。

一応すぐ終わるから試した結果、「そんなわけ」。

### やったこと③ 関数のソースコードを読む

ネストがすごくてあまりやりたくなかった。

タイトルに続くエラーは次の通り。

`E/flutter (31605): #0      _rangeCheck (dart:typed_data-patch/typed_data_patch.dart:5098:5)
E/flutter (31605): #1      _ByteBuffer.asUint8List (dart:typed_data-patch/typed_data_patch.dart:1917:5)
E/flutter (31605): #2      AddressType.decode
package:web3dart/…/abi/integers.dart:117
E/flutter (31605): #3      TupleType.decode
package:web3dart/…/abi/tuple.dart:106
E/flutter (31605): #4      ContractFunction.decodeReturnValues
package:web3dart/…/abi/abi.dart:273
E/flutter (31605): #5      Web3Client.call`

ソースコードをたどると、Web3Client.callの

```jsx
return function.decodeReturnValues(encodedResult);
```

でエラーが起きててなぜかデコードできてない。その前を見ると、

```dart
final encodedResult = await callRaw(
      sender: sender,
      contract: contract.address,
      data: function.encodeCall(params),
      atBlock: atBlock,
    );
```

となってて、callRawでEthereumから結果は受け取っている。この結果が期待された形式ではないのかも？

sender, contract.address, atBlockは間違えてないはず。(sender, atBlockは指定しなくていい。)

となったら

- function.encodeCall(params)
- callRaw

のどちらか。前者は、paramsの形式は問題ないと思うから可能性は低い。

となったら後者。

```dart
Future<String> callRaw({
    EthereumAddress? sender,
    required EthereumAddress contract,
    required Uint8List data,
    BlockNum? atBlock,
  }) {
    final call = {
      'to': contract.hex,
      'data': bytesToHex(data, include0x: true, padToEvenLength: true),
      if (sender != null) 'from': sender.hex,
    };

    return _makeRPCCall<String>('eth_call', [call, _getBlockParam(atBlock)]);
  }
```

どうやら`makeRPCCall`でRPCノードと通信してるらしく、ここでエラーが起きた可能性が高い。

RPCノードの何かがおかしい。と思って振り返ってみると、

「`connectClient()`でendPointの指定間違えてたーーー！」

コントラクトはPolygonにデプロイしてるのに、endPointをRinkebyのやつにしてた。。

という初歩的なミスでした。

これに4時間くらいかかった。

## まとめ

1. Unhandled Exception: RangeError: Value not in range: 32が出た時は、endPointの指定を間違えていないか確認する。
2. 早い段階からエラーが起きている部分のソースコードを読む。
3. 時間かかるエラーほど初歩的なミス。

ちなみに、jsonFileが大きすぎて読み込めなくても必要な関数だけ取り出して別ファイルに書けばいい。デプロイしたコントラクトと全一致してなくてもいいっぽい。