dhali-js 3.0.4 → 3.1.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/.github/workflows/tests.yaml +5 -2
- package/README.md +75 -0
- package/package.json +2 -1
- package/src/dhali/AssetUpdates.js +67 -0
- package/src/dhali/BaseAssetManager.js +182 -0
- package/src/dhali/DhaliAssetManager.js +25 -0
- package/src/dhali/DhaliEthAssetManager.js +35 -0
- package/src/dhali/DhaliXrplAssetManager.js +32 -0
- package/src/dhali/WalletDescriptor.js +27 -0
- package/src/index.js +19 -4
- package/tests/integration.test.js +78 -0
|
@@ -25,8 +25,11 @@ jobs:
|
|
|
25
25
|
- name: Install dependencies
|
|
26
26
|
run: npm ci
|
|
27
27
|
|
|
28
|
-
- name: Run tests
|
|
29
|
-
run: npm test
|
|
28
|
+
- name: Run unit tests
|
|
29
|
+
run: npm test tests/DhaliChannelManager.test.js tests/DhaliEthChannelManager.test.js tests/createSignedClaim.test.js tests/utils.test.js
|
|
30
|
+
|
|
31
|
+
- name: Run integration tests
|
|
32
|
+
run: npm test tests/integration.test.js
|
|
30
33
|
|
|
31
34
|
- name: Run lint
|
|
32
35
|
run: npx tsc src/dhali/*.js --allowJs --checkJs --noEmit --moduleResolution node --module commonjs --target esnext --skipLibCheck
|
package/README.md
CHANGED
|
@@ -148,6 +148,81 @@ async function main() {
|
|
|
148
148
|
main();
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Asset Management (for Providers)
|
|
155
|
+
|
|
156
|
+
If you have an API you want to monetize on Dhali, you can use the `DhaliAssetManager` to create and update your asset on the network.
|
|
157
|
+
|
|
158
|
+
### 1. Create an Asset
|
|
159
|
+
|
|
160
|
+
This generates an **Asset ID (UUID)**.
|
|
161
|
+
|
|
162
|
+
#### XRPL Setup
|
|
163
|
+
```js
|
|
164
|
+
const { Wallet } = require('xrpl');
|
|
165
|
+
const wallet = Wallet.fromSeed("s..."); // Your XRPL seed
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### EVM Setup
|
|
169
|
+
```js
|
|
170
|
+
const { createWalletClient, http } = require('viem');
|
|
171
|
+
const { privateKeyToAccount } = require('viem/accounts');
|
|
172
|
+
const { sepolia } = require('viem/chains');
|
|
173
|
+
|
|
174
|
+
const walletClient = createWalletClient({
|
|
175
|
+
account: privateKeyToAccount("0x..."),
|
|
176
|
+
chain: sepolia,
|
|
177
|
+
transport: http()
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### Initialization & Creation
|
|
182
|
+
```js
|
|
183
|
+
const { DhaliAssetManager, WalletDescriptor, Currency } = require('dhali-js');
|
|
184
|
+
|
|
185
|
+
async function main() {
|
|
186
|
+
// For XRPL
|
|
187
|
+
const manager = DhaliAssetManager.xrpl(wallet);
|
|
188
|
+
const walletDescriptor = new WalletDescriptor(wallet.classicAddress, "XRPL.TESTNET");
|
|
189
|
+
|
|
190
|
+
// OR For EVM
|
|
191
|
+
// const manager = DhaliAssetManager.evm(walletClient);
|
|
192
|
+
// const walletDescriptor = new WalletDescriptor(walletClient.account.address, "SEPOLIA");
|
|
193
|
+
|
|
194
|
+
const currency = new Currency("XRPL.TESTNET", "XRP", 6);
|
|
195
|
+
|
|
196
|
+
// Create the asset
|
|
197
|
+
const result = await manager.createAsset(walletDescriptor, currency);
|
|
198
|
+
console.log("Your new Asset ID:", result.uuid);
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Once created, your asset is represented by an **off-chain facilitator address**:
|
|
203
|
+
`https://x402.api.dhali.io/<uuid>`
|
|
204
|
+
|
|
205
|
+
This facilitator is used for protocol-level concerns like verification and settlement, while your actual service requests are sent to your **Resource Server**.
|
|
206
|
+
|
|
207
|
+
### 2. Update an Asset
|
|
208
|
+
|
|
209
|
+
You can update your asset's metadata (name, rates, etc.) at any time.
|
|
210
|
+
|
|
211
|
+
```js
|
|
212
|
+
const { AssetUpdates } = require('dhali-js');
|
|
213
|
+
|
|
214
|
+
async function main() {
|
|
215
|
+
const updates = new AssetUpdates({
|
|
216
|
+
name: "My Optimized AI API",
|
|
217
|
+
earning_rate: 100, // 100 drops per request
|
|
218
|
+
earning_type: "per_request" // or "per_second"
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const result = await manager.updateAsset(assetId, walletDescriptor, updates);
|
|
222
|
+
console.log("Asset updated successfully");
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
151
226
|
---
|
|
152
227
|
|
|
153
228
|
## API Reference
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dhali-js",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "A JavaScript library for managing XRPL payment channels and generating auth tokens for Dhali APIs",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"ripple-keypairs": "^2.0.0",
|
|
20
20
|
"viem": "^2.23.5",
|
|
21
|
+
"ws": "^8.18.0",
|
|
21
22
|
"xrpl": "^4.0.0"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
class AssetUpdates {
|
|
2
|
+
/**
|
|
3
|
+
* @param {Object} options
|
|
4
|
+
* @param {string} [options.name]
|
|
5
|
+
* @param {number} [options.earningRate]
|
|
6
|
+
* @param {string} [options.earningType]
|
|
7
|
+
* @param {string} [options.url]
|
|
8
|
+
* @param {Object} [options.headers]
|
|
9
|
+
* @param {string} [options.docs]
|
|
10
|
+
* @param {number} [options.maxSurcharge]
|
|
11
|
+
* @param {number} [options.assetPricingRate]
|
|
12
|
+
* @param {number} [options.assetPricingMaxSurcharge]
|
|
13
|
+
* @param {Object} [options.assetPricingCurrency]
|
|
14
|
+
*/
|
|
15
|
+
constructor({
|
|
16
|
+
name,
|
|
17
|
+
earningRate,
|
|
18
|
+
earningType,
|
|
19
|
+
url,
|
|
20
|
+
headers,
|
|
21
|
+
docs,
|
|
22
|
+
maxSurcharge,
|
|
23
|
+
assetPricingRate,
|
|
24
|
+
assetPricingMaxSurcharge,
|
|
25
|
+
assetPricingCurrency
|
|
26
|
+
} = {}) {
|
|
27
|
+
this.name = name;
|
|
28
|
+
this.earningRate = earningRate;
|
|
29
|
+
this.earningType = earningType;
|
|
30
|
+
this.url = url;
|
|
31
|
+
this.headers = headers;
|
|
32
|
+
this.docs = docs;
|
|
33
|
+
this.maxSurcharge = maxSurcharge;
|
|
34
|
+
this.assetPricingRate = assetPricingRate;
|
|
35
|
+
this.assetPricingMaxSurcharge = assetPricingMaxSurcharge;
|
|
36
|
+
this.assetPricingCurrency = assetPricingCurrency;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Converts the updates to the format expected by api-admin-gateway
|
|
41
|
+
* @returns {Object}
|
|
42
|
+
*/
|
|
43
|
+
toGatewayFormat() {
|
|
44
|
+
const updates = {};
|
|
45
|
+
if (this.name !== undefined) updates["name"] = this.name;
|
|
46
|
+
if (this.earningRate !== undefined) updates["asset_earning_rate"] = this.earningRate;
|
|
47
|
+
if (this.earningType !== undefined) updates["asset_earning_type"] = this.earningType;
|
|
48
|
+
if (this.docs !== undefined) updates["docs"] = this.docs;
|
|
49
|
+
if (this.maxSurcharge !== undefined) updates["asset_earning_max_surcharge"] = this.maxSurcharge;
|
|
50
|
+
if (this.assetPricingRate !== undefined) updates["asset_pricing_rate"] = this.assetPricingRate;
|
|
51
|
+
if (this.assetPricingMaxSurcharge !== undefined) updates["asset_pricing_max_surcharge"] = this.assetPricingMaxSurcharge;
|
|
52
|
+
if (this.assetPricingCurrency !== undefined) updates["asset_pricing_currency"] = this.assetPricingCurrency;
|
|
53
|
+
|
|
54
|
+
// Credentials/URL and headers are special
|
|
55
|
+
if (this.url !== undefined || this.headers !== undefined) {
|
|
56
|
+
updates["api_credentials"] = {};
|
|
57
|
+
if (this.url !== undefined) updates["api_credentials"]["url"] = this.url;
|
|
58
|
+
if (this.headers !== undefined) {
|
|
59
|
+
Object.assign(updates["api_credentials"], this.headers);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return updates;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = { AssetUpdates };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
const { WebSocket } = require('ws');
|
|
2
|
+
const Currency = require('./Currency');
|
|
3
|
+
const { AssetUpdates } = require('./AssetUpdates');
|
|
4
|
+
const { WalletDescriptor } = require('./WalletDescriptor');
|
|
5
|
+
const { fetchPublicConfig } = require('./configUtils');
|
|
6
|
+
|
|
7
|
+
class BaseAssetManager {
|
|
8
|
+
/**
|
|
9
|
+
* @param {any} wallet
|
|
10
|
+
* @param {string} [baseUrl]
|
|
11
|
+
*/
|
|
12
|
+
constructor(wallet, baseUrl) {
|
|
13
|
+
this.baseUrl = baseUrl ? baseUrl.replace(/^http/, 'ws') : undefined;
|
|
14
|
+
this.wallet = wallet;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async _resolveBaseUrl() {
|
|
18
|
+
if (this.baseUrl) return;
|
|
19
|
+
const config = await fetchPublicConfig();
|
|
20
|
+
const rootUrl = config.ROOT_API_ADMIN_URL;
|
|
21
|
+
if (!rootUrl) {
|
|
22
|
+
throw new Error("ROOT_API_ADMIN_URL not found in public config");
|
|
23
|
+
}
|
|
24
|
+
this.baseUrl = rootUrl.replace(/^http/, 'ws');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Abstract method to handle protocol-specific signing
|
|
29
|
+
* @protected
|
|
30
|
+
* @returns {Promise<any>}
|
|
31
|
+
*/
|
|
32
|
+
async _performSigning(typedData, walletDescriptor) {
|
|
33
|
+
throw new Error("_performSigning must be implemented by subclass");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async _handleAuth(ws, message, walletDescriptor) {
|
|
37
|
+
if (message.schema === 'api_admin_gateway_message_to_be_signed') {
|
|
38
|
+
const { message: typedData } = message;
|
|
39
|
+
const authResponse = await this._performSigning(typedData, walletDescriptor);
|
|
40
|
+
ws.send(JSON.stringify(authResponse));
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @param {WalletDescriptor} walletDescriptor
|
|
48
|
+
* @param {Currency} currency
|
|
49
|
+
*/
|
|
50
|
+
async createAsset(walletDescriptor, currency) {
|
|
51
|
+
await this._resolveBaseUrl();
|
|
52
|
+
if (!(walletDescriptor instanceof WalletDescriptor)) {
|
|
53
|
+
throw new Error('walletDescriptor must be an instance of WalletDescriptor');
|
|
54
|
+
}
|
|
55
|
+
if (!(currency instanceof Currency)) {
|
|
56
|
+
throw new Error('currency must be an instance of Currency');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
const ws = new WebSocket(`${this.baseUrl}/create`);
|
|
61
|
+
|
|
62
|
+
ws.on('open', () => {
|
|
63
|
+
ws.send(JSON.stringify({
|
|
64
|
+
owner: walletDescriptor.toJson(),
|
|
65
|
+
currency: {
|
|
66
|
+
code: currency.code,
|
|
67
|
+
scale: currency.scale,
|
|
68
|
+
issuer: currency.tokenAddress
|
|
69
|
+
}
|
|
70
|
+
}));
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
ws.on('message', async (data) => {
|
|
74
|
+
const message = JSON.parse(data.toString());
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
if (await this._handleAuth(ws, message, walletDescriptor)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (message.schema === 'api_admin_gateway_request_wallet_json') {
|
|
82
|
+
ws.send(JSON.stringify({
|
|
83
|
+
schema: 'api_admin_gateway_wallet_json_response',
|
|
84
|
+
wallet: walletDescriptor.toJson()
|
|
85
|
+
}));
|
|
86
|
+
} else if (message.schema === 'api_admin_gateway_create_successful') {
|
|
87
|
+
resolve(message);
|
|
88
|
+
ws.close();
|
|
89
|
+
} else if (message.qr_code_url) {
|
|
90
|
+
console.log('Scan this QR code to authenticate:', message.qr_code_url);
|
|
91
|
+
} else if (message.error) {
|
|
92
|
+
reject(new Error(message.error));
|
|
93
|
+
ws.close();
|
|
94
|
+
}
|
|
95
|
+
} catch (err) {
|
|
96
|
+
reject(err);
|
|
97
|
+
ws.close();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
ws.on('error', (error) => {
|
|
102
|
+
reject(error);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
ws.on('close', (code, reason) => {
|
|
106
|
+
if (code !== 1000 && code !== 1005) {
|
|
107
|
+
reject(new Error(`WebSocket closed with code ${code}: ${reason}`));
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @param {string} dhaliId
|
|
115
|
+
* @param {WalletDescriptor} walletDescriptor
|
|
116
|
+
* @param {AssetUpdates} updates
|
|
117
|
+
*/
|
|
118
|
+
async updateAsset(dhaliId, walletDescriptor, updates) {
|
|
119
|
+
await this._resolveBaseUrl();
|
|
120
|
+
if (!(walletDescriptor instanceof WalletDescriptor)) {
|
|
121
|
+
throw new Error('walletDescriptor must be an instance of WalletDescriptor');
|
|
122
|
+
}
|
|
123
|
+
if (!(updates instanceof AssetUpdates)) {
|
|
124
|
+
throw new Error('updates must be an instance of AssetUpdates');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return new Promise((resolve, reject) => {
|
|
128
|
+
const ws = new WebSocket(`${this.baseUrl}/${dhaliId}/update`);
|
|
129
|
+
|
|
130
|
+
ws.on('message', async (data) => {
|
|
131
|
+
const message = JSON.parse(data.toString());
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
if (await this._handleAuth(ws, message, walletDescriptor)) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (message.schema === 'api_admin_gateway_request_wallet_json') {
|
|
139
|
+
ws.send(JSON.stringify({
|
|
140
|
+
schema: 'api_admin_gateway_wallet_json_response',
|
|
141
|
+
wallet: walletDescriptor.toJson()
|
|
142
|
+
}));
|
|
143
|
+
} else if (message.schema === 'api_admin_gateway_authentication_successful') {
|
|
144
|
+
ws.send(JSON.stringify({
|
|
145
|
+
schema: 'api_admin_gateway_prefill_request',
|
|
146
|
+
schema_version: '1.0'
|
|
147
|
+
}));
|
|
148
|
+
} else if (message.schema === 'api_admin_gateway_prefill_response') {
|
|
149
|
+
ws.send(JSON.stringify({
|
|
150
|
+
schema: 'api_admin_gateway_update_request',
|
|
151
|
+
schema_version: '1.0',
|
|
152
|
+
updates: updates.toGatewayFormat()
|
|
153
|
+
}));
|
|
154
|
+
} else if (message.schema === 'api_admin_gateway_update_response') {
|
|
155
|
+
resolve(message);
|
|
156
|
+
ws.close();
|
|
157
|
+
} else if (message.qr_code_url) {
|
|
158
|
+
console.log('Scan this QR code to authenticate:', message.qr_code_url);
|
|
159
|
+
} else if (message.error || message.status === 'failed') {
|
|
160
|
+
reject(new Error(message.error || 'Update failed'));
|
|
161
|
+
ws.close();
|
|
162
|
+
}
|
|
163
|
+
} catch (err) {
|
|
164
|
+
reject(err);
|
|
165
|
+
ws.close();
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
ws.on('error', (error) => {
|
|
170
|
+
reject(error);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
ws.on('close', (code, reason) => {
|
|
174
|
+
if (code !== 1000 && code !== 1005) {
|
|
175
|
+
reject(new Error(`WebSocket closed with code ${code}: ${reason}`));
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
module.exports = { BaseAssetManager };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const { DhaliXrplAssetManager } = require('./DhaliXrplAssetManager');
|
|
2
|
+
const { DhaliEthAssetManager } = require('./DhaliEthAssetManager');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Factory for creating asset managers.
|
|
6
|
+
*/
|
|
7
|
+
const DhaliAssetManager = {
|
|
8
|
+
/**
|
|
9
|
+
* @param {import("xrpl").Wallet} wallet
|
|
10
|
+
* @returns {DhaliXrplAssetManager}
|
|
11
|
+
*/
|
|
12
|
+
xrpl: (wallet) => {
|
|
13
|
+
return new DhaliXrplAssetManager(wallet);
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {import("viem").WalletClient} walletClient
|
|
18
|
+
* @returns {DhaliEthAssetManager}
|
|
19
|
+
*/
|
|
20
|
+
evm: (walletClient) => {
|
|
21
|
+
return new DhaliEthAssetManager(walletClient);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
module.exports = { DhaliAssetManager };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const { BaseAssetManager } = require('./BaseAssetManager');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DhaliAssetManager for EVM protocol.
|
|
5
|
+
*/
|
|
6
|
+
class DhaliEthAssetManager extends BaseAssetManager {
|
|
7
|
+
/**
|
|
8
|
+
* @param {import("viem").WalletClient} walletClient
|
|
9
|
+
* @param {string} [baseUrl]
|
|
10
|
+
*/
|
|
11
|
+
constructor(walletClient, baseUrl) {
|
|
12
|
+
super(walletClient, baseUrl);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @protected
|
|
17
|
+
*/
|
|
18
|
+
async _performSigning(typedData, walletDescriptor) {
|
|
19
|
+
const [account] = await this.wallet.getAddresses();
|
|
20
|
+
const signature = await this.wallet.signTypedData({
|
|
21
|
+
account: this.wallet.account || account,
|
|
22
|
+
domain: typedData.domain,
|
|
23
|
+
types: typedData.types,
|
|
24
|
+
primaryType: typedData.primaryType,
|
|
25
|
+
message: typedData.message
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
schema: 'api_admin_gateway_signed_message_response',
|
|
30
|
+
signature: signature
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = { DhaliEthAssetManager };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const { BaseAssetManager } = require('./BaseAssetManager');
|
|
2
|
+
const { sign: signClaim } = require("ripple-keypairs");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* DhaliAssetManager for XRPL protocol.
|
|
6
|
+
*/
|
|
7
|
+
class DhaliXrplAssetManager extends BaseAssetManager {
|
|
8
|
+
/**
|
|
9
|
+
* @param {import("xrpl").Wallet} wallet
|
|
10
|
+
* @param {string} [baseUrl]
|
|
11
|
+
*/
|
|
12
|
+
constructor(wallet, baseUrl) {
|
|
13
|
+
super(wallet, baseUrl);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @protected
|
|
18
|
+
*/
|
|
19
|
+
async _performSigning(typedData, walletDescriptor) {
|
|
20
|
+
// The backend expects the message as a JSON string for XRPL
|
|
21
|
+
const messageToSign = JSON.stringify(typedData);
|
|
22
|
+
const signature = signClaim(Buffer.from(messageToSign).toString('hex'), this.wallet.privateKey);
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
schema: 'api_admin_gateway_signed_message_response',
|
|
26
|
+
signature: signature.toUpperCase(),
|
|
27
|
+
public_key: this.wallet.publicKey
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = { DhaliXrplAssetManager };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
class WalletDescriptor {
|
|
2
|
+
/**
|
|
3
|
+
* @param {string} address - The classic address of the wallet
|
|
4
|
+
* @param {string} protocol - The network protocol (e.g., 'XRPL.TESTNET', 'ETHEREUM')
|
|
5
|
+
* @param {string} [type='Dhali-js'] - The type of wallet (defaults to 'Dhali-js')
|
|
6
|
+
*/
|
|
7
|
+
constructor(address, protocol, type = 'Dhali-js') {
|
|
8
|
+
this.address = address;
|
|
9
|
+
this.protocol = protocol;
|
|
10
|
+
this.type = type;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Converts to JSON format expected by Dhali backend
|
|
15
|
+
* @returns {Object}
|
|
16
|
+
*/
|
|
17
|
+
toJson() {
|
|
18
|
+
return {
|
|
19
|
+
address: this.address,
|
|
20
|
+
wallet_id: this.address, // Backward compatibility or specific gateway requirement
|
|
21
|
+
type: this.type,
|
|
22
|
+
protocol: this.protocol
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = { WalletDescriptor };
|
package/src/index.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
const { DhaliChannelManager } = require("./dhali/DhaliChannelManager");
|
|
2
|
-
const { DhaliXrplChannelManager
|
|
2
|
+
const { DhaliXrplChannelManager } = require("./dhali/DhaliXrplChannelManager");
|
|
3
3
|
const { DhaliEthChannelManager } = require("./dhali/DhaliEthChannelManager");
|
|
4
|
+
const { DhaliAssetManager } = require("./dhali/DhaliAssetManager");
|
|
5
|
+
const { BaseAssetManager } = require("./dhali/BaseAssetManager");
|
|
6
|
+
const { DhaliXrplAssetManager } = require("./dhali/DhaliXrplAssetManager");
|
|
7
|
+
const { DhaliEthAssetManager } = require("./dhali/DhaliEthAssetManager");
|
|
8
|
+
const { WalletDescriptor } = require("./dhali/WalletDescriptor");
|
|
9
|
+
const { AssetUpdates } = require("./dhali/AssetUpdates");
|
|
4
10
|
const Currency = require("./dhali/Currency");
|
|
5
|
-
const { getAvailableDhaliCurrencies } = require("./dhali/configUtils");
|
|
6
|
-
const { wrapAsX402PaymentPayload } = require("./dhali/utils");
|
|
11
|
+
const { fetchPublicConfig, retrieveChannelIdFromFirestoreRest, notifyAdminGateway, getAvailableDhaliCurrencies } = require("./dhali/configUtils");
|
|
12
|
+
const { wrapAsX402PaymentPayload, ChannelNotFound } = require("./dhali/utils");
|
|
7
13
|
|
|
8
14
|
module.exports = {
|
|
9
15
|
DhaliChannelManager,
|
|
@@ -12,5 +18,14 @@ module.exports = {
|
|
|
12
18
|
ChannelNotFound,
|
|
13
19
|
Currency,
|
|
14
20
|
getAvailableDhaliCurrencies,
|
|
15
|
-
|
|
21
|
+
DhaliAssetManager,
|
|
22
|
+
BaseAssetManager,
|
|
23
|
+
DhaliXrplAssetManager,
|
|
24
|
+
DhaliEthAssetManager,
|
|
25
|
+
WalletDescriptor,
|
|
26
|
+
AssetUpdates,
|
|
27
|
+
fetchPublicConfig,
|
|
28
|
+
retrieveChannelIdFromFirestoreRest,
|
|
29
|
+
notifyAdminGateway,
|
|
30
|
+
wrapAsX402PaymentPayload,
|
|
16
31
|
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const { Wallet } = require('xrpl');
|
|
2
|
+
const { DhaliAssetManager } = require('../src/dhali/DhaliAssetManager');
|
|
3
|
+
const { WalletDescriptor } = require('../src/dhali/WalletDescriptor');
|
|
4
|
+
const Currency = require('../src/dhali/Currency');
|
|
5
|
+
const { AssetUpdates } = require('../src/dhali/AssetUpdates');
|
|
6
|
+
|
|
7
|
+
describe('Dhali-js Integration Test', () => {
|
|
8
|
+
let wallet;
|
|
9
|
+
let manager;
|
|
10
|
+
|
|
11
|
+
beforeAll(() => {
|
|
12
|
+
wallet = Wallet.generate();
|
|
13
|
+
manager = DhaliAssetManager.xrpl(wallet);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('should create and update an asset', async () => {
|
|
17
|
+
const walletDescriptor = new WalletDescriptor(wallet.address, "XRPL.TESTNET");
|
|
18
|
+
const currency = new Currency("XRPL.TESTNET", "XRP", 6);
|
|
19
|
+
|
|
20
|
+
// 1. Create Asset
|
|
21
|
+
console.log('Creating asset...');
|
|
22
|
+
const createResult = await manager.createAsset(walletDescriptor, currency);
|
|
23
|
+
expect(createResult.schema).toBe('api_admin_gateway_create_successful');
|
|
24
|
+
expect(createResult.uuid).toBeDefined();
|
|
25
|
+
const assetId = createResult.uuid;
|
|
26
|
+
console.log('Asset created with UUID:', assetId);
|
|
27
|
+
|
|
28
|
+
// 2. Update Asset
|
|
29
|
+
console.log('Updating asset...');
|
|
30
|
+
const updates = new AssetUpdates({
|
|
31
|
+
name: "Integration Test Asset",
|
|
32
|
+
earning_rate: 100,
|
|
33
|
+
earning_type: "per_request"
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const updateResult = await manager.updateAsset(assetId, walletDescriptor, updates);
|
|
37
|
+
expect(updateResult.schema).toBe('api_admin_gateway_update_response');
|
|
38
|
+
console.log('Asset updated successfully');
|
|
39
|
+
}, 30000); // Increased timeout for live API calls
|
|
40
|
+
|
|
41
|
+
test('should create and update an EVM asset', async () => {
|
|
42
|
+
const { createWalletClient, http } = require('viem');
|
|
43
|
+
const { generatePrivateKey, privateKeyToAccount } = require('viem/accounts');
|
|
44
|
+
const { sepolia } = require('viem/chains');
|
|
45
|
+
|
|
46
|
+
const privateKey = generatePrivateKey();
|
|
47
|
+
const account = privateKeyToAccount(privateKey);
|
|
48
|
+
const walletClient = createWalletClient({
|
|
49
|
+
account,
|
|
50
|
+
chain: sepolia,
|
|
51
|
+
transport: http()
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const evmManager = DhaliAssetManager.evm(walletClient);
|
|
55
|
+
const walletDescriptor = new WalletDescriptor(account.address, "SEPOLIA");
|
|
56
|
+
const currency = new Currency("SEPOLIA", "ETH", 18);
|
|
57
|
+
|
|
58
|
+
// 1. Create Asset
|
|
59
|
+
console.log('Creating EVM asset...');
|
|
60
|
+
const createResult = await evmManager.createAsset(walletDescriptor, currency);
|
|
61
|
+
expect(createResult.schema).toBe('api_admin_gateway_create_successful');
|
|
62
|
+
expect(createResult.uuid).toBeDefined();
|
|
63
|
+
const assetId = createResult.uuid;
|
|
64
|
+
console.log('EVM Asset created with UUID:', assetId);
|
|
65
|
+
|
|
66
|
+
// 2. Update Asset
|
|
67
|
+
console.log('Updating EVM asset...');
|
|
68
|
+
const updates = new AssetUpdates({
|
|
69
|
+
name: "Integration Test Asset EVM",
|
|
70
|
+
earning_rate: 0.001,
|
|
71
|
+
earning_type: "per_request"
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const updateResult = await evmManager.updateAsset(assetId, walletDescriptor, updates);
|
|
75
|
+
expect(updateResult.schema).toBe('api_admin_gateway_update_response');
|
|
76
|
+
console.log('EVM Asset updated successfully');
|
|
77
|
+
}, 30000);
|
|
78
|
+
});
|