normalizeInputs method
Implementation
Future<void> normalizeInputs(BuildOptions options) async {
final inputs = _blockData.inputs;
final commands = _blockData.commands;
final moveCallsToResolve = [];
final moveFunctionsToResolve = <String>{};
for (var command in commands) {
if (command["MoveCall"] != null) {
// Determine if any of the arguments require encoding.
// - If they don't, then this is good to go.
// - If they do, then we need to fetch the normalized move module.
// If we already know the argument types, we don't need to resolve them again
if (command["MoveCall"]?["_argumentTypes"] != null) {
continue;
}
final inputs = (command["MoveCall"]["arguments"] as Iterable).map((
arg,
) {
if (arg is Map && arg["Input"] != null) {
return _blockData.inputs[arg["Input"]];
}
return null;
}).toList();
final needsResolution = inputs.firstWhere(
(input) =>
input?["UnresolvedPure"] != null ||
input?["UnresolvedObject"] != null,
orElse: () => null,
);
if (needsResolution != null) {
final functionName =
"${command["MoveCall"]["package"]}::${command["MoveCall"]["module"]}::${command["MoveCall"]["function"]}";
moveFunctionsToResolve.add(functionName);
moveCallsToResolve.add(command["MoveCall"]);
}
}
// Special handling for values that where previously encoded using the wellKnownEncoding pattern.
// This should only happen when transaction data was hydrated from an old version of the SDK
if (command["SplitCoins"] != null) {
command["SplitCoins"]["amounts"].forEach((amount) {
normalizeRawArgument(amount, SuiBcs.U64);
});
} else if (command["TransferObjects"] != null) {
normalizeRawArgument(
command["TransferObjects"]["address"],
SuiBcs.Address,
);
}
}
final moveFunctionParameters = <String, List<dynamic>>{};
if (moveFunctionsToResolve.isNotEmpty) {
final client = expectClient(options);
await Future.wait(
[...moveFunctionsToResolve].map((functionName) async {
final [packageId, moduleId, functionId] = functionName.split('::');
final def = await client.getNormalizedMoveFunction(
packageId,
moduleId,
functionId,
);
moveFunctionParameters[functionName] = def.parameters
.map((param) => normalizedTypeToMoveTypeSignature(param))
.toList();
}),
);
}
if (moveCallsToResolve.isNotEmpty) {
for (var moveCall in moveCallsToResolve) {
final parameters =
moveFunctionParameters["${moveCall["package"]}::${moveCall["module"]}::${moveCall["function"]}"];
if (parameters != null && parameters.isNotEmpty) {
// Entry functions can have a mutable reference to an instance of the TxContext
// struct defined in the TxContext module as the last parameter. The caller of
// the function does not need to pass it in as an argument.
final hasTxContext = isTxContext(parameters.last!);
final params = hasTxContext
? parameters.sublist(0, parameters.length - 1)
: parameters;
moveCall["_argumentTypes"] = params;
}
}
}
for (var command in commands) {
if (command["MoveCall"] == null) {
continue;
}
final moveCall = command["MoveCall"];
final fnName =
"${moveCall["package"]}::${moveCall["module"]}::${moveCall["function"]}";
final params = moveCall["_argumentTypes"];
if (params == null) {
continue;
}
if (params.length != command["MoveCall"]["arguments"].length) {
throw ArgumentError("Incorrect number of arguments for $fnName");
}
final callArgs = moveCall["arguments"].toList();
for (var i = 0; i < params.length; i++) {
final param = params[i];
final arg = callArgs[i];
if (arg["Input"] == null) continue;
final input = inputs[arg["Input"]];
// Skip if the input is already resolved
if (input["UnresolvedPure"] == null &&
input["UnresolvedObject"] == null) {
continue;
}
final inputValue =
input["UnresolvedPure"]?["value"] ??
input["UnresolvedObject"]?["objectId"];
final schema = getPureBcsSchema(param["body"]);
if (schema != null) {
arg["type"] = 'pure';
inputs[inputs.indexOf(input)] = Inputs.pure(
schema.serialize(inputValue),
);
continue;
}
if (inputValue is! String) {
throw ArgumentError(
"Expect the argument to be an object id string, got $inputValue",
);
}
arg["type"] = 'object';
final unresolvedObject = input["UnresolvedPure"] != null
? {
"UnresolvedObject": {"objectId": inputValue},
}
: input;
inputs[arg["Input"]] = unresolvedObject;
}
}
}