Skip to content

Commit

Permalink
fix: transaction callbacks (#1473)
Browse files Browse the repository at this point in the history
  • Loading branch information
alessey authored Oct 22, 2024
1 parent 706d0c1 commit acd0970
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 49 deletions.
2 changes: 2 additions & 0 deletions playground/nextjs-app-router/components/AppProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export enum TransactionTypes {
Contracts = 'contracts',
CallsPromise = 'callsPromise',
ContractsPromise = 'contractsPromise',
CallsCallback = 'callsCallback',
ContractsCallback = 'contractsCallback',
}

export type Paymaster = {
Expand Down
90 changes: 56 additions & 34 deletions playground/nextjs-app-router/components/demo/Transaction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,24 @@ function TransactionDemo() {
resolve(contracts);
}, 4000);
}) as Promise<ContractFunctionParameters[]>;
const callsCallback = useCallback(
() =>
new Promise((resolve) => {
setTimeout(() => {
resolve(calls);
}, 4000);
}) as Promise<Call[]>,
[calls],
);
const contractsCallback = useCallback(
() =>
new Promise((resolve) => {
setTimeout(() => {
resolve(contracts);
}, 4000);
}) as Promise<ContractFunctionParameters[]>,
[contracts],
);
useEffect(() => {
console.log('Playground.Transaction.chainId:', chainId);
}, [chainId]);
Expand All @@ -49,46 +67,50 @@ function TransactionDemo() {
case TransactionTypes.Contracts:
console.log('Playground.Transaction.contracts:', contracts);
break;
case TransactionTypes.CallsPromise:
console.log('Playground.Transaction.callsPromise');
break;
case TransactionTypes.ContractsPromise:
console.log('Playground.Transaction.contractsPromise');
default:
console.log(`Playground.Transaction.${transactionType}`);
break;
}
}, [transactionType, calls, contracts]);

const transactions = useMemo(() => {
if (transactionType === TransactionTypes.Calls) {
return {
calls,
contracts: undefined,
};
}

if (transactionType === TransactionTypes.Contracts) {
return {
calls: undefined,
contracts,
};
}

if (transactionType === TransactionTypes.CallsPromise) {
return {
calls: promiseCalls,
contracts: undefined,
};
}

if (transactionType === TransactionTypes.ContractsPromise) {
return {
contracts: promiseContracts,
calls: undefined,
};
switch (transactionType) {
case TransactionTypes.Calls:
return {
calls,
contracts: undefined,
};
case TransactionTypes.Contracts:
return {
calls: undefined,
contracts,
};
case TransactionTypes.CallsPromise:
return {
calls: promiseCalls,
contracts: undefined,
};
case TransactionTypes.ContractsPromise:
return {
contracts: promiseContracts,
calls: undefined,
};
case TransactionTypes.CallsCallback:
return { calls: callsCallback, contracts: undefined };
case TransactionTypes.ContractsCallback:
return { calls: undefined, contracts: contractsCallback };
default:
return { calls: undefined, contracts: undefined };
}

return { calls: undefined, contracts: undefined };
}, [calls, promiseCalls, contracts, promiseContracts, transactionType]);
}, [
calls,
callsCallback,
promiseCalls,
contracts,
contractsCallback,
promiseContracts,
transactionType,
]);

