Summary
Before users sign any Soroban transaction, the Astera frontend should simulate the transaction and display the estimated gas cost (in XLM). Currently, users have no way to know the cost until the Freighter wallet shows the fee — at which point they've already invested time in filling out forms.
Desired Behavior
On any action form (create invoice, deposit, fund invoice, repay), after the user has filled in all fields:
- Frontend calls `sorobanRpc.simulateTransaction()` to get the compute units
- Estimated fee shown below the submit button:
```
Estimated network fee: ~0.00123 XLM
[Sign & Submit]
```
- If simulation fails (e.g., insufficient collateral), show the error inline before the user signs
Implementation
```ts
// frontend/hooks/useTransactionSimulation.ts
export function useTransactionSimulation(operation: xdr.Operation) {
return useQuery({
queryKey: ['simulate', operation],
queryFn: async () => {
const server = new SorobanRpc.Server(horizonUrl);
const result = await server.simulateTransaction(buildTx(operation));
if (SorobanRpc.Api.isSimulationError(result)) throw new Error(result.error);
return result;
},
enabled: !!operation,
});
}
```
Acceptance Criteria
References
- `frontend/components/` — form components
- Soroban RPC: `simulateTransaction()`
Summary
Before users sign any Soroban transaction, the Astera frontend should simulate the transaction and display the estimated gas cost (in XLM). Currently, users have no way to know the cost until the Freighter wallet shows the fee — at which point they've already invested time in filling out forms.
Desired Behavior
On any action form (create invoice, deposit, fund invoice, repay), after the user has filled in all fields:
```
Estimated network fee: ~0.00123 XLM
[Sign & Submit]
```
Implementation
```ts
// frontend/hooks/useTransactionSimulation.ts
export function useTransactionSimulation(operation: xdr.Operation) {
return useQuery({
queryKey: ['simulate', operation],
queryFn: async () => {
const server = new SorobanRpc.Server(horizonUrl);
const result = await server.simulateTransaction(buildTx(operation));
if (SorobanRpc.Api.isSimulationError(result)) throw new Error(result.error);
return result;
},
enabled: !!operation,
});
}
```
Acceptance Criteria
References