-
Notifications
You must be signed in to change notification settings - Fork 126
/
call.ts
113 lines (98 loc) · 2.64 KB
/
call.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { useCallback, useEffect, useReducer } from 'react'
import { ContractInterface } from 'starknet'
import { useStarknetBlock } from '../providers/block'
interface State {
data?: Array<any>
loading: boolean
error?: string
lastUpdatedAt: string
}
interface SetCallResponse {
type: 'set_call_response'
data: Array<any>
}
interface SetCallError {
type: 'set_call_error'
error: string
}
interface SetLastUpdatedAt {
type: 'set_last_updated_at'
blockHash: string
}
type Action = SetCallResponse | SetCallError | SetLastUpdatedAt
function starknetCallReducer(state: State, action: Action): State {
if (action.type === 'set_call_response') {
return {
...state,
data: action.data,
error: undefined,
loading: false,
}
} else if (action.type === 'set_call_error') {
return {
...state,
error: action.error,
loading: false,
}
} else if (action.type === 'set_last_updated_at') {
return {
...state,
loading: false,
lastUpdatedAt: action.blockHash,
}
}
return state
}
interface UseStarknetCallArgs<T extends unknown[]> {
contract?: ContractInterface
method?: string
args?: T
}
export interface UseStarknetCall {
data?: Array<any>
loading: boolean
error?: string
refresh: () => void
}
export function useStarknetCall<T extends unknown[]>({
contract,
method,
args,
}: UseStarknetCallArgs<T>): UseStarknetCall {
const [state, dispatch] = useReducer(starknetCallReducer, {
loading: true,
lastUpdatedAt: '',
})
const { data: block } = useStarknetBlock()
const callContract = useCallback(async () => {
if (contract && method && args) {
return await contract.call(method, args)
}
}, [contract, method, JSON.stringify(args)])
const refresh = useCallback(() => {
callContract()
.then((response) => {
if (response) {
dispatch({ type: 'set_call_response', data: response })
}
})
.catch((err) => {
if (err.message) {
dispatch({ type: 'set_call_error', error: err.message })
} else {
dispatch({ type: 'set_call_error', error: 'call failed' })
}
})
}, [callContract])
useEffect(() => {
if (block?.block_hash && block?.block_hash !== state.lastUpdatedAt) {
refresh()
dispatch({ type: 'set_last_updated_at', blockHash: block.block_hash })
}
}, [block?.block_hash, state.lastUpdatedAt, refresh])
// always refresh on contract, method, or args change
useEffect(() => {
refresh()
}, [contract?.address, method, JSON.stringify(args)])
return { data: state.data, loading: state.loading, error: state.error, refresh }
}