return (
<div className="mx-auto grid w-1/2 gap-8">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ export function TransactionOptions() {
<SelectItem value={TransactionTypes.ContractsPromise}>
Contracts Promise
</SelectItem>
<SelectItem value={TransactionTypes.CallsCallback}>
Calls Callback
</SelectItem>
<SelectItem value={TransactionTypes.ContractsCallback}>
Contracts Callback
</SelectItem>
</SelectContent>
</Select>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/transaction/components/TransactionProvider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ describe('TransactionProvider', () => {
sendWalletTransactionsMock,
);
const onErrorMock = vi.fn();
const contracts = Promise.reject(new Error('error'));
const contracts = () => Promise.reject(new Error('error'));
render(
<TransactionProvider contracts={contracts} onError={onErrorMock}>
<TestComponent />
Expand Down
4 changes: 3 additions & 1 deletion src/transaction/components/TransactionProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,9 @@ export function TransactionProvider({
statusData: null,
});
try {
const resolvedTransactions = await Promise.resolve(transactions);
const resolvedTransactions = await (typeof transactions === 'function'
? transactions()
: Promise.resolve(transactions));
setTransactionCount(resolvedTransactions?.length);
return resolvedTransactions;
} catch (err) {
Expand Down
24 changes: 11 additions & 13 deletions src/transaction/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,7 @@ export type TransactionContextType = {
setIsToastVisible: (isVisible: boolean) => void; // A function to set the visibility of the transaction toast.
setLifecycleStatus: (state: LifecycleStatus) => void; // A function to set the lifecycle status of the component
setTransactionId: (id: string) => void; // A function to set the transaction ID.
transactions?:
| Call[]
| ContractFunctionParameters[]
| Promise<Call[]>
| Promise<ContractFunctionParameters[]>; // An array of transactions for the component or a promise that resolves to an array of transactions.
transactions?: Calls | Contracts; // An array of transactions for the component or a promise that resolves to an array of transactions.
transactionId?: string; // An optional string representing the ID of the transaction.
transactionHash?: string; // An optional string representing the hash of the transaction.
};
Expand Down Expand Up @@ -133,14 +129,18 @@ export type TransactionError = {
message: string; // The error message providing details about the transaction error.
};

type Calls = Call[] | Promise<Call[]> | (() => Promise<Call[]>);
type Contracts =
| ContractFunctionParameters[]
| Promise<ContractFunctionParameters[]>
| (() => Promise<ContractFunctionParameters[]>);

export type TransactionProviderReact = {
calls?: Call[] | Promise<Call[]>; // An array of calls for the transaction. Mutually exclusive with the `contracts` prop.
calls?: Calls; // An array of calls to be made in the transaction. Mutually exclusive with the `contracts` prop.
capabilities?: WalletCapabilities; // Capabilities that a wallet supports (e.g. paymasters, session keys, etc).
chainId: number; // The chainId for the transaction.
children: ReactNode; // The child components to be rendered within the provider component.
contracts?:
| ContractFunctionParameters[]
| Promise<ContractFunctionParameters[]>; // An array of contract function parameters provided to the child components. Mutually exclusive with the `calls` prop.
contracts?: Contracts; // An array of contract function parameters provided to the child components. Mutually exclusive with the `calls` prop.
onError?: (e: TransactionError) => void; // An optional callback function that handles errors within the provider.
onStatus?: (lifecycleStatus: LifecycleStatus) => void; // An optional callback function that exposes the component lifecycle state
onSuccess?: (response: TransactionResponse) => void; // An optional callback function that exposes the transaction receipts
Expand All @@ -150,14 +150,12 @@ export type TransactionProviderReact = {
* Note: exported as public Type
*/
export type TransactionReact = {
calls?: Call[] | Promise<Call[]>; // An array of calls to be made in the transaction. Mutually exclusive with the `contracts` prop.
calls?: Calls; // An array of calls to be made in the transaction. Mutually exclusive with the `contracts` prop.
capabilities?: WalletCapabilities; // Capabilities that a wallet supports (e.g. paymasters, session keys, etc).
chainId?: number; // The chainId for the transaction.
children: ReactNode; // The child components to be rendered within the transaction component.
className?: string; // An optional CSS class name for styling the component.
contracts?:
| ContractFunctionParameters[]
| Promise<ContractFunctionParameters[]>; // An array of contract function parameters for the transaction. Mutually exclusive with the `calls` prop.
contracts?: Contracts; // An array of contract function parameters provided to the child components. Mutually exclusive with the `calls` prop.
onError?: (e: TransactionError) => void; // An optional callback function that handles transaction errors.
onStatus?: (lifecycleStatus: LifecycleStatus) => void; // An optional callback function that exposes the component lifecycle state
onSuccess?: (response: TransactionResponse) => void; // An optional callback function that exposes the transaction receipts
Expand Down

0 comments on commit acd0970

Please sign in to comment.