register method

Future<Transaction> register(
  1. WriteBlobFlowRegisterOptions options
)

Step 2: Build the register transaction.

Returns an unsigned Transaction for external signing.

If options.walCoinObjectId is provided along with cost info, uses proper WAL payment via WalrusTransactionBuilder.registerBlobWithWal.

When WriteBlobFlowRegisterOptions.walCoinObjectId is not provided and a SuiClient + SystemStateReader are available (the default when created via WalrusDirectClient.writeBlobFlow), the flow automatically finds a WAL coin with sufficient balance for the owner.

For convenience, if _stateReader is available and WAL cost info is not provided, this method auto-resolves costs from chain state.

Implementation

Future<Transaction> register(WriteBlobFlowRegisterOptions options) async {
  if (_step != _FlowStep.encoded) {
    throw StateError('Must call encode() before register()');
  }

  _deletable = options.deletable;
  final metadata = _metadata!;

  final tx = Transaction();
  tx.setSenderIfNotSet(options.owner);

  // Add upload relay tip if configured.
  if (_relayClient != null && _tipConfig != null) {
    final tipConfig = _tipConfig;
    _txBuilder.sendUploadRelayTip(
      size: _blob.length,
      blobDigest: metadata.blobDigest,
      nonce: metadata.nonce,
      tipConfig: tipConfig,
      transaction: tx,
    );
  }

  // Resolve WAL payment parameters.
  String? walCoinObjectId = options.walCoinObjectId;
  String? walType = options.walType;
  BigInt? storageCost = options.storageCost;
  BigInt? writeCost = options.writeCost;
  int? encodedSize = options.encodedSize;

  // Auto-resolve from chain if state reader is available.
  if (_stateReader != null &&
      (walType == null ||
          storageCost == null ||
          writeCost == null ||
          encodedSize == null)) {
    walType ??= await _stateReader.getWalType();
    final costs = await _stateReader.storageCost(
      _blob.length,
      options.epochs,
    );
    storageCost ??= costs.storageCost;
    writeCost ??= costs.writeCost;
    final state = await _stateReader.systemState();
    encodedSize ??= encodedBlobLength(_blob.length, state.nShards);
  }

  // Auto-resolve WAL coin when not provided.
  if (walCoinObjectId == null &&
      _suiClient != null &&
      walType != null &&
      storageCost != null &&
      writeCost != null) {
    final totalWalNeeded = storageCost + writeCost;
    final coins = await _suiClient.getCoins(options.owner, coinType: walType);
    final coinList = coins.data as List?;
    if (coinList != null) {
      for (final coin in coinList) {
        final balance =
            BigInt.tryParse(coin.balance as String) ?? BigInt.zero;
        if (balance >= totalWalNeeded) {
          walCoinObjectId = coin.coinObjectId as String?;
          break;
        }
      }
    }
  }

  // Register the blob on-chain with WAL payment.
  if (walCoinObjectId != null &&
      walType != null &&
      storageCost != null &&
      writeCost != null &&
      encodedSize != null) {
    _txBuilder.registerBlobWithWal(
      RegisterBlobOptions(
        size: _blob.length,
        epochs: options.epochs,
        blobId: metadata.blobId,
        rootHash: metadata.rootHash,
        deletable: options.deletable,
        owner: options.owner,
      ),
      walCoinObjectId: walCoinObjectId,
      walType: walType,
      storageCost: storageCost,
      writeCost: writeCost,
      encodedSize: encodedSize,
      transaction: tx,
    );
  } else {
    throw StateError(
      'WAL payment requires a WAL coin with sufficient balance. '
      'Either provide walCoinObjectId explicitly, or ensure a SuiClient '
      'and SystemStateReader are available for auto-resolution. '
      'Resolved: walCoinObjectId=$walCoinObjectId, walType=$walType, '
      'storageCost=$storageCost, writeCost=$writeCost, encodedSize=$encodedSize',
    );
  }

  _step = _FlowStep.registered;
  return tx;
}