feat(grants-create): add configurable grant authorization fields

This commit is contained in:
hdbg
2026-03-29 00:13:45 +01:00
parent 59c7091cba
commit b5507e7d0f
2 changed files with 102 additions and 25 deletions

View File

@@ -5,6 +5,10 @@ import 'package:arbiter/screens/dashboard/evm/grants/create/grants/ether_transfe
import 'package:arbiter/screens/dashboard/evm/grants/create/grants/grant_form_handler.dart';
import 'package:arbiter/screens/dashboard/evm/grants/create/grants/token_transfer_grant.dart';
import 'package:arbiter/screens/dashboard/evm/grants/create/provider.dart';
import 'package:arbiter/screens/dashboard/evm/grants/create/fields/chain_id_field.dart';
import 'package:arbiter/screens/dashboard/evm/grants/create/fields/gas_fee_options_field.dart';
import 'package:arbiter/screens/dashboard/evm/grants/create/fields/transaction_rate_limit_field.dart';
import 'package:arbiter/screens/dashboard/evm/grants/create/fields/validity_window_field.dart';
import 'package:arbiter/screens/dashboard/evm/grants/create/shared_grant_fields.dart';
import 'package:arbiter/screens/dashboard/evm/grants/create/utils.dart';
import 'package:arbiter/theme/palette.dart';
@@ -101,8 +105,64 @@ class CreateEvmGrantScreen extends HookConsumerWidget {
const _IntroCard(),
SizedBox(height: 1.8.h),
const _Section(
title: 'Shared grant options',
child: SharedGrantFields(),
title: 'Authorization',
tooltip: 'Select which SDK client receives this grant and '
'which of its wallet accesses it applies to.',
child: AuthorizationFields(),
),
SizedBox(height: 1.8.h),
IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Expanded(
child: _Section(
title: 'Chain',
tooltip: 'Restrict this grant to a specific EVM chain ID. '
'Leave empty to allow any chain.',
optional: true,
child: ChainIdField(),
),
),
SizedBox(width: 1.8.w),
const Expanded(
child: _Section(
title: 'Timing',
tooltip: 'Set an optional validity window. '
'Signing requests outside this period will be rejected.',
optional: true,
child: ValidityWindowField(),
),
),
],
),
),
SizedBox(height: 1.8.h),
IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Expanded(
child: _Section(
title: 'Gas limits',
tooltip: 'Cap the gas fees this grant may authorize. '
'Transactions exceeding these values will be rejected.',
optional: true,
child: GasFeeOptionsField(),
),
),
SizedBox(width: 1.8.w),
const Expanded(
child: _Section(
title: 'Transaction limits',
tooltip: 'Limit how many transactions can be signed '
'within a rolling time window.',
optional: true,
child: TransactionRateLimitField(),
),
),
],
),
),
SizedBox(height: 1.8.h),
_GrantTypeSelector(
@@ -112,6 +172,8 @@ class CreateEvmGrantScreen extends HookConsumerWidget {
SizedBox(height: 1.8.h),
_Section(
title: 'Grant-specific options',
tooltip: 'Rules specific to the selected transfer type. '
'Switch between Ether and token above to change these fields.',
child: handler.buildForm(context, ref),
),
SizedBox(height: 2.2.h),
@@ -175,13 +237,21 @@ class _IntroCard extends StatelessWidget {
}
class _Section extends StatelessWidget {
const _Section({required this.title, required this.child});
const _Section({
required this.title,
required this.tooltip,
required this.child,
this.optional = false,
});
final String title;
final String tooltip;
final Widget child;
final bool optional;
@override
Widget build(BuildContext context) {
final subtleColor = Theme.of(context).colorScheme.outline;
return Container(
padding: EdgeInsets.all(2.h),
decoration: BoxDecoration(
@@ -191,6 +261,8 @@ class _Section extends StatelessWidget {
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
title,
@@ -198,6 +270,26 @@ class _Section extends StatelessWidget {
fontWeight: FontWeight.w800,
),
),
SizedBox(width: 0.4.w),
Tooltip(
message: tooltip,
child: Icon(
Icons.info_outline_rounded,
size: 16,
color: subtleColor,
),
),
if (optional) ...[
SizedBox(width: 0.6.w),
Text(
'(optional)',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: subtleColor,
),
),
],
],
),
SizedBox(height: 1.4.h),
child,
],

View File

@@ -1,19 +1,11 @@
// lib/screens/dashboard/evm/grants/create/shared_grant_fields.dart
import 'package:arbiter/screens/dashboard/evm/grants/create/fields/chain_id_field.dart';
import 'package:arbiter/screens/dashboard/evm/grants/create/fields/client_picker_field.dart';
import 'package:arbiter/screens/dashboard/evm/grants/create/fields/gas_fee_options_field.dart';
import 'package:arbiter/screens/dashboard/evm/grants/create/fields/transaction_rate_limit_field.dart';
import 'package:arbiter/screens/dashboard/evm/grants/create/fields/validity_window_field.dart';
import 'package:arbiter/screens/dashboard/evm/grants/create/fields/wallet_access_picker_field.dart';
import 'package:flutter/material.dart';
import 'package:sizer/sizer.dart';
/// All shared grant fields in a single vertical layout.
///
/// Every [FormBuilderField] descendant auto-registers with the nearest
/// [FormBuilder] ancestor via [BuildContext] — no controllers passed.
class SharedGrantFields extends StatelessWidget {
const SharedGrantFields({super.key});
class AuthorizationFields extends StatelessWidget {
const AuthorizationFields({super.key});
@override
Widget build(BuildContext context) {
@@ -23,15 +15,8 @@ class SharedGrantFields extends StatelessWidget {
const ClientPickerField(),
SizedBox(height: 1.6.h),
const WalletAccessPickerField(),
SizedBox(height: 1.6.h),
const ChainIdField(),
SizedBox(height: 1.6.h),
const ValidityWindowField(),
SizedBox(height: 1.6.h),
const GasFeeOptionsField(),
SizedBox(height: 1.6.h),
const TransactionRateLimitField(),
],
);
}
}