@monerium/sdk 3.4.11 → 4.0.0
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/README.md +348 -308
- package/dist/index.d.ts +956 -504
- package/dist/index.js +6 -6
- package/dist/index.mjs +6 -6
- package/package.json +3 -4
package/README.md
CHANGED
|
@@ -5,27 +5,27 @@
|
|
|
5
5
|
|
|
6
6
|
<a href="https://docs.monerium.com">
|
|
7
7
|
<picture>
|
|
8
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/badge/Developer_portal-2c6ca7"
|
|
9
|
-
<img src="https://img.shields.io/badge/Developer_portal-2c6ca7" alt="Static Badge"
|
|
8
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/badge/Developer_portal-2c6ca7"/>
|
|
9
|
+
<img src="https://img.shields.io/badge/Developer_portal-2c6ca7" alt="Static Badge"/>
|
|
10
10
|
</picture>
|
|
11
11
|
</a>
|
|
12
12
|
<a href="https://docs.monerium.com/api">
|
|
13
13
|
<picture>
|
|
14
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/badge/API_documentation-2c6ca7"
|
|
15
|
-
<img src="https://img.shields.io/badge/API_documentation-2c6ca7" alt="Static Badge"
|
|
14
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/badge/API_documentation-2c6ca7"/>
|
|
15
|
+
<img src="https://img.shields.io/badge/API_documentation-2c6ca7" alt="Static Badge"/>
|
|
16
16
|
</picture>
|
|
17
17
|
</a>
|
|
18
|
-
<br
|
|
18
|
+
<br/><br/>
|
|
19
19
|
<a href="https://www.npmjs.com/package/@monerium/sdk">
|
|
20
20
|
<picture>
|
|
21
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/v/%40monerium%2Fsdk?colorA=2c6ca7&colorB=21262d"
|
|
22
|
-
<img src="https://img.shields.io/npm/v/%40monerium%2Fsdk?colorA=f6f8fa&colorB=f6f8fa" alt="Version"
|
|
21
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/v/%40monerium%2Fsdk?colorA=2c6ca7&colorB=21262d"/>
|
|
22
|
+
<img src="https://img.shields.io/npm/v/%40monerium%2Fsdk?colorA=f6f8fa&colorB=f6f8fa" alt="Version"/>
|
|
23
23
|
</picture>
|
|
24
24
|
</a>
|
|
25
25
|
<a href="https://github.com/monerium/js-monorepo/issues">
|
|
26
26
|
<picture>
|
|
27
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/issues/monerium/js-monorepo?colorA=2c6ca7&colorB=21262d"
|
|
28
|
-
<img src="https://img.shields.io/github/issues/monerium/js-monorepo?colorA=2c6ca7&colorB=21262d" alt="Version"
|
|
27
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/issues/monerium/js-monorepo?colorA=2c6ca7&colorB=21262d"/>
|
|
28
|
+
<img src="https://img.shields.io/github/issues/monerium/js-monorepo?colorA=2c6ca7&colorB=21262d" alt="Version"/>
|
|
29
29
|
</picture>
|
|
30
30
|
</a>
|
|
31
31
|
|
|
@@ -36,342 +36,396 @@ All incoming euro payments are automatically minted as EURe tokens to your walle
|
|
|
36
36
|
Sending EURe to traditional bank accounts is just as easy.
|
|
37
37
|
With a single signature from your wallet, your EURe is burned and sent as Euros to any bank account.
|
|
38
38
|
|
|
39
|
-
## Documentation
|
|
40
|
-
|
|
41
|
-
- [Documentation](../../apps/developer/docs/packages/SDK/index.md)
|
|
42
|
-
- [Documentation - MoneriumClient](../../apps/developer/docs/packages/SDK/classes/MoneriumClient.md)
|
|
43
|
-
|
|
44
|
-
## Table of Contents
|
|
45
|
-
|
|
46
|
-
- [Installation](#installation)
|
|
47
|
-
- [Configuration](#configuration)
|
|
48
|
-
- [Usage Examples](#usage-examples)
|
|
49
|
-
- [API Reference](#api-reference)
|
|
50
|
-
- [Contributing](#contributing)
|
|
51
|
-
- [FAQs](#faqs)
|
|
52
|
-
- [Support](#support)
|
|
53
|
-
- [Release Notes](#release-notes)
|
|
54
|
-
- [License](#license)
|
|
55
|
-
|
|
56
39
|
## Installation
|
|
57
40
|
|
|
58
|
-
### Prerequisites
|
|
59
|
-
|
|
60
|
-
Node v16.15 or higher is required.
|
|
61
|
-
|
|
62
41
|
```sh
|
|
63
|
-
|
|
42
|
+
pnpm add @monerium/sdk
|
|
64
43
|
```
|
|
65
44
|
|
|
66
|
-
##
|
|
67
|
-
|
|
68
|
-
### Environments - URLs
|
|
45
|
+
## Usage Patterns
|
|
69
46
|
|
|
70
|
-
|
|
71
|
-
| ----------- | ---------------------------- | ------------------------ |
|
|
72
|
-
| sandbox | https://sandbox.monerium.app | https://api.monerium.dev |
|
|
73
|
-
| production | https://monerium.app | https://api.monerium.app |
|
|
47
|
+
This section demonstrates how to use the plan-specific client classes (`MoneriumPrivateClient`, `MoneriumWhitelabelClient`, and `MoneriumOAuthClient`) for the integration flows.
|
|
74
48
|
|
|
75
|
-
###
|
|
49
|
+
### 1. Private Plan
|
|
76
50
|
|
|
77
|
-
|
|
78
|
-
| ----------- | -------- | -------- |
|
|
79
|
-
| sandbox | ethereum | sepolia |
|
|
80
|
-
| | polygon | mumbai |
|
|
81
|
-
| | gnosis | chiado |
|
|
82
|
-
| | linea | sepolia |
|
|
83
|
-
| | scroll | sepolia |
|
|
84
|
-
| | camino | columbus |
|
|
85
|
-
| production | ethereum | mainnet |
|
|
86
|
-
| | polygon | mainnet |
|
|
87
|
-
| | gnosis | mainnet |
|
|
88
|
-
| | linea | mainnet |
|
|
89
|
-
| | scroll | mainnet |
|
|
90
|
-
| | camino | mainnet |
|
|
51
|
+
[Read the Private Integration Guide](https://docs.monerium.com/private)
|
|
91
52
|
|
|
92
|
-
|
|
53
|
+
The Private plan gives you direct API access to your own Monerium account.
|
|
54
|
+
You use `MoneriumPrivateClient` for Server-to-Server communication.
|
|
93
55
|
|
|
94
|
-
|
|
56
|
+
Instead of manually passing static access tokens, the recommended approach is to provide a `getAccessToken` callback. This allows the client to dynamically retrieve, cache, and refresh tokens seamlessly across all requests using a single global client instance.
|
|
95
57
|
|
|
96
|
-
|
|
58
|
+
```typescript
|
|
59
|
+
import { MoneriumPrivateClient, Currency } from '@monerium/sdk';
|
|
97
60
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
```ts
|
|
101
|
-
import { MoneriumClient } from '@monerium/sdk';
|
|
102
|
-
// Initialize the client with credentials
|
|
103
|
-
const monerium = new MoneriumClient({
|
|
61
|
+
// 1. Initialize the client ONCE globally
|
|
62
|
+
const client: MoneriumPrivateClient = new MoneriumPrivateClient({
|
|
104
63
|
environment: 'sandbox',
|
|
105
|
-
|
|
106
|
-
|
|
64
|
+
getAccessToken: async () => {
|
|
65
|
+
// a. Check in-memory cache
|
|
66
|
+
let token = memoryCache.get('monerium_token');
|
|
67
|
+
|
|
68
|
+
// b. Fallback to Database
|
|
69
|
+
if (!token) {
|
|
70
|
+
token = await db.getToken();
|
|
71
|
+
if (token) memoryCache.set('monerium_token', token);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// c. If token is missing or expired, fetch a new one
|
|
75
|
+
if (!token || isExpired(token)) {
|
|
76
|
+
// clientCredentialsGrant does not require authentication
|
|
77
|
+
const auth = await client.clientCredentialsGrant('YOUR_CLIENT_ID', 'YOUR_CLIENT_SECRET');
|
|
78
|
+
token = auth.access_token;
|
|
79
|
+
|
|
80
|
+
memoryCache.set('monerium_token', token);
|
|
81
|
+
await db.saveToken(token);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return token;
|
|
85
|
+
}
|
|
107
86
|
});
|
|
108
87
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
API documentation:
|
|
122
|
-
|
|
123
|
-
- [/auth/token](https://docs.monerium.com/api#operation/auth-token)
|
|
124
|
-
|
|
125
|
-
#### Initialize and authenticate using Authorization Code Flow with PKCE
|
|
126
|
-
|
|
127
|
-
> Authorization Code Flow with PKCE is used for apps where direct user interaction is involved, and the application is running on an environment where the confidentiality of a secret cannot be safely maintained. It allows the application to authorize users without handling their passwords and mitigates the additional risk involved in this sort of delegation.
|
|
128
|
-
|
|
129
|
-
First, you have to navigate the user to the Monerium authentication flow. This can be done by generating a URL and redirecting the user to it. After the user has authenticated, Monerium will redirect back to your specified URI with a code. You can then finalize the authentication process by exchanging the code for access and refresh tokens.
|
|
130
|
-
|
|
131
|
-
```ts
|
|
132
|
-
import { MoneriumClient } from '@monerium/sdk';
|
|
133
|
-
|
|
134
|
-
export function App() {
|
|
135
|
-
const [profiles, setProfiles] = useState<Profile[] | null>(null);
|
|
136
|
-
const [monerium, setMonerium] = useState<MoneriumClient>();
|
|
137
|
-
const [isAuthorized, setIsAuthorized] = useState<boolean>(false);
|
|
138
|
-
|
|
139
|
-
useEffect(() => {
|
|
140
|
-
const sdk = new MoneriumClient({
|
|
141
|
-
environment: 'sandbox',
|
|
142
|
-
clientId: 'f99e629b-6dca-11ee-8aa6-5273f65ed05b',
|
|
143
|
-
redirectUri: 'http://localhost:4200',
|
|
88
|
+
// 2. Set up Webhooks (One-off initialization)
|
|
89
|
+
async function setupWebhooks() {
|
|
90
|
+
const { subscriptions } = await client.getSubscriptions();
|
|
91
|
+
const webhookUrl = 'https://your-app.com/webhooks/monerium';
|
|
92
|
+
|
|
93
|
+
if (!subscriptions.some(sub => sub.url === webhookUrl)) {
|
|
94
|
+
await client.createSubscription({
|
|
95
|
+
url: webhookUrl,
|
|
96
|
+
secret: 'whsec_YOUR_BASE64_ENCODED_SECRET',
|
|
97
|
+
types: ['order.created', 'order.updated']
|
|
144
98
|
});
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
useEffect(() => {
|
|
149
|
-
const connect = async () => {
|
|
150
|
-
if (monerium) {
|
|
151
|
-
setIsAuthorized(await monerium.getAccess());
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
connect();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
156
101
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
102
|
+
async function runPrivateFlow() {
|
|
103
|
+
// 3. Link a Wallet
|
|
104
|
+
const { addresses } = await client.getAddresses();
|
|
105
|
+
if (!addresses.some(a => a.address === '0xYourAddress...')) {
|
|
106
|
+
await client.linkAddress({
|
|
107
|
+
address: '0xYourAddress...',
|
|
108
|
+
message: 'I hereby declare that I am the address owner.',
|
|
109
|
+
signature: '0xYourSignature...',
|
|
110
|
+
chain: 'ethereum'
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 4. Send payments (Place an Order)
|
|
115
|
+
// Check if profile and IBAN are approved before placing an order
|
|
116
|
+
const profiles = await client.getProfiles();
|
|
117
|
+
const defaultProfile = profiles.profiles[0];
|
|
118
|
+
const { ibans } = await client.getIbans();
|
|
119
|
+
const activeIban = ibans.find(i => i.state === 'approved');
|
|
120
|
+
|
|
121
|
+
if (defaultProfile?.state === 'approved' && activeIban) {
|
|
122
|
+
await client.placeOrder({
|
|
123
|
+
address: '0xYourAddress...',
|
|
124
|
+
chain: 'ethereum',
|
|
125
|
+
amount: '100.00',
|
|
126
|
+
signature: '0xYourSignature...',
|
|
127
|
+
currency: Currency.eur,
|
|
128
|
+
counterpart: {
|
|
129
|
+
identifier: {
|
|
130
|
+
standard: 'iban',
|
|
131
|
+
iban: 'YOUR_IBAN',
|
|
132
|
+
bic: 'YOUR_BIC'
|
|
133
|
+
},
|
|
134
|
+
details: {
|
|
135
|
+
firstName: 'John',
|
|
136
|
+
lastName: 'Doe',
|
|
137
|
+
country: 'IS'
|
|
172
138
|
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return (
|
|
179
|
-
<div>
|
|
180
|
-
{!isAuthorized && <button onClick={() => monerium?.authorize()}>Connect</button>}
|
|
181
|
-
|
|
182
|
-
<p>{profiles[0]?.name}</p>
|
|
183
|
-
</div>
|
|
184
|
-
);
|
|
139
|
+
},
|
|
140
|
+
message: 'Payment for services'
|
|
141
|
+
});
|
|
142
|
+
}
|
|
185
143
|
}
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
API documentation:
|
|
189
|
-
|
|
190
|
-
- [/auth](https://docs.monerium.com/api#operation/auth)
|
|
191
|
-
- [/auth/token](https://docs.monerium.com/api#operation/auth-token)
|
|
192
|
-
|
|
193
|
-
#### Get account information
|
|
194
|
-
|
|
195
|
-
```ts
|
|
196
|
-
// Get all profiles
|
|
197
|
-
const { profiles }: Profile[] = await monerium.getProfiles();
|
|
198
|
-
|
|
199
|
-
// Fetching all accounts for a specific profile
|
|
200
|
-
const { id: profileId, accounts }: Profile = await monerium.getProfile(
|
|
201
|
-
profiles[0].id
|
|
202
|
-
);
|
|
203
144
|
|
|
204
|
-
//
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
145
|
+
// 5. Handle Webhooks (e.g., in your Express route)
|
|
146
|
+
async function handleMoneriumWebhook(event: any) {
|
|
147
|
+
// Automatically provision IBAN when the profile is approved
|
|
148
|
+
if (event.type === 'profile.updated' && event.meta?.state === 'approved') {
|
|
149
|
+
const { ibans } = await client.getIbans();
|
|
150
|
+
|
|
151
|
+
if (ibans.length > 0) {
|
|
152
|
+
if (!ibans.some(i => i.address === '0xYourAddress...' && i.chain === 'ethereum')) {
|
|
153
|
+
await client.moveIban({
|
|
154
|
+
iban: ibans[0].iban,
|
|
155
|
+
address: '0xYourAddress...',
|
|
156
|
+
chain: 'ethereum'
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
await client.requestIban({
|
|
161
|
+
address: '0xYourAddress...',
|
|
162
|
+
chain: 'ethereum'
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (event.type === 'order.updated') {
|
|
168
|
+
console.log('Order status changed:', event.meta?.state);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
219
171
|
```
|
|
220
172
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
- [/tokens](https://docs.monerium.com/api#operation/tokens)
|
|
224
|
-
|
|
225
|
-
#### Link a new address to Monerium
|
|
226
|
-
|
|
227
|
-
It's important to understand when interacting with a blockchain, the user needs to provide a signature in their wallet.
|
|
228
|
-
This signature is used to verify that the user is the owner of the wallet address.
|
|
173
|
+
### 2. Whitelabel Plan
|
|
229
174
|
|
|
230
|
-
|
|
175
|
+
[Read the Whitelabel Integration Guide](https://docs.monerium.com/whitelabel)
|
|
231
176
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
import { constants } from '@monerium/sdk';
|
|
235
|
-
import { walletClient } from '...' // See Viem documentation
|
|
177
|
+
Embed regulated euro accounts and SEPA payments in your product under your own brand.
|
|
178
|
+
You use `MoneriumWhitelabelClient` to manage profiles on behalf of your customers.
|
|
236
179
|
|
|
237
|
-
|
|
180
|
+
Similar to the Private plan, use the `getAccessToken` pattern for efficient, secure server-to-server authentication.
|
|
238
181
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
message: LINK_MESSAGE,
|
|
242
|
-
})
|
|
243
|
-
|
|
244
|
-
// Link a new address to Monerium and create accounts for ethereum and gnosis.
|
|
245
|
-
await monerium.linkAddress({
|
|
246
|
-
profile: 'your-profile-id',
|
|
247
|
-
address: '0xUserAddress72413Fa92980B889A1eCE84dD', // user wallet address
|
|
248
|
-
message: LINK_MESSAGE
|
|
249
|
-
signature,
|
|
250
|
-
chain: 'ethereum',
|
|
251
|
-
} as LinkAddress);
|
|
252
|
-
```
|
|
182
|
+
```typescript
|
|
183
|
+
import { MoneriumWhitelabelClient } from '@monerium/sdk';
|
|
253
184
|
|
|
254
|
-
|
|
185
|
+
// 1. Initialize the client ONCE globally
|
|
186
|
+
const client: MoneriumWhitelabelClient = new MoneriumWhitelabelClient({
|
|
187
|
+
environment: 'sandbox',
|
|
188
|
+
getAccessToken: async () => {
|
|
189
|
+
let token = memoryCache.get('monerium_token');
|
|
190
|
+
|
|
191
|
+
if (!token) {
|
|
192
|
+
token = await db.getToken();
|
|
193
|
+
if (token) memoryCache.set('monerium_token', token);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (!token || isExpired(token)) {
|
|
197
|
+
const auth = await client.clientCredentialsGrant('YOUR_CLIENT_ID', 'YOUR_CLIENT_SECRET');
|
|
198
|
+
token = auth.access_token;
|
|
199
|
+
|
|
200
|
+
memoryCache.set('monerium_token', token);
|
|
201
|
+
await db.saveToken(token);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return token;
|
|
205
|
+
}
|
|
206
|
+
});
|
|
255
207
|
|
|
256
|
-
-
|
|
208
|
+
// 2. Set up Webhooks (One-off initialization, listen for profile approvals)
|
|
209
|
+
async function setupWebhooks() {
|
|
210
|
+
const { subscriptions } = await client.getSubscriptions();
|
|
211
|
+
const webhookUrl = 'https://your-app.com/webhooks/monerium';
|
|
212
|
+
|
|
213
|
+
if (!subscriptions.some(sub => sub.url === webhookUrl)) {
|
|
214
|
+
await client.createSubscription({
|
|
215
|
+
url: webhookUrl,
|
|
216
|
+
secret: 'whsec_YOUR_BASE64_ENCODED_SECRET',
|
|
217
|
+
types: ['profile.updated', 'iban.updated', 'order.created', 'order.updated']
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
257
221
|
|
|
258
|
-
|
|
222
|
+
async function runWhitelabelFlow() {
|
|
223
|
+
// 3. Onboard the customer (Create a Profile)
|
|
224
|
+
const profile = await client.createProfile({
|
|
225
|
+
kind: 'personal'
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// 4. Submit identity data (e.g., via Sumsub integration)
|
|
229
|
+
// await client.shareProfileKYC({ ... });
|
|
230
|
+
|
|
231
|
+
// 5. Link a Wallet
|
|
232
|
+
const { addresses } = await client.getAddresses({ profile: profile.id });
|
|
233
|
+
if (!addresses.some(a => a.address === '0xCustomerAddress...')) {
|
|
234
|
+
await client.linkAddress({
|
|
235
|
+
profile: profile.id,
|
|
236
|
+
address: '0xCustomerAddress...',
|
|
237
|
+
message: 'I hereby declare that I am the address owner.',
|
|
238
|
+
signature: '0xCustomerSignature...',
|
|
239
|
+
chain: 'polygon'
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 6. Send/Receive Payments
|
|
244
|
+
// Check if profile and IBAN are approved before interacting
|
|
245
|
+
const currentProfile = await client.getProfile(profile.id);
|
|
246
|
+
const { ibans } = await client.getIbans({ profile: profile.id });
|
|
247
|
+
const activeIban = ibans.find(i => i.state === 'approved');
|
|
248
|
+
|
|
249
|
+
if (currentProfile.state === 'approved' && activeIban) {
|
|
250
|
+
// Monerium handles incoming SEPA payments automatically once the IBAN is active.
|
|
251
|
+
// You can also place outgoing orders here using client.placeOrder()
|
|
252
|
+
}
|
|
253
|
+
}
|
|
259
254
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
255
|
+
// 7. Handle Webhooks (e.g., in your Express route)
|
|
256
|
+
async function handleMoneriumWebhook(event: any) {
|
|
257
|
+
// Automatically provision IBAN when the profile is approved
|
|
258
|
+
if (event.type === 'profile.updated' && event.meta?.state === 'approved') {
|
|
259
|
+
const profileId = event.meta?.profile;
|
|
260
|
+
const { ibans } = await client.getIbans({ profile: profileId });
|
|
261
|
+
|
|
262
|
+
if (ibans.length > 0) {
|
|
263
|
+
if (!ibans.some(i => i.address === '0xCustomerAddress...' && i.chain === 'polygon')) {
|
|
264
|
+
await client.moveIban({
|
|
265
|
+
iban: ibans[0].iban,
|
|
266
|
+
address: '0xCustomerAddress...',
|
|
267
|
+
chain: 'polygon'
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
} else {
|
|
271
|
+
await client.requestIban({
|
|
272
|
+
address: '0xCustomerAddress...',
|
|
273
|
+
chain: 'polygon'
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (event.type === 'iban.updated') {
|
|
279
|
+
console.log('IBAN state changed for profile:', event.meta?.profile);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
263
282
|
```
|
|
264
283
|
|
|
265
|
-
|
|
266
|
-
// Place a redeem order
|
|
267
|
-
import { placeOrderMessage } from '@monerium/sdk';
|
|
268
|
-
import { walletClient } from '...'; // See Viem documentation
|
|
284
|
+
### 3. OAuth Plan
|
|
269
285
|
|
|
270
|
-
|
|
271
|
-
const iban = 'EE12341234123412341234'; // replace with requested IBAN
|
|
286
|
+
[Read the OAuth Integration Guide](https://docs.monerium.com/oauth)
|
|
272
287
|
|
|
273
|
-
|
|
274
|
-
|
|
288
|
+
The OAuth flow lets users authorize your application to access their Monerium account.
|
|
289
|
+
You use `MoneriumOAuthClient` as it is safe for both browser and server environments (it does not contain `clientCredentialsGrant`).
|
|
275
290
|
|
|
276
|
-
|
|
277
|
-
// Send EUR 100 to EE12341234123412341234 at Thu, 29 Dec 2022 14:58:29Z
|
|
291
|
+
When managing multiple users, you can also use `getAccessToken` to fetch the specific user's token from your database and refresh it automatically via `refreshTokenGrant` if it expires.
|
|
278
292
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
message: message,
|
|
282
|
-
});
|
|
293
|
+
```typescript
|
|
294
|
+
import { MoneriumOAuthClient, generatePKCE } from '@monerium/sdk';
|
|
283
295
|
|
|
284
|
-
//
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
network: 'sepolia',
|
|
305
|
-
// supportingDocumentId, see below
|
|
296
|
+
// 1. Initialize the client (Browser or Server)
|
|
297
|
+
const client: MoneriumOAuthClient = new MoneriumOAuthClient({
|
|
298
|
+
environment: 'sandbox',
|
|
299
|
+
getAccessToken: async () => {
|
|
300
|
+
// Fetch the authenticated user's access token from your database/session
|
|
301
|
+
let { accessToken, refreshToken, expiresAt } = await db.getUserTokens(userId);
|
|
302
|
+
|
|
303
|
+
// If expired, refresh it automatically using the OAuth client
|
|
304
|
+
if (Date.now() >= expiresAt) {
|
|
305
|
+
const auth = await client.refreshTokenGrant({
|
|
306
|
+
clientId: 'YOUR_CLIENT_ID',
|
|
307
|
+
refreshToken: refreshToken
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
accessToken = auth.access_token;
|
|
311
|
+
await db.saveUserTokens(userId, auth);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return accessToken;
|
|
315
|
+
}
|
|
306
316
|
});
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
API documentation:
|
|
310
317
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
318
|
+
// --- Server or Client: Initiate login ---
|
|
319
|
+
async function initiateAuth() {
|
|
320
|
+
const { codeChallenge, codeVerifier } = generatePKCE();
|
|
321
|
+
// Store `codeVerifier` in a secure, server-side session or cookie
|
|
322
|
+
// session.set('pkce_verifier', codeVerifier);
|
|
323
|
+
|
|
324
|
+
const authUrl = client.buildAuthorizationUrl({
|
|
325
|
+
clientId: 'YOUR_CLIENT_ID',
|
|
326
|
+
redirectUri: 'https://your-app.com/callback',
|
|
327
|
+
codeChallenge: codeChallenge,
|
|
328
|
+
state: 'random_state_string'
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// Redirect user to the returned URL...
|
|
332
|
+
// (e.g., `window.location.assign(authUrl)` on the client, or `redirect(authUrl)` on the server)
|
|
333
|
+
}
|
|
315
334
|
|
|
316
|
-
|
|
335
|
+
// --- Server: Handle Callback ---
|
|
336
|
+
// Exchanging the code requires a secure backend endpoint
|
|
337
|
+
async function handleAuthCallback(requestUrl: string) {
|
|
338
|
+
// 1. Parse Authorization Response
|
|
339
|
+
const { code } = client.parseAuthorizationResponse(requestUrl);
|
|
340
|
+
|
|
341
|
+
// 2. Retrieve the stored verifier
|
|
342
|
+
// const storedVerifier = session.get('pkce_verifier');
|
|
343
|
+
|
|
344
|
+
// 3. Exchange code for tokens
|
|
345
|
+
const tokens = await client.authorizationCodeGrant({
|
|
346
|
+
clientId: 'YOUR_CLIENT_ID',
|
|
347
|
+
redirectUri: 'https://your-app.com/callback',
|
|
348
|
+
code: code!,
|
|
349
|
+
codeVerifier: 'STORED_CODE_VERIFIER'
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// 4. Save `tokens` to your database associated with the user
|
|
353
|
+
await db.saveUserTokens(userId, tokens);
|
|
354
|
+
}
|
|
317
355
|
|
|
318
|
-
|
|
319
|
-
//
|
|
320
|
-
const
|
|
321
|
-
|
|
356
|
+
async function runOAuthUserFlow() {
|
|
357
|
+
// 5. Link a Wallet
|
|
358
|
+
const { addresses } = await client.getAddresses();
|
|
359
|
+
if (!addresses.some(a => a.address === '0xUserAddress...')) {
|
|
360
|
+
await client.linkAddress({
|
|
361
|
+
address: '0xUserAddress...',
|
|
362
|
+
message: 'I hereby declare that I am the address owner.',
|
|
363
|
+
signature: '0xUserSignature...',
|
|
364
|
+
chain: 'arbitrum'
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// 6. Check if Profile & IBAN are approved
|
|
369
|
+
const profiles = await client.getProfiles();
|
|
370
|
+
const defaultProfile = profiles.profiles[0];
|
|
371
|
+
const { ibans } = await client.getIbans();
|
|
372
|
+
const activeIban = ibans.find(i => i.state === 'approved');
|
|
373
|
+
|
|
374
|
+
if (defaultProfile?.state === 'approved' && activeIban) {
|
|
375
|
+
// 7. Get user's balances
|
|
376
|
+
const balances = await client.getBalances({
|
|
377
|
+
address: '0xUserAddress...',
|
|
378
|
+
chain: 'arbitrum'
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
console.log(balances);
|
|
382
|
+
|
|
383
|
+
// You can also place orders here safely!
|
|
384
|
+
} else if (defaultProfile?.state === 'approved' && !activeIban) {
|
|
385
|
+
// Automatically issue/move the IBAN if the profile is approved but the IBAN is not ready
|
|
386
|
+
if (ibans.length > 0) {
|
|
387
|
+
if (!ibans.some(i => i.address === '0xUserAddress...' && i.chain === 'arbitrum')) {
|
|
388
|
+
await client.moveIban({
|
|
389
|
+
iban: ibans[0].iban,
|
|
390
|
+
address: '0xUserAddress...',
|
|
391
|
+
chain: 'arbitrum'
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
} else {
|
|
395
|
+
await client.requestIban({
|
|
396
|
+
address: '0xUserAddress...',
|
|
397
|
+
chain: 'arbitrum'
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
322
402
|
```
|
|
323
403
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
- [/files](https://docs.monerium.com/api#operation/supporting-document)
|
|
404
|
+
### 4. Custom Transport
|
|
327
405
|
|
|
328
|
-
|
|
406
|
+
_Inject custom logic (retries, logging, proxies) by replacing the default fetch implementation._
|
|
329
407
|
|
|
330
408
|
```ts
|
|
331
|
-
import {
|
|
332
|
-
const [orderState, setOrderState] = useState<OrderState>();
|
|
409
|
+
import { MoneriumOAuthClient } from '@monerium/sdk';
|
|
333
410
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
profile: 'my-profile-id',
|
|
411
|
+
const api = new MoneriumOAuthClient({
|
|
412
|
+
environment: 'sandbox',
|
|
413
|
+
getAccessToken: async () => '...',
|
|
414
|
+
transport: async ({ method, url, headers, body }) => {
|
|
415
|
+
console.log(`Calling ${method} ${url}`);
|
|
416
|
+
const res = await fetch(url, { method, headers, body });
|
|
417
|
+
return { status: res.status, bodyText: await res.text() };
|
|
342
418
|
},
|
|
343
|
-
// optional callback functions
|
|
344
|
-
onMessage: (order) => console.log(order)
|
|
345
|
-
onError: (error) => console.error(error)
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
// Unsubscribe from specific order events
|
|
349
|
-
monerium.unsubscribeOrderNotifications({
|
|
350
|
-
state: OrderState.pending,
|
|
351
|
-
profile: 'my-profile-id'
|
|
352
419
|
});
|
|
353
|
-
// Unsubscribe from all order events
|
|
354
|
-
monerium.unsubscribeOrderNotifications();
|
|
355
|
-
|
|
356
420
|
```
|
|
357
421
|
|
|
358
422
|
## API Reference
|
|
359
423
|
|
|
360
|
-
[API Documentation](https://docs.monerium.com
|
|
424
|
+
[API Documentation](https://docs.monerium.com/api)
|
|
361
425
|
|
|
362
426
|
## Contributing
|
|
363
427
|
|
|
364
|
-
We are using
|
|
365
|
-
|
|
366
|
-
We are using PNPM as a package manager.
|
|
367
|
-
|
|
368
|
-
#### Development mode
|
|
369
|
-
|
|
370
|
-
```
|
|
371
|
-
pnpm dev
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
While in development mode, TypeScript declaration maps (`.d.ts.map`) are generated. TypeScript declaration maps are mainly used to quickly jump to type definitions in the context of a monorepo.
|
|
428
|
+
We are using PNPM as a package manager and [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) standard.
|
|
375
429
|
|
|
376
430
|
#### Build
|
|
377
431
|
|
|
@@ -379,26 +433,12 @@ While in development mode, TypeScript declaration maps (`.d.ts.map`) are generat
|
|
|
379
433
|
pnpm build
|
|
380
434
|
```
|
|
381
435
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
Refer to [Typedocs](https://typedoc.org/) syntaxes to use for this [documentation](https://monerium.github.io/js-monorepo/).
|
|
385
|
-
|
|
386
|
-
#### Publishing
|
|
387
|
-
|
|
388
|
-
When changes are merged to the `main` branch that follows the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) standard, [release-please](https://github.com/googleapis/release-please) workflow creates a pull request, preparing for the next release. If kept open, the following commits will also be added to the PR. Merging that PR will create a new release, a workflow will publish it on NPM and tag it on Github.
|
|
389
|
-
|
|
390
|
-
## FAQs
|
|
436
|
+
#### Test
|
|
391
437
|
|
|
392
|
-
|
|
438
|
+
```
|
|
439
|
+
pnpm test
|
|
440
|
+
```
|
|
393
441
|
|
|
394
442
|
## Support
|
|
395
443
|
|
|
396
|
-
[Support](https://monerium.app/help)
|
|
397
|
-
|
|
398
|
-
[Telegram](https://t.me/+lGtM1gY9zWthNGE8)
|
|
399
|
-
|
|
400
|
-
[Github Issues](https://github.com/monerium/js-monorepo/issues)
|
|
401
|
-
|
|
402
|
-
## Release Notes
|
|
403
|
-
|
|
404
|
-
https://github.com/monerium/js-monorepo/releases
|
|
444
|
+
[Support](https://monerium.app/help) | [Github Issues](https://github.com/monerium/js-monorepo/issues)
|