-
Notifications
You must be signed in to change notification settings - Fork 149
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
26 changed files
with
577 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@starknet-react/core': minor | ||
--- | ||
|
||
Add transaction manager |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
export { StarknetBlockProvider, useStarknetBlock } from './providers/block' | ||
export { StarknetProvider, useStarknet } from './providers/starknet' | ||
export { useStarknetBlock } from './providers/block' | ||
export { useStarknet } from './providers/starknet' | ||
export { useStarknetTransactionManager } from './providers/transaction' | ||
export type { Transaction } from './providers/transaction' | ||
export { StarknetProvider } from './providers' | ||
export * from './hooks' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import React from 'react' | ||
import { StarknetBlockProvider } from './block' | ||
import { StarknetTransactionManagerProvider } from './transaction' | ||
import { StarknetLibraryProvider } from './starknet' | ||
|
||
interface StarknetProviderProps { | ||
children?: React.ReactNode | ||
} | ||
|
||
export function StarknetProvider({ children }: StarknetProviderProps): JSX.Element { | ||
return ( | ||
<StarknetLibraryProvider> | ||
<StarknetBlockProvider> | ||
<StarknetTransactionManagerProvider>{children}</StarknetTransactionManagerProvider> | ||
</StarknetBlockProvider> | ||
</StarknetLibraryProvider> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { createContext, useContext } from 'react' | ||
|
||
import { StarknetTransactionManager, TRANSACTION_MANAGER_INITIAL_STATE } from './model' | ||
|
||
export const TransactionManagerContext = createContext<StarknetTransactionManager>( | ||
TRANSACTION_MANAGER_INITIAL_STATE | ||
) | ||
|
||
export function useStarknetTransactionManager(): StarknetTransactionManager { | ||
return useContext(TransactionManagerContext) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './context' | ||
export * from './model' | ||
export * from './provider' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { Status, TransactionStatus, Transaction as StarknetTransaction } from 'starknet' | ||
|
||
export interface TransactionSubmitted { | ||
status: TransactionStatus | ||
transactionHash: string | ||
address?: string | ||
} | ||
|
||
export interface TransactionReceived { | ||
status: Status | ||
transaction: StarknetTransaction | ||
transactionHash: string | ||
lastUpdatedAt: number | ||
} | ||
|
||
export type Transaction = TransactionSubmitted | TransactionReceived | ||
|
||
export interface StarknetTransactionManager { | ||
transactions: Transaction[] | ||
addTransaction: (transaction: TransactionSubmitted) => void | ||
removeTransaction: (transactionHash: string) => void | ||
refreshTransaction: (transactionHash: string) => void | ||
} | ||
|
||
export const TRANSACTION_MANAGER_INITIAL_STATE: StarknetTransactionManager = { | ||
transactions: [], | ||
addTransaction: (_transaction) => undefined, | ||
removeTransaction: (_transactionHash) => undefined, | ||
refreshTransaction: (_transactionHash) => undefined, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import React, { useCallback, useEffect, useReducer } from 'react' | ||
import { List } from 'immutable' | ||
import { useStarknet } from '../starknet' | ||
import { TransactionManagerContext } from './context' | ||
import { Transaction, TransactionSubmitted } from './model' | ||
import { transactionManagerReducer } from './reducer' | ||
|
||
function shouldRefreshTransaction(transaction: Transaction, now: number): boolean { | ||
// try to get transaction data as soon as possible | ||
if (transaction.status === 'TRANSACTION_RECEIVED') { | ||
return true | ||
} | ||
|
||
// wont' be updated anymore | ||
if (transaction.status === 'ACCEPTED_ON_L1' || transaction.status === 'REJECTED') { | ||
return false | ||
} | ||
|
||
// every couple of minutes is enough. Blocks finalized infrequently. | ||
if (transaction.status === 'ACCEPTED_ON_L2') { | ||
return now - transaction.lastUpdatedAt > 120000 | ||
} | ||
|
||
return now - transaction.lastUpdatedAt > 15000 | ||
} | ||
|
||
interface StarknetTransactionManagerProviderProps { | ||
children: React.ReactNode | ||
interval?: number | ||
} | ||
|
||
export function StarknetTransactionManagerProvider({ | ||
children, | ||
interval, | ||
}: StarknetTransactionManagerProviderProps): JSX.Element { | ||
const { library } = useStarknet() | ||
|
||
const [state, dispatch] = useReducer(transactionManagerReducer, { | ||
transactions: List<Transaction>(), | ||
}) | ||
|
||
const refresh = useCallback( | ||
async (transactionHash: string) => { | ||
try { | ||
const transactionResponse = await library.getTransaction(transactionHash) | ||
const lastUpdatedAt = Date.now() | ||
dispatch({ type: 'update_transaction', transactionResponse, lastUpdatedAt }) | ||
} catch (err) { | ||
// TODO(fra): somehow should track the error | ||
console.error(err) | ||
} | ||
}, | ||
[library, dispatch] | ||
) | ||
|
||
const refreshAllTransactions = useCallback(() => { | ||
const now = Date.now() | ||
for (const transaction of state.transactions) { | ||
if (shouldRefreshTransaction(transaction, now)) { | ||
refresh(transaction.transactionHash) | ||
} | ||
} | ||
}, [state.transactions, refresh]) | ||
|
||
const addTransaction = useCallback( | ||
(transaction: TransactionSubmitted) => { | ||
dispatch({ type: 'add_transaction', transaction }) | ||
}, | ||
[dispatch] | ||
) | ||
|
||
const removeTransaction = useCallback( | ||
(transactionHash: string) => { | ||
dispatch({ type: 'remove_transaction', transactionHash }) | ||
}, | ||
[dispatch] | ||
) | ||
|
||
const refreshTransaction = useCallback( | ||
(transactionHash: string) => { | ||
refresh(transactionHash) | ||
}, | ||
[refresh] | ||
) | ||
|
||
// periodically refresh all transactions. | ||
// do this more often than once per block since there are | ||
// different stages of "accepted" transactions. | ||
useEffect(() => { | ||
refreshAllTransactions() | ||
const intervalId = setInterval(() => { | ||
refreshAllTransactions() | ||
}, interval ?? 5000) | ||
return () => clearInterval(intervalId) | ||
}, [interval, refreshAllTransactions]) | ||
|
||
return ( | ||
<TransactionManagerContext.Provider | ||
value={{ | ||
transactions: state.transactions.toArray(), | ||
addTransaction, | ||
removeTransaction, | ||
refreshTransaction, | ||
}} | ||
> | ||
{children} | ||
</TransactionManagerContext.Provider> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { GetTransactionResponse } from 'starknet' | ||
import { List } from 'immutable' | ||
import { Transaction, TransactionSubmitted } from './model' | ||
|
||
export interface TransactionManagerState { | ||
transactions: List<Transaction> | ||
} | ||
|
||
interface AddTransaction { | ||
type: 'add_transaction' | ||
transaction: TransactionSubmitted | ||
} | ||
|
||
interface RemoveTransaction { | ||
type: 'remove_transaction' | ||
transactionHash: string | ||
} | ||
|
||
interface UpdateTransaction { | ||
type: 'update_transaction' | ||
transactionResponse: GetTransactionResponse | ||
lastUpdatedAt: number | ||
} | ||
|
||
export type Action = AddTransaction | RemoveTransaction | UpdateTransaction | ||
|
||
export function transactionManagerReducer( | ||
state: TransactionManagerState, | ||
action: Action | ||
): TransactionManagerState { | ||
if (action.type === 'add_transaction') { | ||
return { | ||
...state, | ||
transactions: state.transactions.push(action.transaction), | ||
} | ||
} else if (action.type === 'remove_transaction') { | ||
return { | ||
...state, | ||
transactions: state.transactions.filter( | ||
(tx) => tx.transactionHash !== action.transactionHash | ||
), | ||
} | ||
} else if (action.type === 'update_transaction') { | ||
if (action.transactionResponse.status === 'NOT_RECEIVED') { | ||
return state | ||
} | ||
|
||
const entry = state.transactions.findEntry( | ||
(tx) => tx.transactionHash === action.transactionResponse.transaction['transaction_hash'] | ||
) | ||
|
||
if (!entry) { | ||
return state | ||
} | ||
|
||
const [transactionIndex, _oldTransaction] = entry | ||
|
||
const newTransaction: Transaction = { | ||
status: action.transactionResponse.status, | ||
transaction: action.transactionResponse.transaction, | ||
transactionHash: action.transactionResponse.transaction['transaction_hash'], | ||
lastUpdatedAt: action.lastUpdatedAt, | ||
} | ||
|
||
return { | ||
...state, | ||
transactions: state.transactions.set(transactionIndex, newTransaction), | ||
} | ||
} | ||
|
||
return state | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.