Unhandled Exception: RangeError: Value not in range: 32
解決策
結論から言うと、
RPCノードに接続するときのendPointを確かめる。
これに至った経緯を知りたい方は続きを。
コード
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とかに設定しているから、まあ当たり前か。
やったこと② ネットで記事を探してみる
あえて文献は載せないけど、
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の
return function.decodeReturnValues(encodedResult);
でエラーが起きててなぜかデコードできてない。その前を見ると、
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の形式は問題ないと思うから可能性は低い。
となったら後者。
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時間くらいかかった。
まとめ
- Unhandled Exception: RangeError: Value not in range: 32が出た時は、endPointの指定を間違えていないか確認する。
- 早い段階からエラーが起きている部分のソースコードを読む。
- 時間かかるエラーほど初歩的なミス。
ちなみに、jsonFileが大きすぎて読み込めなくても必要な関数だけ取り出して別ファイルに書けばいい。デプロイしたコントラクトと全一致してなくてもいいっぽい。