@funkit/api-base 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +5 -0
- package/README.md +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/src/consts/api.d.ts +1 -0
- package/dist/src/consts/api.js +12 -0
- package/dist/src/consts/api.js.map +1 -0
- package/dist/src/consts/index.d.ts +3 -0
- package/dist/src/consts/index.js +20 -0
- package/dist/src/consts/index.js.map +1 -0
- package/dist/src/consts/request.d.ts +13 -0
- package/dist/src/consts/request.js +3 -0
- package/dist/src/consts/request.js.map +1 -0
- package/dist/src/consts/retry.d.ts +4 -0
- package/dist/src/consts/retry.js +19 -0
- package/dist/src/consts/retry.js.map +1 -0
- package/dist/src/errors/BaseError.d.ts +9 -0
- package/dist/src/errors/BaseError.js +24 -0
- package/dist/src/errors/BaseError.js.map +1 -0
- package/dist/src/errors/ClientError.d.ts +22 -0
- package/dist/src/errors/ClientError.js +76 -0
- package/dist/src/errors/ClientError.js.map +1 -0
- package/dist/src/errors/ServerError.d.ts +7 -0
- package/dist/src/errors/ServerError.js +18 -0
- package/dist/src/errors/ServerError.js.map +1 -0
- package/dist/src/errors/errors.json +626 -0
- package/dist/src/errors/index.d.ts +4 -0
- package/dist/src/errors/index.js +21 -0
- package/dist/src/errors/index.js.map +1 -0
- package/dist/src/errors/types.d.ts +60 -0
- package/dist/src/errors/types.js +51 -0
- package/dist/src/errors/types.js.map +1 -0
- package/dist/src/services/assets/endpoints.d.ts +50 -0
- package/dist/src/services/assets/endpoints.js +95 -0
- package/dist/src/services/assets/endpoints.js.map +1 -0
- package/dist/src/services/assets/index.d.ts +2 -0
- package/dist/src/services/assets/index.js +19 -0
- package/dist/src/services/assets/index.js.map +1 -0
- package/dist/src/services/assets/types.d.ts +65 -0
- package/dist/src/services/assets/types.js +3 -0
- package/dist/src/services/assets/types.js.map +1 -0
- package/dist/src/services/checkout/endpoints.d.ts +55 -0
- package/dist/src/services/checkout/endpoints.js +169 -0
- package/dist/src/services/checkout/endpoints.js.map +1 -0
- package/dist/src/services/checkout/index.d.ts +2 -0
- package/dist/src/services/checkout/index.js +19 -0
- package/dist/src/services/checkout/index.js.map +1 -0
- package/dist/src/services/checkout/types.d.ts +106 -0
- package/dist/src/services/checkout/types.js +21 -0
- package/dist/src/services/checkout/types.js.map +1 -0
- package/dist/src/services/index.d.ts +4 -0
- package/dist/src/services/index.js +21 -0
- package/dist/src/services/index.js.map +1 -0
- package/dist/src/services/mesh/endpoints.d.ts +45 -0
- package/dist/src/services/mesh/endpoints.js +129 -0
- package/dist/src/services/mesh/endpoints.js.map +1 -0
- package/dist/src/services/mesh/index.d.ts +2 -0
- package/dist/src/services/mesh/index.js +19 -0
- package/dist/src/services/mesh/index.js.map +1 -0
- package/dist/src/services/mesh/types.d.ts +56 -0
- package/dist/src/services/mesh/types.js +3 -0
- package/dist/src/services/mesh/types.js.map +1 -0
- package/dist/src/services/moonpay/endpoints.d.ts +3 -0
- package/dist/src/services/moonpay/endpoints.js +43 -0
- package/dist/src/services/moonpay/endpoints.js.map +1 -0
- package/dist/src/services/moonpay/index.d.ts +2 -0
- package/dist/src/services/moonpay/index.js +19 -0
- package/dist/src/services/moonpay/index.js.map +1 -0
- package/dist/src/services/moonpay/types.d.ts +14 -0
- package/dist/src/services/moonpay/types.js +3 -0
- package/dist/src/services/moonpay/types.js.map +1 -0
- package/dist/src/utils/checkout.d.ts +2 -0
- package/dist/src/utils/checkout.js +20 -0
- package/dist/src/utils/checkout.js.map +1 -0
- package/dist/src/utils/error.d.ts +1 -0
- package/dist/src/utils/error.js +13 -0
- package/dist/src/utils/error.js.map +1 -0
- package/dist/src/utils/index.d.ts +3 -0
- package/dist/src/utils/index.js +20 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/request.d.ts +7 -0
- package/dist/src/utils/request.js +128 -0
- package/dist/src/utils/request.js.map +1 -0
- package/dist/test/services/assets.test.d.ts +1 -0
- package/dist/test/services/assets.test.js +37 -0
- package/dist/test/services/assets.test.js.map +1 -0
- package/dist/test/services/checkout.test.d.ts +1 -0
- package/dist/test/services/checkout.test.js +42 -0
- package/dist/test/services/checkout.test.js.map +1 -0
- package/dist/test/services/mesh.test.d.ts +1 -0
- package/dist/test/services/mesh.test.js +12 -0
- package/dist/test/services/mesh.test.js.map +1 -0
- package/dist/test/services/moonpay.test.d.ts +1 -0
- package/dist/test/services/moonpay.test.js +25 -0
- package/dist/test/services/moonpay.test.js.map +1 -0
- package/dist/test/setup.d.ts +0 -0
- package/dist/test/setup.js +10 -0
- package/dist/test/setup.js.map +1 -0
- package/index.ts +4 -0
- package/package.json +37 -0
- package/src/consts/api.ts +9 -0
- package/src/consts/index.ts +3 -0
- package/src/consts/request.ts +16 -0
- package/src/consts/retry.ts +21 -0
- package/src/errors/BaseError.ts +28 -0
- package/src/errors/ClientError.ts +175 -0
- package/src/errors/ServerError.ts +43 -0
- package/src/errors/errors.json +626 -0
- package/src/errors/index.ts +4 -0
- package/src/errors/types.ts +64 -0
- package/src/services/assets/endpoints.ts +131 -0
- package/src/services/assets/index.ts +2 -0
- package/src/services/assets/types.ts +80 -0
- package/src/services/checkout/endpoints.ts +233 -0
- package/src/services/checkout/index.ts +2 -0
- package/src/services/checkout/types.ts +130 -0
- package/src/services/index.ts +4 -0
- package/src/services/mesh/endpoints.ts +164 -0
- package/src/services/mesh/index.ts +2 -0
- package/src/services/mesh/types.ts +63 -0
- package/src/services/moonpay/endpoints.ts +62 -0
- package/src/services/moonpay/index.ts +2 -0
- package/src/services/moonpay/types.ts +15 -0
- package/src/utils/checkout.ts +17 -0
- package/src/utils/error.ts +15 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/request.ts +198 -0
- package/test/services/assets.test.ts +41 -0
- package/test/services/checkout.test.ts +53 -0
- package/test/services/mesh.test.ts +10 -0
- package/test/services/moonpay.test.ts +24 -0
- package/test/setup.ts +9 -0
- package/tsconfig.json +33 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { API_BASE_URL } from '../../consts'
|
|
2
|
+
import { sendGetRequest, sendPostRequest } from '../../utils'
|
|
3
|
+
import {
|
|
4
|
+
ExecuteTransferRequest,
|
|
5
|
+
GetCryptocurrencyHoldingsRequest,
|
|
6
|
+
GetLinkTokenRequest,
|
|
7
|
+
GetLinkTokenResponse,
|
|
8
|
+
GetTransferIntegrationsRequest,
|
|
9
|
+
GetTransferIntegrationsResponse,
|
|
10
|
+
PreviewTransferRequest,
|
|
11
|
+
} from './types'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param authToken The authentication token to send the asset from.
|
|
15
|
+
* @param type The type of the integration to send the asset from.
|
|
16
|
+
* @return https://docs.meshconnect.com/reference/post_api-v1-holdings-get
|
|
17
|
+
*/
|
|
18
|
+
export async function meshGetCryptocurrencyHoldings({
|
|
19
|
+
authToken,
|
|
20
|
+
type,
|
|
21
|
+
apiKey,
|
|
22
|
+
}: GetCryptocurrencyHoldingsRequest): Promise<any> {
|
|
23
|
+
const res = await sendPostRequest({
|
|
24
|
+
uri: `${API_BASE_URL}/mesh/holdings/get`,
|
|
25
|
+
body: { authToken, type },
|
|
26
|
+
apiKey,
|
|
27
|
+
})
|
|
28
|
+
return res
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @return https://docs.meshconnect.com/reference/get_api-v1-transfers-managed-integrations
|
|
33
|
+
*/
|
|
34
|
+
export async function meshGetTransferIntegrations({
|
|
35
|
+
apiKey,
|
|
36
|
+
}: GetTransferIntegrationsRequest): Promise<GetTransferIntegrationsResponse> {
|
|
37
|
+
const res = await sendGetRequest({
|
|
38
|
+
uri: `${API_BASE_URL}/mesh/transfers/managed/integrations`,
|
|
39
|
+
apiKey,
|
|
40
|
+
})
|
|
41
|
+
return res
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param userId A unique Id representing the end user. Typically this will be a user Id from the
|
|
46
|
+
client application. Personally identifiable information, such as an email address or phone number,
|
|
47
|
+
should not be used. 50 characters length maximum.
|
|
48
|
+
* @param integrationId A unique identifier representing a specific integration obtained from the list of available integrations.
|
|
49
|
+
* @param restrictMultipleAccounts The final screen of Link allows users to “continue” back to your app or “Link another account.”
|
|
50
|
+
If this param is present then this button will be hidden.
|
|
51
|
+
* @param transferOptions Encapsulates transaction-related parameters, including destination addresses and the amount to transfer in fiat currency.
|
|
52
|
+
* @return https://docs.meshconnect.com/reference/post_api-v1-linktoken
|
|
53
|
+
*/
|
|
54
|
+
export async function meshGetLinkToken({
|
|
55
|
+
userId,
|
|
56
|
+
integrationId,
|
|
57
|
+
restrictMultipleAccounts,
|
|
58
|
+
transferOptions,
|
|
59
|
+
apiKey,
|
|
60
|
+
}: GetLinkTokenRequest): Promise<GetLinkTokenResponse> {
|
|
61
|
+
let body: any = { userId }
|
|
62
|
+
if (integrationId) {
|
|
63
|
+
body = { ...body, integrationId }
|
|
64
|
+
}
|
|
65
|
+
if (restrictMultipleAccounts) {
|
|
66
|
+
body = { ...body, restrictMultipleAccounts }
|
|
67
|
+
}
|
|
68
|
+
if (transferOptions) {
|
|
69
|
+
body = { ...body, transferOptions }
|
|
70
|
+
}
|
|
71
|
+
const res = await sendPostRequest({
|
|
72
|
+
uri: `${API_BASE_URL}/mesh/linktoken`,
|
|
73
|
+
body,
|
|
74
|
+
apiKey,
|
|
75
|
+
})
|
|
76
|
+
return res
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param fromAuthToken The authentication token to send the asset from.
|
|
81
|
+
* @param fromType The type of the integration to send the asset from.
|
|
82
|
+
* @param toAuthToken The authentication token of the target integration. Can be used alternatively to the address in the ToAddress field. If used, toType should also be provided.
|
|
83
|
+
* @param toType The type of the target integration to send assets to. Used along with the toAuthToken alternatively to ToAddress.
|
|
84
|
+
* @param networkId The network to send the asset over. This is generated by Mesh, it isn't a chainId or chain name.
|
|
85
|
+
* @param symbol The symbol of the digital asset to send.
|
|
86
|
+
* @param toAddress The target address to send the asset to.
|
|
87
|
+
* @param amount The amount to send, in crypto.
|
|
88
|
+
* @param amountInFiat The amount to send, in fiat currency. Can be used alternatively to Amount.
|
|
89
|
+
* @param fiatCurrency Fiat currency that is to get corresponding converted fiat values of transfer and fee amounts. If not provided, defaults to USD.
|
|
90
|
+
* @returns https://docs.meshconnect.com/reference/post_api-v1-transfers-managed-preview
|
|
91
|
+
*/
|
|
92
|
+
export async function meshPreviewTransfer({
|
|
93
|
+
fromAuthToken,
|
|
94
|
+
fromType,
|
|
95
|
+
toAuthToken,
|
|
96
|
+
toType,
|
|
97
|
+
networkId,
|
|
98
|
+
symbol,
|
|
99
|
+
toAddress,
|
|
100
|
+
amount,
|
|
101
|
+
amountInFiat,
|
|
102
|
+
fiatCurrency,
|
|
103
|
+
apiKey,
|
|
104
|
+
}: PreviewTransferRequest): Promise<any> {
|
|
105
|
+
let body: any = { fromAuthToken, fromType }
|
|
106
|
+
if (toAuthToken) {
|
|
107
|
+
body = { ...body, toAuthToken }
|
|
108
|
+
}
|
|
109
|
+
if (toType) {
|
|
110
|
+
body = { ...body, toType }
|
|
111
|
+
}
|
|
112
|
+
if (networkId) {
|
|
113
|
+
body = { ...body, networkId }
|
|
114
|
+
}
|
|
115
|
+
if (symbol) {
|
|
116
|
+
body = { ...body, symbol }
|
|
117
|
+
}
|
|
118
|
+
if (toAddress) {
|
|
119
|
+
body = { ...body, toAddress }
|
|
120
|
+
}
|
|
121
|
+
if (amount) {
|
|
122
|
+
body = { ...body, amount }
|
|
123
|
+
}
|
|
124
|
+
if (amountInFiat) {
|
|
125
|
+
body = { ...body, amountInFiat }
|
|
126
|
+
}
|
|
127
|
+
if (fiatCurrency) {
|
|
128
|
+
body = { ...body, fiatCurrency }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const res = await sendPostRequest({
|
|
132
|
+
uri: `${API_BASE_URL}/mesh/transfers/managed/preview`,
|
|
133
|
+
body,
|
|
134
|
+
apiKey,
|
|
135
|
+
retryOptions: { maxAttempts: 1 },
|
|
136
|
+
})
|
|
137
|
+
return res
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
*
|
|
141
|
+
* @param fromAuthToken The authentication token to send the asset from.
|
|
142
|
+
* @param fromType The type of the integration to send the asset from.
|
|
143
|
+
* @param previewId The preview ID of the transfer to execute.
|
|
144
|
+
* @param mfaCode Multi-factor auth code that should be provided if the status of the transfer was MfaRequired.
|
|
145
|
+
* @returns https://docs.meshconnect.com/reference/post_api-v1-transfers-managed-execute
|
|
146
|
+
*/
|
|
147
|
+
export async function meshExecuteTransfer({
|
|
148
|
+
fromAuthToken,
|
|
149
|
+
fromType,
|
|
150
|
+
previewId,
|
|
151
|
+
mfaCode,
|
|
152
|
+
apiKey,
|
|
153
|
+
}: ExecuteTransferRequest): Promise<any> {
|
|
154
|
+
let body: any = { fromAuthToken, fromType, previewId }
|
|
155
|
+
if (mfaCode) {
|
|
156
|
+
body = { ...body, mfaCode }
|
|
157
|
+
}
|
|
158
|
+
const res = await sendPostRequest({
|
|
159
|
+
uri: `${API_BASE_URL}/mesh/transfers/managed/execute`,
|
|
160
|
+
body,
|
|
161
|
+
apiKey,
|
|
162
|
+
})
|
|
163
|
+
return res
|
|
164
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export interface GetCryptocurrencyHoldingsRequest {
|
|
2
|
+
authToken: string
|
|
3
|
+
type: string
|
|
4
|
+
apiKey: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface GetTransferIntegrationsRequest {
|
|
8
|
+
apiKey: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface IntegrationNetworkInfo {
|
|
12
|
+
chainId: string
|
|
13
|
+
id: string
|
|
14
|
+
logoUrl: string
|
|
15
|
+
name: string
|
|
16
|
+
nativeSymbol: string
|
|
17
|
+
supportedTokens: string[]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface TransferIntegration {
|
|
21
|
+
networks: IntegrationNetworkInfo[]
|
|
22
|
+
supportsIncomingTransfers: boolean
|
|
23
|
+
supportsOutgoingTransfers: boolean
|
|
24
|
+
type: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface GetTransferIntegrationsResponse {
|
|
28
|
+
integrations: TransferIntegration[]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface GetLinkTokenRequest {
|
|
32
|
+
userId: string
|
|
33
|
+
integrationId?: string | null
|
|
34
|
+
restrictMultipleAccounts?: boolean
|
|
35
|
+
transferOptions?: any | null
|
|
36
|
+
apiKey: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface GetLinkTokenResponse {
|
|
40
|
+
linkToken: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface PreviewTransferRequest {
|
|
44
|
+
apiKey: string
|
|
45
|
+
fromAuthToken: string
|
|
46
|
+
fromType: string
|
|
47
|
+
toAuthToken?: string | null
|
|
48
|
+
toType?: string | null
|
|
49
|
+
networkId?: string
|
|
50
|
+
symbol?: string | null
|
|
51
|
+
toAddress?: string | null
|
|
52
|
+
amount?: string | null
|
|
53
|
+
amountInFiat?: string | null
|
|
54
|
+
fiatCurrency?: string | null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface ExecuteTransferRequest {
|
|
58
|
+
apiKey: string
|
|
59
|
+
fromAuthToken: string
|
|
60
|
+
fromType: string
|
|
61
|
+
previewId: string
|
|
62
|
+
mfaCode?: string | null
|
|
63
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { API_BASE_URL } from '../../consts'
|
|
2
|
+
import { ErrorCode, InternalFailureError } from '../../errors'
|
|
3
|
+
import { sendGetRequest, sendPostRequest } from '../../utils'
|
|
4
|
+
import {
|
|
5
|
+
GetMoonpayBuyQuoteForCreditCardRequest,
|
|
6
|
+
GetMoonpayUrlSignatureRequest,
|
|
7
|
+
} from './types'
|
|
8
|
+
|
|
9
|
+
export async function getMoonpayUrlSignature({
|
|
10
|
+
url,
|
|
11
|
+
isSandbox,
|
|
12
|
+
apiKey,
|
|
13
|
+
}: GetMoonpayUrlSignatureRequest): Promise<string> {
|
|
14
|
+
const signature = await sendPostRequest({
|
|
15
|
+
uri: `${API_BASE_URL}/on-ramp/moonpay-signature/`,
|
|
16
|
+
body: { url, isSandbox },
|
|
17
|
+
apiKey,
|
|
18
|
+
})
|
|
19
|
+
if (!signature || !signature?.url) {
|
|
20
|
+
throw new InternalFailureError(
|
|
21
|
+
ErrorCode.UnknownServerError,
|
|
22
|
+
'No onramp url found.',
|
|
23
|
+
{ url },
|
|
24
|
+
'This is an internal error, please contact support.',
|
|
25
|
+
'https://docs.fun.xyz',
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
return signature.url
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function getMoonpayBuyQuoteForCreditCard({
|
|
32
|
+
currencyCode,
|
|
33
|
+
baseCurrencyCode,
|
|
34
|
+
quoteCurrencyAmount,
|
|
35
|
+
baseCurrencyAmount,
|
|
36
|
+
extraFeePercentage,
|
|
37
|
+
areFeesIncluded,
|
|
38
|
+
apiKey,
|
|
39
|
+
}: GetMoonpayBuyQuoteForCreditCardRequest): Promise<any> {
|
|
40
|
+
const params = new URLSearchParams({
|
|
41
|
+
currencyCode,
|
|
42
|
+
baseCurrencyCode,
|
|
43
|
+
quoteCurrencyAmount,
|
|
44
|
+
paymentMethod: 'credit_debit_card',
|
|
45
|
+
...(baseCurrencyAmount == null
|
|
46
|
+
? {}
|
|
47
|
+
: { baseCurrencyAmount: baseCurrencyAmount.toString() }),
|
|
48
|
+
...(extraFeePercentage == null
|
|
49
|
+
? {}
|
|
50
|
+
: { extraFeePercentage: extraFeePercentage.toString() }),
|
|
51
|
+
...(areFeesIncluded == null
|
|
52
|
+
? {}
|
|
53
|
+
: { areFeesIncluded: areFeesIncluded.toString() }),
|
|
54
|
+
}).toString()
|
|
55
|
+
|
|
56
|
+
const res = await sendGetRequest({
|
|
57
|
+
uri: `${API_BASE_URL}/on-ramp/moonpay-buy-quote?${params}`,
|
|
58
|
+
apiKey,
|
|
59
|
+
retryOptions: { maxAttempts: 1 },
|
|
60
|
+
})
|
|
61
|
+
return res
|
|
62
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface GetMoonpayUrlSignatureRequest {
|
|
2
|
+
apiKey: string
|
|
3
|
+
url: string
|
|
4
|
+
isSandbox?: boolean
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface GetMoonpayBuyQuoteForCreditCardRequest {
|
|
8
|
+
apiKey: string
|
|
9
|
+
currencyCode: string
|
|
10
|
+
baseCurrencyCode: string
|
|
11
|
+
quoteCurrencyAmount: string
|
|
12
|
+
baseCurrencyAmount?: number
|
|
13
|
+
extraFeePercentage?: number
|
|
14
|
+
areFeesIncluded?: boolean
|
|
15
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { toHex } from 'viem'
|
|
2
|
+
|
|
3
|
+
const randomBytes = (length: number) => {
|
|
4
|
+
const bytes = new Uint8Array(length)
|
|
5
|
+
for (let i = 0; i < length; i++) {
|
|
6
|
+
bytes[i] = Math.floor(Math.random() * 256)
|
|
7
|
+
}
|
|
8
|
+
return toHex(bytes)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function generateRandomCheckoutSalt() {
|
|
12
|
+
return BigInt(randomBytes(32))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function roundToNearestBottomTenth(n: number) {
|
|
16
|
+
return Math.floor(n / 10) * 10
|
|
17
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InvalidParameterError,
|
|
3
|
+
ResourceNotFoundError,
|
|
4
|
+
UserOpFailureError,
|
|
5
|
+
} from '../errors'
|
|
6
|
+
|
|
7
|
+
export const errorAbortHandler = (err: any, context: any) => {
|
|
8
|
+
if (
|
|
9
|
+
err instanceof ResourceNotFoundError ||
|
|
10
|
+
err instanceof InvalidParameterError ||
|
|
11
|
+
err instanceof UserOpFailureError
|
|
12
|
+
) {
|
|
13
|
+
context.abort()
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { retry } from '@lifeomic/attempt'
|
|
2
|
+
import { toHex } from 'viem'
|
|
3
|
+
|
|
4
|
+
const fetch = (...args) =>
|
|
5
|
+
import('node-fetch').then(({ default: fetch }) => fetch(...args))
|
|
6
|
+
|
|
7
|
+
import { BaseRequest } from '../consts/request'
|
|
8
|
+
import { DEFAULT_RETRY_OPTIONS, RetryOptions } from '../consts/retry'
|
|
9
|
+
import {
|
|
10
|
+
AccessDeniedError,
|
|
11
|
+
ErrorCode,
|
|
12
|
+
InternalFailureError,
|
|
13
|
+
InvalidParameterError,
|
|
14
|
+
ResourceNotFoundError,
|
|
15
|
+
ThrottlingError,
|
|
16
|
+
UserOpFailureError,
|
|
17
|
+
} from '../errors'
|
|
18
|
+
import {
|
|
19
|
+
BaseResponse,
|
|
20
|
+
DeleteRequest,
|
|
21
|
+
GetRequest,
|
|
22
|
+
PostRequest,
|
|
23
|
+
PutRequest,
|
|
24
|
+
} from './../consts/request'
|
|
25
|
+
|
|
26
|
+
const stringifyWithBigIntSanitization = (object: any) => {
|
|
27
|
+
return JSON.stringify(
|
|
28
|
+
object,
|
|
29
|
+
(_, value) => (typeof value === 'bigint' ? toHex(value) : value), // return everything else unchanged
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const sendRequest = async ({
|
|
34
|
+
uri,
|
|
35
|
+
method,
|
|
36
|
+
apiKey,
|
|
37
|
+
body = {},
|
|
38
|
+
retryOptions = {},
|
|
39
|
+
}: BaseRequest): Promise<BaseResponse> => {
|
|
40
|
+
try {
|
|
41
|
+
const headers = {
|
|
42
|
+
'Content-Type': 'application/json',
|
|
43
|
+
...(apiKey ? { 'X-Api-Key': apiKey } : {}),
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const finalRetryOptions = {
|
|
47
|
+
...DEFAULT_RETRY_OPTIONS,
|
|
48
|
+
...(retryOptions || {}),
|
|
49
|
+
} as RetryOptions
|
|
50
|
+
|
|
51
|
+
return retry(async function () {
|
|
52
|
+
const response = await fetch(uri, {
|
|
53
|
+
method,
|
|
54
|
+
headers,
|
|
55
|
+
redirect: 'follow',
|
|
56
|
+
body:
|
|
57
|
+
method !== 'GET' ? stringifyWithBigIntSanitization(body) : undefined,
|
|
58
|
+
})
|
|
59
|
+
const json = await response.json()
|
|
60
|
+
if (response.ok) {
|
|
61
|
+
return json
|
|
62
|
+
} else if (response.status === 400) {
|
|
63
|
+
throw new InvalidParameterError(
|
|
64
|
+
ErrorCode.InvalidParameter,
|
|
65
|
+
`bad request ${JSON.stringify(json)}`,
|
|
66
|
+
{ body },
|
|
67
|
+
'check the api call parameters. its mostly because some call parameters are wrong',
|
|
68
|
+
'https://docs.fun.xyz',
|
|
69
|
+
)
|
|
70
|
+
} else if (response.status === 403) {
|
|
71
|
+
throw new AccessDeniedError(
|
|
72
|
+
ErrorCode.Unauthorized,
|
|
73
|
+
'Invalid API key or insufficient access.',
|
|
74
|
+
{ apiKey },
|
|
75
|
+
'Check your api key at https://app.fun.xyz and check with fun team if you believe something is off',
|
|
76
|
+
'https://docs.fun.xyz',
|
|
77
|
+
)
|
|
78
|
+
} else if (response.status === 404) {
|
|
79
|
+
throw new ResourceNotFoundError(
|
|
80
|
+
ErrorCode.ServerMissingData,
|
|
81
|
+
JSON.stringify(json),
|
|
82
|
+
{ body },
|
|
83
|
+
'check the api call parameters. its mostly because some call parameters are wrong',
|
|
84
|
+
'https://docs.fun.xyz',
|
|
85
|
+
)
|
|
86
|
+
} else if (response.status === 429) {
|
|
87
|
+
throw new ThrottlingError(
|
|
88
|
+
ErrorCode.RequestLimitExceeded,
|
|
89
|
+
`too many requests ${JSON.stringify(json)}`,
|
|
90
|
+
|
|
91
|
+
{ body },
|
|
92
|
+
'you are making too many requests. please slow down. Reach out to fun team if you need more quota',
|
|
93
|
+
'https://docs.fun.xyz',
|
|
94
|
+
)
|
|
95
|
+
} else if (response.status === 500) {
|
|
96
|
+
if ((json as any).errorCode === ErrorCode.UserOpFailureError) {
|
|
97
|
+
throw new UserOpFailureError(
|
|
98
|
+
ErrorCode.UserOpFailureError,
|
|
99
|
+
JSON.stringify(json),
|
|
100
|
+
{ body },
|
|
101
|
+
'fix user op failure. Most of the time this is due to invalid parameters',
|
|
102
|
+
'https://docs.fun.xyz',
|
|
103
|
+
)
|
|
104
|
+
} else {
|
|
105
|
+
throw new InternalFailureError(
|
|
106
|
+
ErrorCode.ServerFailure,
|
|
107
|
+
`server failure ${JSON.stringify(json)}`,
|
|
108
|
+
{ body },
|
|
109
|
+
'retry later. if it still fails, please contact us.',
|
|
110
|
+
'https://docs.fun.xyz',
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
} else if (response.status === 504) {
|
|
114
|
+
throw new InternalFailureError(
|
|
115
|
+
ErrorCode.ServerTimeout,
|
|
116
|
+
`server timeout failure ${JSON.stringify(json)}`,
|
|
117
|
+
{ body },
|
|
118
|
+
'retry later. if it still fails, please contact us.',
|
|
119
|
+
'https://docs.fun.xyz',
|
|
120
|
+
)
|
|
121
|
+
} else if (!response.ok) {
|
|
122
|
+
throw new InternalFailureError(
|
|
123
|
+
ErrorCode.UnknownServerError,
|
|
124
|
+
`unknown server failure ${JSON.stringify(json)}`,
|
|
125
|
+
{ body },
|
|
126
|
+
'retry later. if it still fails, please contact us.',
|
|
127
|
+
'https://docs.fun.xyz',
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
return {}
|
|
131
|
+
}, finalRetryOptions)
|
|
132
|
+
} catch (err) {
|
|
133
|
+
throw new InternalFailureError(
|
|
134
|
+
ErrorCode.ServerConnectionError,
|
|
135
|
+
`Cannot connect to Fun API Service ${err}`,
|
|
136
|
+
|
|
137
|
+
{ body },
|
|
138
|
+
'retry later. if it still fails, please contact us.',
|
|
139
|
+
'https://docs.fun.xyz',
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export async function sendGetRequest({
|
|
145
|
+
uri,
|
|
146
|
+
apiKey,
|
|
147
|
+
retryOptions,
|
|
148
|
+
}: GetRequest): Promise<BaseResponse> {
|
|
149
|
+
return await sendRequest({
|
|
150
|
+
uri,
|
|
151
|
+
apiKey,
|
|
152
|
+
retryOptions,
|
|
153
|
+
method: 'GET',
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export async function sendPostRequest({
|
|
158
|
+
uri,
|
|
159
|
+
body,
|
|
160
|
+
apiKey,
|
|
161
|
+
retryOptions,
|
|
162
|
+
}: PostRequest): Promise<BaseResponse> {
|
|
163
|
+
return await sendRequest({
|
|
164
|
+
uri,
|
|
165
|
+
apiKey,
|
|
166
|
+
body,
|
|
167
|
+
retryOptions,
|
|
168
|
+
method: 'POST',
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export async function sendDeleteRequest({
|
|
173
|
+
uri,
|
|
174
|
+
apiKey,
|
|
175
|
+
retryOptions,
|
|
176
|
+
}: DeleteRequest): Promise<void> {
|
|
177
|
+
await sendRequest({
|
|
178
|
+
uri,
|
|
179
|
+
method: 'DELETE',
|
|
180
|
+
apiKey,
|
|
181
|
+
retryOptions,
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export async function sendPutRequest({
|
|
186
|
+
uri,
|
|
187
|
+
body,
|
|
188
|
+
apiKey,
|
|
189
|
+
retryOptions,
|
|
190
|
+
}: PutRequest): Promise<BaseResponse> {
|
|
191
|
+
return await sendRequest({
|
|
192
|
+
uri,
|
|
193
|
+
apiKey,
|
|
194
|
+
body,
|
|
195
|
+
retryOptions,
|
|
196
|
+
method: 'PUT',
|
|
197
|
+
})
|
|
198
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getAllWalletTokens,
|
|
3
|
+
getAllWalletTokensByChainId,
|
|
4
|
+
getAssetPriceInfo,
|
|
5
|
+
} from '../../'
|
|
6
|
+
|
|
7
|
+
describe('assets service', () => {
|
|
8
|
+
test('getAssetPriceInfo returns valid result', async () => {
|
|
9
|
+
const assetPriceInfo = await getAssetPriceInfo({
|
|
10
|
+
chainId: '1',
|
|
11
|
+
assetTokenAddress: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
|
12
|
+
apiKey: global.TEST_API_KEY,
|
|
13
|
+
})
|
|
14
|
+
expect(assetPriceInfo.amount).toBe(1)
|
|
15
|
+
expect(assetPriceInfo.unitPrice).toBeGreaterThan(0)
|
|
16
|
+
expect(assetPriceInfo.total).toBeGreaterThan(0)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('getAllWalletTokens returns valid result', async () => {
|
|
20
|
+
const walletBalance = await getAllWalletTokens({
|
|
21
|
+
walletAddress: global.TEST_WALLET_ADDRESS,
|
|
22
|
+
onlyVerifiedTokens: true,
|
|
23
|
+
apiKey: global.TEST_API_KEY,
|
|
24
|
+
})
|
|
25
|
+
expect(walletBalance['1']).toBeTruthy()
|
|
26
|
+
expect(walletBalance['137']).toBeTruthy()
|
|
27
|
+
expect(walletBalance['8453']).toBeTruthy()
|
|
28
|
+
expect(walletBalance['324']).toBeTruthy()
|
|
29
|
+
expect(walletBalance['42161']).toBeTruthy()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('getAllWalletTokensByChainId returns valid result', async () => {
|
|
33
|
+
const ethereumBalance = await getAllWalletTokensByChainId({
|
|
34
|
+
chainId: '1',
|
|
35
|
+
walletAddress: global.TEST_WALLET_ADDRESS,
|
|
36
|
+
onlyVerifiedTokens: true,
|
|
37
|
+
apiKey: global.TEST_API_KEY,
|
|
38
|
+
})
|
|
39
|
+
expect(ethereumBalance).toBeTruthy()
|
|
40
|
+
})
|
|
41
|
+
})
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCheckoutQuote,
|
|
3
|
+
getCheckoutsByRecipientAddress,
|
|
4
|
+
initializeCheckout,
|
|
5
|
+
} from '../../'
|
|
6
|
+
|
|
7
|
+
const QUOTE_TEST_TIMEOUT = 30000 // 30 seconds
|
|
8
|
+
|
|
9
|
+
describe('checkout service', () => {
|
|
10
|
+
let quoteId: string
|
|
11
|
+
test(
|
|
12
|
+
'getCheckoutQuote and initializeCheckout returns valid result',
|
|
13
|
+
async () => {
|
|
14
|
+
const quoteParams = {
|
|
15
|
+
fromChainId: '8453',
|
|
16
|
+
fromTokenAddress:
|
|
17
|
+
'0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' as `0x${string}`,
|
|
18
|
+
fromTokenDecimals: 18,
|
|
19
|
+
toChainId: '137',
|
|
20
|
+
toTokenAddress:
|
|
21
|
+
'0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' as `0x${string}`,
|
|
22
|
+
toTokenDecimals: 18,
|
|
23
|
+
toTokenAmount: 5,
|
|
24
|
+
expirationTimestampMs: 300_000, // 5 minutes
|
|
25
|
+
sponsorInitialTransferGasLimit: '0',
|
|
26
|
+
recipientAddr: global.TEST_WALLET_ADDRESS,
|
|
27
|
+
needsRefuel: false,
|
|
28
|
+
apiKey: global.TEST_API_KEY,
|
|
29
|
+
}
|
|
30
|
+
const quote = await getCheckoutQuote(quoteParams)
|
|
31
|
+
quoteId = quote.quoteId
|
|
32
|
+
expect(quote.quoteId).toBeTruthy()
|
|
33
|
+
|
|
34
|
+
const checkoutInitParams = {
|
|
35
|
+
quoteId,
|
|
36
|
+
sourceOfFund: `balance|eoa|${global.TEST_WALLET_ADDRESS}`,
|
|
37
|
+
apiKey: global.TEST_API_KEY,
|
|
38
|
+
clientMetadata: {},
|
|
39
|
+
}
|
|
40
|
+
const depositAddr = await initializeCheckout(checkoutInitParams)
|
|
41
|
+
expect(depositAddr).toBeTruthy()
|
|
42
|
+
},
|
|
43
|
+
QUOTE_TEST_TIMEOUT,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
test('getCheckoutsByRecipientAddress returns valid result', async () => {
|
|
47
|
+
const checkouts = await getCheckoutsByRecipientAddress({
|
|
48
|
+
recipientAddress: global.TEST_WALLET_ADDRESS,
|
|
49
|
+
apiKey: global.TEST_API_KEY,
|
|
50
|
+
})
|
|
51
|
+
expect(checkouts.length).toBeGreaterThan(0)
|
|
52
|
+
})
|
|
53
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { meshGetTransferIntegrations } from '../../'
|
|
2
|
+
|
|
3
|
+
describe('mesh service', () => {
|
|
4
|
+
test('meshGetTransferIntegrations returns valid result', async () => {
|
|
5
|
+
const integrationsResponse = await meshGetTransferIntegrations({
|
|
6
|
+
apiKey: global.TEST_API_KEY,
|
|
7
|
+
})
|
|
8
|
+
expect(integrationsResponse.integrations.length).toBeGreaterThan(0)
|
|
9
|
+
})
|
|
10
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getMoonpayBuyQuoteForCreditCard, getMoonpayUrlSignature } from '../../'
|
|
2
|
+
|
|
3
|
+
describe('moonpay service', () => {
|
|
4
|
+
test('getMoonpayUrlSignature returns valid result', async () => {
|
|
5
|
+
const urlSignature = await getMoonpayUrlSignature({
|
|
6
|
+
apiKey: global.TEST_API_KEY,
|
|
7
|
+
isSandbox: true,
|
|
8
|
+
url: 'https://buy.moonpay.com/?apiKey=pk_test_dWfAhBbvVexIId9S5hPd78mKM7ivIsqu¤cyCode=usdc&walletAddress=0x931122fD30c218e208A3546A3faa2f40F6c06A3e&colorCode=%2331a3f8&theme=light&baseCurrencyCode=usd"eCurrencyAmount=106.23&lockAmount=true&externalCustomerId=0x6ec0c2f25d323e7779925Cc20c3740101f990d9F%7C0x6ec0c2f25d323e7779925Cc20c3740101f990d9F%7CgsWiq9zk0W5Rh4vzpqURI6nyauFL0tSm9m0EydTI&mpSdk=%7B%22version%22%3A%221.8.0%22%2C%22environment%22%3A%22production%22%2C%22flow%22%3A%22buy%22%2C%22variant%22%3A%22embedded%22%2C%22platform%22%3A%22web%22%7D',
|
|
9
|
+
})
|
|
10
|
+
expect(urlSignature).toBeTruthy()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('getMoonpayBuyQuoteForCreditCard returns valid result', async () => {
|
|
14
|
+
const buyQuote = await getMoonpayBuyQuoteForCreditCard({
|
|
15
|
+
apiKey: global.TEST_API_KEY,
|
|
16
|
+
baseCurrencyCode: 'usd',
|
|
17
|
+
currencyCode: 'usdc',
|
|
18
|
+
quoteCurrencyAmount: '106.23',
|
|
19
|
+
areFeesIncluded: true,
|
|
20
|
+
})
|
|
21
|
+
expect(buyQuote.accountId).toBeTruthy()
|
|
22
|
+
expect(buyQuote.baseCurrencyCode).toBe('usd')
|
|
23
|
+
})
|
|
24
|
+
})
|
package/test/setup.ts
ADDED