@pioneer-platform/zapper-client 8.15.0 โ 8.17.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/CHANGELOG.md +22 -0
- package/ERROR_HANDLING_UPGRADE.md +187 -0
- package/lib/index.d.ts +17 -0
- package/lib/index.js +257 -89
- package/package.json +2 -2
- package/test-api.js +22 -0
- package/test-error-handling.js +33 -0
- package/test-raw-api.js +70 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @pioneer-platform/zapper-client
|
|
2
2
|
|
|
3
|
+
## 8.17.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- chore: chore: chore: chore: chore: chore: feat(pioneer): implement end-to-end Solana transaction signing
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
- @pioneer-platform/pioneer-caip@9.17.0
|
|
13
|
+
|
|
14
|
+
## 8.16.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- chore: chore: chore: chore: chore: feat(pioneer): implement end-to-end Solana transaction signing
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
- @pioneer-platform/pioneer-caip@9.16.0
|
|
24
|
+
|
|
3
25
|
## 8.15.0
|
|
4
26
|
|
|
5
27
|
### Minor Changes
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Zapper Integration - Error Handling Upgrade
|
|
2
|
+
|
|
3
|
+
## ๐ฏ Changes Made
|
|
4
|
+
|
|
5
|
+
### 1. **Proper Error Propagation** โ
|
|
6
|
+
**Before**: Functions returned empty data (0, [], null) on errors, which got cached
|
|
7
|
+
**After**: Functions throw proper `ZapperAPIError` exceptions with error codes
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// OLD (BAD)
|
|
11
|
+
catch (e) {
|
|
12
|
+
return {
|
|
13
|
+
balances: [],
|
|
14
|
+
totalNetWorth: 0 // This gets cached!
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// NEW (GOOD)
|
|
19
|
+
catch (e) {
|
|
20
|
+
await handleZapperError(e, 'getPortfolio');
|
|
21
|
+
// Throws error - won't be cached
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 2. **Discord Alerts for Critical Issues** ๐
|
|
26
|
+
Automatically sends Discord notifications when:
|
|
27
|
+
- ๐จ **CRITICAL**: API credits exhausted (PAYMENT_REQUIRED)
|
|
28
|
+
- โ ๏ธ **WARNING**: Rate limit exceeded
|
|
29
|
+
- โ **ERROR**: Authentication failures
|
|
30
|
+
|
|
31
|
+
### 3. **Specific Error Codes** ๐ท๏ธ
|
|
32
|
+
- `402` - Payment Required (credits exhausted)
|
|
33
|
+
- `429` - Rate Limited
|
|
34
|
+
- `401` - Authentication Failed
|
|
35
|
+
- `500` - Generic API errors
|
|
36
|
+
- `503` - Network/connection errors
|
|
37
|
+
|
|
38
|
+
### 4. **Error Handler Function** ๐ก๏ธ
|
|
39
|
+
New `handleZapperError()` function:
|
|
40
|
+
- Detects specific Zapper error types from GraphQL responses
|
|
41
|
+
- Sends Discord alerts for critical issues
|
|
42
|
+
- Throws typed `ZapperAPIError` with proper HTTP status codes
|
|
43
|
+
- Prevents empty data from being cached
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## ๐ Setup Required
|
|
48
|
+
|
|
49
|
+
### 1. Environment Variables
|
|
50
|
+
Add to `.env` file:
|
|
51
|
+
```bash
|
|
52
|
+
# Required
|
|
53
|
+
ZAPPER_API_KEY=your-production-key-here
|
|
54
|
+
|
|
55
|
+
# Optional but HIGHLY recommended
|
|
56
|
+
DISCORD_WEBHOOK_ZAPPER_ALERTS=https://discord.com/api/webhooks/YOUR_WEBHOOK_URL
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 2. Restart Server
|
|
60
|
+
The module has been rebuilt, but the server needs restart to load changes:
|
|
61
|
+
```bash
|
|
62
|
+
cd /Users/highlander/WebstormProjects/keepkey-stack/projects/pioneer/services/pioneer-server
|
|
63
|
+
|
|
64
|
+
# Kill existing server
|
|
65
|
+
lsof -ti:9001 | xargs kill -9
|
|
66
|
+
|
|
67
|
+
# Start fresh
|
|
68
|
+
make start
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 3. Clear Stale Cache
|
|
72
|
+
Clear any cached empty data from before:
|
|
73
|
+
```bash
|
|
74
|
+
# Clear all Zapper cache
|
|
75
|
+
redis-cli KEYS "zapper_v1:*" | xargs redis-cli DEL
|
|
76
|
+
|
|
77
|
+
# Or via API
|
|
78
|
+
curl http://localhost:9001/api/v1/zapper/clear/YOUR_ADDRESS
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## ๐งช Testing
|
|
84
|
+
|
|
85
|
+
### Test Error Handling
|
|
86
|
+
```bash
|
|
87
|
+
# 1. Test with valid address (should work)
|
|
88
|
+
curl -s "http://localhost:9001/api/v1/zapper/totals/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" | jq
|
|
89
|
+
|
|
90
|
+
# 2. Simulate exhausted credits (if you have test key)
|
|
91
|
+
# Should return 402 and send Discord alert
|
|
92
|
+
|
|
93
|
+
# 3. Check cache stats
|
|
94
|
+
curl -s "http://localhost:9001/api/v1/zapper/stats/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" | jq
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Verify Discord Alerts
|
|
98
|
+
1. Trigger an error (exhausted credits, rate limit, etc.)
|
|
99
|
+
2. Check your Discord channel for alert
|
|
100
|
+
3. Should see formatted embed with:
|
|
101
|
+
- Error severity (CRITICAL/WARNING/ERROR)
|
|
102
|
+
- Operation that failed
|
|
103
|
+
- Error message
|
|
104
|
+
- Action required
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## ๐ How It Works Now
|
|
109
|
+
|
|
110
|
+
### Error Flow
|
|
111
|
+
```
|
|
112
|
+
1. User Request โ Zapper API
|
|
113
|
+
โ
|
|
114
|
+
2. API Error (e.g., PAYMENT_REQUIRED)
|
|
115
|
+
โ
|
|
116
|
+
3. handleZapperError() detects error type
|
|
117
|
+
โ
|
|
118
|
+
4. Send Discord Alert (if webhook configured)
|
|
119
|
+
โ
|
|
120
|
+
5. Throw ZapperAPIError with proper status code
|
|
121
|
+
โ
|
|
122
|
+
6. Cache layer: DON'T cache errors
|
|
123
|
+
โ
|
|
124
|
+
7. Controller: Return error to user with HTTP status
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Cache Behavior
|
|
128
|
+
- โ
**Success**: Cache for 24 hours
|
|
129
|
+
- โ **Error**: Don't cache, throw to user
|
|
130
|
+
- ๐ **Stale**: Return cached + refresh in background
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## ๐ Benefits
|
|
135
|
+
|
|
136
|
+
1. **No More Silent Failures**: Users see actual errors instead of empty portfolios
|
|
137
|
+
2. **Proactive Monitoring**: Discord alerts notify you before users complain
|
|
138
|
+
3. **No Stale Cache**: Errors aren't cached, so fixing API issues immediately reflects
|
|
139
|
+
4. **Better Debugging**: Specific error codes and messages make troubleshooting easier
|
|
140
|
+
5. **Production Ready**: Proper error handling for long-term reliability
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## ๐จ Common Issues & Solutions
|
|
145
|
+
|
|
146
|
+
### Issue: Still seeing empty data
|
|
147
|
+
**Solution**: Clear cache and restart server
|
|
148
|
+
```bash
|
|
149
|
+
redis-cli KEYS "zapper_v1:*" | xargs redis-cli DEL
|
|
150
|
+
lsof -ti:9001 | xargs kill -9 && make start
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Issue: Not receiving Discord alerts
|
|
154
|
+
**Solution**: Check webhook URL is correct in .env
|
|
155
|
+
```bash
|
|
156
|
+
# Test webhook manually
|
|
157
|
+
curl -X POST "$DISCORD_WEBHOOK_ZAPPER_ALERTS" \
|
|
158
|
+
-H "Content-Type: application/json" \
|
|
159
|
+
-d '{"content": "Test alert from Zapper integration"}'
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Issue: Getting 402 errors
|
|
163
|
+
**Solution**: Add credits at https://build.zapper.xyz/dashboard
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## ๐ Next Steps
|
|
168
|
+
|
|
169
|
+
1. โ
Module updated with error handling
|
|
170
|
+
2. โ
Documentation updated
|
|
171
|
+
3. โณ **Add Discord webhook to .env**
|
|
172
|
+
4. โณ **Restart server to load changes**
|
|
173
|
+
5. โณ **Clear stale cache**
|
|
174
|
+
6. โณ **Test with real address**
|
|
175
|
+
7. โณ **Verify Discord alerts work**
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## ๐ Key Learnings
|
|
180
|
+
|
|
181
|
+
**Problem**: Zapper API failures were silently returning empty data (0, [], null), which got cached for 24 hours, making users think they had no assets.
|
|
182
|
+
|
|
183
|
+
**Root Cause**: Error handlers were catching exceptions but returning empty objects instead of re-throwing errors.
|
|
184
|
+
|
|
185
|
+
**Solution**: Proper error propagation with typed exceptions, Discord alerting, and cache-aware error handling.
|
|
186
|
+
|
|
187
|
+
**Impact**: System is now production-ready with proper observability and error handling.
|
package/lib/index.d.ts
CHANGED
|
@@ -8,6 +8,23 @@ declare let API_KEY: string | undefined;
|
|
|
8
8
|
declare const axios: any;
|
|
9
9
|
declare const GRAPHQL_URL = "https://public.zapper.xyz/graphql";
|
|
10
10
|
declare const REST_URL = "https://api.zapper.xyz";
|
|
11
|
+
declare const DISCORD_WEBHOOK_URL: string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Custom error types for Zapper API failures
|
|
14
|
+
*/
|
|
15
|
+
declare class ZapperAPIError extends Error {
|
|
16
|
+
code: string;
|
|
17
|
+
statusCode?: number | undefined;
|
|
18
|
+
constructor(message: string, code: string, statusCode?: number | undefined);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Send Discord alert for critical Zapper issues
|
|
22
|
+
*/
|
|
23
|
+
declare const sendDiscordAlert: (message: string, severity: "error" | "warning" | "critical") => Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Handle Zapper API errors and throw appropriate exceptions
|
|
26
|
+
*/
|
|
27
|
+
declare const handleZapperError: (error: any, operation: string) => Promise<never>;
|
|
11
28
|
/**
|
|
12
29
|
* Validates if a CAIP is correctly formatted for the given token
|
|
13
30
|
*/
|
package/lib/index.js
CHANGED
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
https://docs.blocknative.com/webhook-api
|
|
4
4
|
|
|
5
5
|
*/
|
|
6
|
+
var __extends = (this && this.__extends) || (function () {
|
|
7
|
+
var extendStatics = function (d, b) {
|
|
8
|
+
extendStatics = Object.setPrototypeOf ||
|
|
9
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
10
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
11
|
+
return extendStatics(d, b);
|
|
12
|
+
};
|
|
13
|
+
return function (d, b) {
|
|
14
|
+
if (typeof b !== "function" && b !== null)
|
|
15
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
16
|
+
extendStatics(d, b);
|
|
17
|
+
function __() { this.constructor = d; }
|
|
18
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
19
|
+
};
|
|
20
|
+
})();
|
|
6
21
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
7
22
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
8
23
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -53,6 +68,126 @@ var axios = Axios.create();
|
|
|
53
68
|
// IMPORTANT: Zapper GraphQL API uses x-zapper-api-key header, not Authorization
|
|
54
69
|
var GRAPHQL_URL = "https://public.zapper.xyz/graphql";
|
|
55
70
|
var REST_URL = "https://api.zapper.xyz";
|
|
71
|
+
var DISCORD_WEBHOOK_URL = process.env['DISCORD_WEBHOOK_ZAPPER_ALERTS'];
|
|
72
|
+
/**
|
|
73
|
+
* Custom error types for Zapper API failures
|
|
74
|
+
*/
|
|
75
|
+
var ZapperAPIError = /** @class */ (function (_super) {
|
|
76
|
+
__extends(ZapperAPIError, _super);
|
|
77
|
+
function ZapperAPIError(message, code, statusCode) {
|
|
78
|
+
var _this = _super.call(this, message) || this;
|
|
79
|
+
_this.code = code;
|
|
80
|
+
_this.statusCode = statusCode;
|
|
81
|
+
_this.name = 'ZapperAPIError';
|
|
82
|
+
return _this;
|
|
83
|
+
}
|
|
84
|
+
return ZapperAPIError;
|
|
85
|
+
}(Error));
|
|
86
|
+
/**
|
|
87
|
+
* Send Discord alert for critical Zapper issues
|
|
88
|
+
*/
|
|
89
|
+
var sendDiscordAlert = function (message, severity) {
|
|
90
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
91
|
+
var tag, colors, e_1;
|
|
92
|
+
return __generator(this, function (_a) {
|
|
93
|
+
switch (_a.label) {
|
|
94
|
+
case 0:
|
|
95
|
+
tag = TAG + " | sendDiscordAlert | ";
|
|
96
|
+
if (!DISCORD_WEBHOOK_URL) {
|
|
97
|
+
log.warn(tag, "Discord webhook not configured, skipping alert");
|
|
98
|
+
return [2 /*return*/];
|
|
99
|
+
}
|
|
100
|
+
colors = {
|
|
101
|
+
error: 15158332, // Red
|
|
102
|
+
warning: 16776960, // Yellow
|
|
103
|
+
critical: 10038562 // Dark red
|
|
104
|
+
};
|
|
105
|
+
_a.label = 1;
|
|
106
|
+
case 1:
|
|
107
|
+
_a.trys.push([1, 3, , 4]);
|
|
108
|
+
return [4 /*yield*/, Axios.post(DISCORD_WEBHOOK_URL, {
|
|
109
|
+
embeds: [{
|
|
110
|
+
title: "\uD83D\uDEA8 Zapper API ".concat(severity.toUpperCase()),
|
|
111
|
+
description: message,
|
|
112
|
+
color: colors[severity],
|
|
113
|
+
timestamp: new Date().toISOString(),
|
|
114
|
+
footer: {
|
|
115
|
+
text: 'Pioneer Zapper Integration'
|
|
116
|
+
}
|
|
117
|
+
}]
|
|
118
|
+
})];
|
|
119
|
+
case 2:
|
|
120
|
+
_a.sent();
|
|
121
|
+
log.info(tag, "Discord alert sent: ".concat(severity));
|
|
122
|
+
return [3 /*break*/, 4];
|
|
123
|
+
case 3:
|
|
124
|
+
e_1 = _a.sent();
|
|
125
|
+
log.error(tag, "Failed to send Discord alert:", e_1);
|
|
126
|
+
return [3 /*break*/, 4];
|
|
127
|
+
case 4: return [2 /*return*/];
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Handle Zapper API errors and throw appropriate exceptions
|
|
134
|
+
*/
|
|
135
|
+
var handleZapperError = function (error, operation) {
|
|
136
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
137
|
+
var tag, errors, _i, errors_1, err, code, message, alertMessage;
|
|
138
|
+
var _a, _b, _c, _d, _e, _f;
|
|
139
|
+
return __generator(this, function (_g) {
|
|
140
|
+
switch (_g.label) {
|
|
141
|
+
case 0:
|
|
142
|
+
tag = TAG + " | handleZapperError | ";
|
|
143
|
+
if (!((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.errors)) return [3 /*break*/, 9];
|
|
144
|
+
errors = error.response.data.errors;
|
|
145
|
+
_i = 0, errors_1 = errors;
|
|
146
|
+
_g.label = 1;
|
|
147
|
+
case 1:
|
|
148
|
+
if (!(_i < errors_1.length)) return [3 /*break*/, 9];
|
|
149
|
+
err = errors_1[_i];
|
|
150
|
+
code = (_c = err.extensions) === null || _c === void 0 ? void 0 : _c.code;
|
|
151
|
+
message = ((_d = err.extensions) === null || _d === void 0 ? void 0 : _d.message) || err.message;
|
|
152
|
+
if (!(code === 'PAYMENT_REQUIRED')) return [3 /*break*/, 3];
|
|
153
|
+
alertMessage = "**Zapper API Credits Exhausted**\n\n" +
|
|
154
|
+
"Operation: ".concat(operation, "\n") +
|
|
155
|
+
"Message: ".concat(message, "\n\n") +
|
|
156
|
+
"Action Required: Visit https://build.zapper.xyz/dashboard to add credits";
|
|
157
|
+
return [4 /*yield*/, sendDiscordAlert(alertMessage, 'critical')];
|
|
158
|
+
case 2:
|
|
159
|
+
_g.sent();
|
|
160
|
+
throw new ZapperAPIError('Zapper API credits exhausted. Please add credits at https://build.zapper.xyz/dashboard', 'PAYMENT_REQUIRED', 402);
|
|
161
|
+
case 3:
|
|
162
|
+
if (!(code === 'RATE_LIMITED' || err.message.includes('rate limit'))) return [3 /*break*/, 5];
|
|
163
|
+
return [4 /*yield*/, sendDiscordAlert("**Zapper API Rate Limited**\n\nOperation: ".concat(operation, "\nMessage: ").concat(message), 'warning')];
|
|
164
|
+
case 4:
|
|
165
|
+
_g.sent();
|
|
166
|
+
throw new ZapperAPIError('Zapper API rate limit exceeded. Please try again later.', 'RATE_LIMITED', 429);
|
|
167
|
+
case 5:
|
|
168
|
+
if (!(code === 'UNAUTHENTICATED' || message.includes('authentication'))) return [3 /*break*/, 7];
|
|
169
|
+
return [4 /*yield*/, sendDiscordAlert("**Zapper API Authentication Failed**\n\nOperation: ".concat(operation, "\nMessage: ").concat(message), 'error')];
|
|
170
|
+
case 6:
|
|
171
|
+
_g.sent();
|
|
172
|
+
throw new ZapperAPIError('Zapper API authentication failed. Please check API key.', 'UNAUTHENTICATED', 401);
|
|
173
|
+
case 7:
|
|
174
|
+
// Generic GraphQL error
|
|
175
|
+
throw new ZapperAPIError("Zapper API error: ".concat(message), code || 'UNKNOWN_ERROR', (_e = error.response) === null || _e === void 0 ? void 0 : _e.status);
|
|
176
|
+
case 8:
|
|
177
|
+
_i++;
|
|
178
|
+
return [3 /*break*/, 1];
|
|
179
|
+
case 9:
|
|
180
|
+
// Handle network/connection errors
|
|
181
|
+
if (error.code === 'ECONNREFUSED' || error.code === 'ETIMEDOUT') {
|
|
182
|
+
throw new ZapperAPIError('Failed to connect to Zapper API. Please check network connection.', 'NETWORK_ERROR');
|
|
183
|
+
}
|
|
184
|
+
// Generic error
|
|
185
|
+
log.error(tag, "Zapper API ".concat(operation, " failed:"), error);
|
|
186
|
+
throw new ZapperAPIError("Zapper API ".concat(operation, " failed: ").concat(error.message), 'API_ERROR', (_f = error.response) === null || _f === void 0 ? void 0 : _f.status);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
};
|
|
56
191
|
// Removed axios-retry - using basic axios
|
|
57
192
|
/**
|
|
58
193
|
* Validates if a CAIP is correctly formatted for the given token
|
|
@@ -181,16 +316,16 @@ module.exports = {
|
|
|
181
316
|
};
|
|
182
317
|
var get_portfolio = function (address) {
|
|
183
318
|
return __awaiter(this, void 0, void 0, function () {
|
|
184
|
-
var tag, output_1, appsGraphqlQuery, appsResponse, appsData, totalBalanceUSDApp, apps, _i, apps_1, appEdge, appNode, networkName, networkId, positions, _a, positions_1, posEdge, position, balance, tokenForCaip, tokens, _b, tokens_1, tokenWithMeta, token, balance, tokenForCaip, graphqlQuery, tokensResponse, totalBalanceUsdTokens_1, tokenData, tokens, nftGraphqlQuery, nftResponse, nftData, nftUsdNetWorth, allTokens, totalNetWorth,
|
|
319
|
+
var tag, output_1, appsGraphqlQuery, appsResponse, appsData, totalBalanceUSDApp, apps, _i, apps_1, appEdge, appNode, networkName, networkId, positions, _a, positions_1, posEdge, position, balance, tokenForCaip, tokens, _b, tokens_1, tokenWithMeta, token, balance, tokenForCaip, graphqlQuery, tokensResponse, totalBalanceUsdTokens_1, tokenData, tokens, nftGraphqlQuery, nftResponse, nftData, nftUsdNetWorth, allTokens, totalNetWorth, e_2;
|
|
185
320
|
var _c;
|
|
186
|
-
var _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9;
|
|
187
|
-
return __generator(this, function (
|
|
188
|
-
switch (
|
|
321
|
+
var _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11;
|
|
322
|
+
return __generator(this, function (_12) {
|
|
323
|
+
switch (_12.label) {
|
|
189
324
|
case 0:
|
|
190
325
|
tag = TAG + " | get_portfolio | ";
|
|
191
|
-
|
|
326
|
+
_12.label = 1;
|
|
192
327
|
case 1:
|
|
193
|
-
|
|
328
|
+
_12.trys.push([1, 11, , 13]);
|
|
194
329
|
output_1 = {
|
|
195
330
|
balances: []
|
|
196
331
|
};
|
|
@@ -207,39 +342,45 @@ var get_portfolio = function (address) {
|
|
|
207
342
|
}
|
|
208
343
|
})];
|
|
209
344
|
case 2:
|
|
210
|
-
appsResponse =
|
|
345
|
+
appsResponse = _12.sent();
|
|
346
|
+
if (!((_d = appsResponse.data) === null || _d === void 0 ? void 0 : _d.errors)) return [3 /*break*/, 4];
|
|
347
|
+
return [4 /*yield*/, handleZapperError({ response: appsResponse }, 'getPortfolio[apps]')];
|
|
348
|
+
case 3:
|
|
349
|
+
_12.sent();
|
|
350
|
+
return [2 /*return*/];
|
|
351
|
+
case 4:
|
|
211
352
|
log.debug(tag, "GraphQL apps response:", appsResponse.data);
|
|
212
|
-
appsData = (
|
|
353
|
+
appsData = (_g = (_f = (_e = appsResponse.data) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.portfolioV2) === null || _g === void 0 ? void 0 : _g.appBalances;
|
|
213
354
|
totalBalanceUSDApp = (appsData === null || appsData === void 0 ? void 0 : appsData.totalBalanceUSD) || 0;
|
|
214
|
-
apps = ((
|
|
355
|
+
apps = ((_h = appsData === null || appsData === void 0 ? void 0 : appsData.byApp) === null || _h === void 0 ? void 0 : _h.edges) || [];
|
|
215
356
|
for (_i = 0, apps_1 = apps; _i < apps_1.length; _i++) {
|
|
216
357
|
appEdge = apps_1[_i];
|
|
217
358
|
appNode = appEdge.node;
|
|
218
359
|
networkName = appNode.network.name.toLowerCase().replace(' ', '-');
|
|
219
|
-
networkId = ((
|
|
360
|
+
networkId = ((_j = evmCaips[networkName]) === null || _j === void 0 ? void 0 : _j.split('/')[0]) || ((_k = evmCaips[appNode.network.name.toLowerCase()]) === null || _k === void 0 ? void 0 : _k.split('/')[0]);
|
|
220
361
|
if (!networkId) {
|
|
221
362
|
log.warn(tag, "No CAIP found for network: ".concat(networkName));
|
|
222
363
|
continue;
|
|
223
364
|
}
|
|
224
|
-
positions = ((
|
|
365
|
+
positions = ((_l = appNode.positionBalances) === null || _l === void 0 ? void 0 : _l.edges) || [];
|
|
225
366
|
for (_a = 0, positions_1 = positions; _a < positions_1.length; _a++) {
|
|
226
367
|
posEdge = positions_1[_a];
|
|
227
368
|
position = posEdge.node;
|
|
228
369
|
if (position.type === 'app-token') {
|
|
229
370
|
balance = {};
|
|
230
371
|
balance.pubkey = address;
|
|
231
|
-
balance.balance = ((
|
|
372
|
+
balance.balance = ((_m = position.balance) === null || _m === void 0 ? void 0 : _m.toString()) || '0';
|
|
232
373
|
balance.chain = networkName;
|
|
233
374
|
balance.networkId = networkId;
|
|
234
375
|
balance.symbol = position.symbol;
|
|
235
376
|
balance.ticker = position.symbol;
|
|
236
|
-
balance.name = ((
|
|
377
|
+
balance.name = ((_o = position.displayProps) === null || _o === void 0 ? void 0 : _o.label) || position.symbol;
|
|
237
378
|
balance.appId = position.appId;
|
|
238
379
|
balance.groupId = position.groupId;
|
|
239
|
-
balance.icon = ((
|
|
240
|
-
balance.display = ((
|
|
241
|
-
balance.priceUsd = ((
|
|
242
|
-
balance.valueUsd = ((
|
|
380
|
+
balance.icon = ((_q = (_p = position.displayProps) === null || _p === void 0 ? void 0 : _p.images) === null || _q === void 0 ? void 0 : _q[0]) || '';
|
|
381
|
+
balance.display = ((_r = position.displayProps) === null || _r === void 0 ? void 0 : _r.images) || [];
|
|
382
|
+
balance.priceUsd = ((_s = position.price) === null || _s === void 0 ? void 0 : _s.toString()) || '0';
|
|
383
|
+
balance.valueUsd = ((_t = position.balanceUSD) === null || _t === void 0 ? void 0 : _t.toString()) || '0';
|
|
243
384
|
balance.tokenAddress = position.address;
|
|
244
385
|
balance.tokenType = 'app-token';
|
|
245
386
|
tokenForCaip = {
|
|
@@ -258,18 +399,18 @@ var get_portfolio = function (address) {
|
|
|
258
399
|
if (token && token.balanceUSD > 0) {
|
|
259
400
|
balance = {};
|
|
260
401
|
balance.pubkey = address;
|
|
261
|
-
balance.balance = ((
|
|
402
|
+
balance.balance = ((_u = token.balance) === null || _u === void 0 ? void 0 : _u.toString()) || '0';
|
|
262
403
|
balance.chain = networkName;
|
|
263
404
|
balance.networkId = networkId;
|
|
264
405
|
balance.symbol = token.symbol;
|
|
265
406
|
balance.ticker = token.symbol;
|
|
266
|
-
balance.name = ((
|
|
407
|
+
balance.name = ((_v = position.displayProps) === null || _v === void 0 ? void 0 : _v.label) || token.symbol;
|
|
267
408
|
balance.appId = position.appId;
|
|
268
409
|
balance.groupId = position.groupId;
|
|
269
|
-
balance.icon = ((
|
|
270
|
-
balance.display = ((
|
|
271
|
-
balance.priceUsd = ((
|
|
272
|
-
balance.valueUsd = ((
|
|
410
|
+
balance.icon = ((_x = (_w = position.displayProps) === null || _w === void 0 ? void 0 : _w.images) === null || _x === void 0 ? void 0 : _x[0]) || '';
|
|
411
|
+
balance.display = ((_y = position.displayProps) === null || _y === void 0 ? void 0 : _y.images) || [];
|
|
412
|
+
balance.priceUsd = ((_z = token.price) === null || _z === void 0 ? void 0 : _z.toString()) || '0';
|
|
413
|
+
balance.valueUsd = ((_0 = token.balanceUSD) === null || _0 === void 0 ? void 0 : _0.toString()) || '0';
|
|
273
414
|
balance.tokenAddress = token.address;
|
|
274
415
|
balance.tokenType = 'contract-position';
|
|
275
416
|
balance.metaType = tokenWithMeta.metaType;
|
|
@@ -296,13 +437,19 @@ var get_portfolio = function (address) {
|
|
|
296
437
|
'x-zapper-api-key': API_KEY,
|
|
297
438
|
}
|
|
298
439
|
})];
|
|
299
|
-
case
|
|
300
|
-
tokensResponse =
|
|
440
|
+
case 5:
|
|
441
|
+
tokensResponse = _12.sent();
|
|
442
|
+
if (!((_1 = tokensResponse.data) === null || _1 === void 0 ? void 0 : _1.errors)) return [3 /*break*/, 7];
|
|
443
|
+
return [4 /*yield*/, handleZapperError({ response: tokensResponse }, 'getPortfolio[tokens]')];
|
|
444
|
+
case 6:
|
|
445
|
+
_12.sent();
|
|
446
|
+
return [2 /*return*/];
|
|
447
|
+
case 7:
|
|
301
448
|
log.debug(tag, "GraphQL tokens response:", tokensResponse.data);
|
|
302
449
|
totalBalanceUsdTokens_1 = 0;
|
|
303
|
-
if ((
|
|
450
|
+
if ((_4 = (_3 = (_2 = tokensResponse.data) === null || _2 === void 0 ? void 0 : _2.data) === null || _3 === void 0 ? void 0 : _3.portfolioV2) === null || _4 === void 0 ? void 0 : _4.tokenBalances) {
|
|
304
451
|
tokenData = tokensResponse.data.data.portfolioV2.tokenBalances;
|
|
305
|
-
tokens = ((
|
|
452
|
+
tokens = ((_5 = tokenData.byToken) === null || _5 === void 0 ? void 0 : _5.edges) || [];
|
|
306
453
|
output_1.tokens = tokens.map(function (edge) { return edge.node; });
|
|
307
454
|
log.info(tag, "tokens: ", tokens.length);
|
|
308
455
|
if (tokens.length > 0) {
|
|
@@ -372,49 +519,47 @@ var get_portfolio = function (address) {
|
|
|
372
519
|
'x-zapper-api-key': API_KEY,
|
|
373
520
|
}
|
|
374
521
|
})];
|
|
375
|
-
case
|
|
376
|
-
nftResponse =
|
|
377
|
-
|
|
522
|
+
case 8:
|
|
523
|
+
nftResponse = _12.sent();
|
|
524
|
+
if (!((_6 = nftResponse.data) === null || _6 === void 0 ? void 0 : _6.errors)) return [3 /*break*/, 10];
|
|
525
|
+
return [4 /*yield*/, handleZapperError({ response: nftResponse }, 'getPortfolio[nfts]')];
|
|
526
|
+
case 9:
|
|
527
|
+
_12.sent();
|
|
528
|
+
return [2 /*return*/];
|
|
529
|
+
case 10:
|
|
530
|
+
nftData = (_9 = (_8 = (_7 = nftResponse.data) === null || _7 === void 0 ? void 0 : _7.data) === null || _8 === void 0 ? void 0 : _8.portfolioV2) === null || _9 === void 0 ? void 0 : _9.nftBalances;
|
|
378
531
|
nftUsdNetWorth = (nftData === null || nftData === void 0 ? void 0 : nftData.totalBalanceUSD) || 0;
|
|
379
|
-
allTokens = ((
|
|
532
|
+
allTokens = ((_11 = (_10 = nftData === null || nftData === void 0 ? void 0 : nftData.byToken) === null || _10 === void 0 ? void 0 : _10.edges) === null || _11 === void 0 ? void 0 : _11.map(function (edge) { return edge.node.token; })) || [];
|
|
380
533
|
output_1.nfts = allTokens;
|
|
381
534
|
output_1.nftUsdNetWorth = (_c = {}, _c[address.toLowerCase()] = nftUsdNetWorth.toString(), _c);
|
|
382
535
|
output_1.totalBalanceUsdTokens = totalBalanceUsdTokens_1;
|
|
383
536
|
output_1.totalBalanceUSDApp = totalBalanceUSDApp;
|
|
384
|
-
totalNetWorth = totalBalanceUSDApp + totalBalanceUsdTokens_1 +
|
|
537
|
+
totalNetWorth = totalBalanceUSDApp + totalBalanceUsdTokens_1 + nftUsdNetWorth;
|
|
385
538
|
//console.log("totalNetWorth: ",totalNetWorth);
|
|
386
539
|
output_1.totalNetWorth = totalNetWorth;
|
|
387
540
|
return [2 /*return*/, output_1];
|
|
388
|
-
case
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
return [
|
|
394
|
-
|
|
395
|
-
tokens: [],
|
|
396
|
-
nfts: [],
|
|
397
|
-
totalNetWorth: 0,
|
|
398
|
-
totalBalanceUsdTokens: 0,
|
|
399
|
-
totalBalanceUSDApp: 0,
|
|
400
|
-
nftUsdNetWorth: {}
|
|
401
|
-
}];
|
|
402
|
-
case 6: return [2 /*return*/];
|
|
541
|
+
case 11:
|
|
542
|
+
e_2 = _12.sent();
|
|
543
|
+
return [4 /*yield*/, handleZapperError(e_2, 'getPortfolio')];
|
|
544
|
+
case 12:
|
|
545
|
+
_12.sent();
|
|
546
|
+
return [3 /*break*/, 13];
|
|
547
|
+
case 13: return [2 /*return*/];
|
|
403
548
|
}
|
|
404
549
|
});
|
|
405
550
|
});
|
|
406
551
|
};
|
|
407
552
|
var get_total_networth = function (address) {
|
|
408
553
|
return __awaiter(this, void 0, void 0, function () {
|
|
409
|
-
var tag, graphqlQuery, portfolioResponse, portfolioData, totalBalanceUsdTokens, totalBalanceUSDApp, nftUsdNetWorth, totalNetWorth,
|
|
410
|
-
var _a, _b, _c, _d, _e;
|
|
411
|
-
return __generator(this, function (
|
|
412
|
-
switch (
|
|
554
|
+
var tag, graphqlQuery, portfolioResponse, portfolioData, totalBalanceUsdTokens, totalBalanceUSDApp, nftUsdNetWorth, totalNetWorth, e_3;
|
|
555
|
+
var _a, _b, _c, _d, _e, _f;
|
|
556
|
+
return __generator(this, function (_g) {
|
|
557
|
+
switch (_g.label) {
|
|
413
558
|
case 0:
|
|
414
559
|
tag = TAG + " | get_total_networth | ";
|
|
415
|
-
|
|
560
|
+
_g.label = 1;
|
|
416
561
|
case 1:
|
|
417
|
-
|
|
562
|
+
_g.trys.push([1, 5, , 7]);
|
|
418
563
|
graphqlQuery = {
|
|
419
564
|
query: "\n query PortfolioTotals($addresses: [Address!]!) {\n portfolioV2(addresses: $addresses) {\n tokenBalances {\n totalBalanceUSD\n }\n appBalances {\n totalBalanceUSD\n }\n nftBalances {\n totalBalanceUSD\n }\n }\n }\n ",
|
|
420
565
|
variables: {
|
|
@@ -428,37 +573,45 @@ var get_total_networth = function (address) {
|
|
|
428
573
|
}
|
|
429
574
|
})];
|
|
430
575
|
case 2:
|
|
431
|
-
portfolioResponse =
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
576
|
+
portfolioResponse = _g.sent();
|
|
577
|
+
if (!((_a = portfolioResponse.data) === null || _a === void 0 ? void 0 : _a.errors)) return [3 /*break*/, 4];
|
|
578
|
+
return [4 /*yield*/, handleZapperError({ response: portfolioResponse }, 'getTotalNetworth')];
|
|
579
|
+
case 3:
|
|
580
|
+
_g.sent();
|
|
581
|
+
return [2 /*return*/]; // TypeScript needs this even though handleZapperError throws
|
|
582
|
+
case 4:
|
|
583
|
+
portfolioData = (_c = (_b = portfolioResponse.data) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.portfolioV2;
|
|
584
|
+
totalBalanceUsdTokens = ((_d = portfolioData === null || portfolioData === void 0 ? void 0 : portfolioData.tokenBalances) === null || _d === void 0 ? void 0 : _d.totalBalanceUSD) || 0;
|
|
585
|
+
totalBalanceUSDApp = ((_e = portfolioData === null || portfolioData === void 0 ? void 0 : portfolioData.appBalances) === null || _e === void 0 ? void 0 : _e.totalBalanceUSD) || 0;
|
|
586
|
+
nftUsdNetWorth = ((_f = portfolioData === null || portfolioData === void 0 ? void 0 : portfolioData.nftBalances) === null || _f === void 0 ? void 0 : _f.totalBalanceUSD) || 0;
|
|
436
587
|
log.debug(tag, "totalBalanceUsdTokens: ", totalBalanceUsdTokens);
|
|
437
588
|
log.debug(tag, "totalBalanceUSDApp: ", totalBalanceUSDApp);
|
|
438
589
|
log.debug(tag, "nftUsdNetWorth: ", nftUsdNetWorth);
|
|
439
590
|
totalNetWorth = totalBalanceUSDApp + totalBalanceUsdTokens + nftUsdNetWorth;
|
|
440
591
|
log.debug(tag, "totalNetWorth: ", totalNetWorth);
|
|
441
592
|
return [2 /*return*/, totalNetWorth];
|
|
442
|
-
case
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
593
|
+
case 5:
|
|
594
|
+
e_3 = _g.sent();
|
|
595
|
+
return [4 /*yield*/, handleZapperError(e_3, 'getTotalNetworth')];
|
|
596
|
+
case 6:
|
|
597
|
+
_g.sent();
|
|
598
|
+
return [3 /*break*/, 7];
|
|
599
|
+
case 7: return [2 /*return*/];
|
|
447
600
|
}
|
|
448
601
|
});
|
|
449
602
|
});
|
|
450
603
|
};
|
|
451
604
|
var get_tokens = function (address) {
|
|
452
605
|
return __awaiter(this, void 0, void 0, function () {
|
|
453
|
-
var tag, graphqlQuery, appsResponse,
|
|
454
|
-
var _a, _b, _c, _d, _e;
|
|
455
|
-
return __generator(this, function (
|
|
456
|
-
switch (
|
|
606
|
+
var tag, graphqlQuery, appsResponse, e_4;
|
|
607
|
+
var _a, _b, _c, _d, _e, _f;
|
|
608
|
+
return __generator(this, function (_g) {
|
|
609
|
+
switch (_g.label) {
|
|
457
610
|
case 0:
|
|
458
611
|
tag = TAG + " | get_tokens | ";
|
|
459
|
-
|
|
612
|
+
_g.label = 1;
|
|
460
613
|
case 1:
|
|
461
|
-
|
|
614
|
+
_g.trys.push([1, 5, , 7]);
|
|
462
615
|
log.debug(tag, "Using API key:", (API_KEY === null || API_KEY === void 0 ? void 0 : API_KEY.substring(0, 10)) + "...");
|
|
463
616
|
graphqlQuery = {
|
|
464
617
|
query: "\n query AppBalances($addresses: [Address!]!) {\n portfolioV2(addresses: $addresses) {\n appBalances {\n byApp(first: 100) {\n edges {\n node {\n balanceUSD\n app {\n slug\n displayName\n }\n network {\n name\n }\n }\n }\n }\n }\n }\n }\n ",
|
|
@@ -473,28 +626,35 @@ var get_tokens = function (address) {
|
|
|
473
626
|
}
|
|
474
627
|
})];
|
|
475
628
|
case 2:
|
|
476
|
-
appsResponse =
|
|
477
|
-
|
|
629
|
+
appsResponse = _g.sent();
|
|
630
|
+
if (!((_a = appsResponse.data) === null || _a === void 0 ? void 0 : _a.errors)) return [3 /*break*/, 4];
|
|
631
|
+
return [4 /*yield*/, handleZapperError({ response: appsResponse }, 'getTokens')];
|
|
478
632
|
case 3:
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
case
|
|
633
|
+
_g.sent();
|
|
634
|
+
return [2 /*return*/];
|
|
635
|
+
case 4: return [2 /*return*/, ((_f = (_e = (_d = (_c = (_b = appsResponse.data) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.portfolioV2) === null || _d === void 0 ? void 0 : _d.appBalances) === null || _e === void 0 ? void 0 : _e.byApp) === null || _f === void 0 ? void 0 : _f.edges) || []];
|
|
636
|
+
case 5:
|
|
637
|
+
e_4 = _g.sent();
|
|
638
|
+
return [4 /*yield*/, handleZapperError(e_4, 'getTokens')];
|
|
639
|
+
case 6:
|
|
640
|
+
_g.sent();
|
|
641
|
+
return [3 /*break*/, 7];
|
|
642
|
+
case 7: return [2 /*return*/];
|
|
483
643
|
}
|
|
484
644
|
});
|
|
485
645
|
});
|
|
486
646
|
};
|
|
487
647
|
var get_nfts = function (address) {
|
|
488
648
|
return __awaiter(this, void 0, void 0, function () {
|
|
489
|
-
var tag, graphqlQuery, result, nftData, tokens,
|
|
490
|
-
var _a, _b, _c, _d, _e;
|
|
491
|
-
return __generator(this, function (
|
|
492
|
-
switch (
|
|
649
|
+
var tag, graphqlQuery, result, nftData, tokens, e_5;
|
|
650
|
+
var _a, _b, _c, _d, _e, _f;
|
|
651
|
+
return __generator(this, function (_g) {
|
|
652
|
+
switch (_g.label) {
|
|
493
653
|
case 0:
|
|
494
654
|
tag = TAG + " | get_nfts | ";
|
|
495
|
-
|
|
655
|
+
_g.label = 1;
|
|
496
656
|
case 1:
|
|
497
|
-
|
|
657
|
+
_g.trys.push([1, 5, , 7]);
|
|
498
658
|
graphqlQuery = {
|
|
499
659
|
query: "\n query NFTBalances($addresses: [Address!]!) {\n portfolioV2(addresses: $addresses) {\n nftBalances {\n totalBalanceUSD\n totalTokensOwned\n byToken(first: 100) {\n edges {\n node {\n token {\n tokenId\n name\n description\n collection {\n address\n name\n network\n type\n }\n estimatedValue {\n valueUsd\n }\n mediasV3 {\n images {\n edges {\n node {\n originalUri\n thumbnail\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n ",
|
|
500
660
|
variables: {
|
|
@@ -508,19 +668,27 @@ var get_nfts = function (address) {
|
|
|
508
668
|
}
|
|
509
669
|
})];
|
|
510
670
|
case 2:
|
|
511
|
-
result =
|
|
512
|
-
|
|
513
|
-
|
|
671
|
+
result = _g.sent();
|
|
672
|
+
if (!((_a = result.data) === null || _a === void 0 ? void 0 : _a.errors)) return [3 /*break*/, 4];
|
|
673
|
+
return [4 /*yield*/, handleZapperError({ response: result }, 'getNFTs')];
|
|
674
|
+
case 3:
|
|
675
|
+
_g.sent();
|
|
676
|
+
return [2 /*return*/];
|
|
677
|
+
case 4:
|
|
678
|
+
nftData = (_d = (_c = (_b = result.data) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.portfolioV2) === null || _d === void 0 ? void 0 : _d.nftBalances;
|
|
679
|
+
tokens = ((_f = (_e = nftData === null || nftData === void 0 ? void 0 : nftData.byToken) === null || _e === void 0 ? void 0 : _e.edges) === null || _f === void 0 ? void 0 : _f.map(function (edge) { return edge.node.token; })) || [];
|
|
514
680
|
return [2 /*return*/, {
|
|
515
681
|
items: tokens,
|
|
516
682
|
totalCount: (nftData === null || nftData === void 0 ? void 0 : nftData.totalTokensOwned) || 0,
|
|
517
683
|
totalBalanceUSD: (nftData === null || nftData === void 0 ? void 0 : nftData.totalBalanceUSD) || 0
|
|
518
684
|
}];
|
|
519
|
-
case
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
685
|
+
case 5:
|
|
686
|
+
e_5 = _g.sent();
|
|
687
|
+
return [4 /*yield*/, handleZapperError(e_5, 'getNFTs')];
|
|
688
|
+
case 6:
|
|
689
|
+
_g.sent();
|
|
690
|
+
return [3 /*break*/, 7];
|
|
691
|
+
case 7: return [2 /*return*/];
|
|
524
692
|
}
|
|
525
693
|
});
|
|
526
694
|
});
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pioneer-platform/zapper-client",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.17.0",
|
|
4
4
|
"main": "./lib/index.js",
|
|
5
5
|
"types": "./lib/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@pioneer-platform/loggerdog": "^8.11.0",
|
|
8
|
-
"@pioneer-platform/pioneer-caip": "^9.
|
|
8
|
+
"@pioneer-platform/pioneer-caip": "^9.17.0",
|
|
9
9
|
"axios": "^1.6.0",
|
|
10
10
|
"dotenv": "^8.2.0"
|
|
11
11
|
},
|
package/test-api.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require('dotenv').config({ path: '/Users/highlander/WebstormProjects/keepkey-stack/projects/pioneer/services/pioneer-server/.env' });
|
|
2
|
+
const zapper = require('./lib/index.js');
|
|
3
|
+
|
|
4
|
+
async function test() {
|
|
5
|
+
console.log('Testing Zapper API with key:', process.env.ZAPPER_API_KEY?.substring(0, 10) + '...');
|
|
6
|
+
|
|
7
|
+
const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'; // Vitalik
|
|
8
|
+
console.log('\nFetching portfolio for:', address);
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const result = await zapper.getTotalNetworth(address);
|
|
12
|
+
console.log('Total Net Worth:', result);
|
|
13
|
+
} catch (e) {
|
|
14
|
+
console.error('Error:', e.message);
|
|
15
|
+
if (e.response) {
|
|
16
|
+
console.error('API Response Status:', e.response.status);
|
|
17
|
+
console.error('API Response Data:', e.response.data);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
test();
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require('dotenv').config({ path: '../../../services/pioneer-server/.env' });
|
|
2
|
+
const zapper = require('./lib/index.js');
|
|
3
|
+
|
|
4
|
+
async function test() {
|
|
5
|
+
console.log('\n๐งช Testing Zapper Error Handling...\n');
|
|
6
|
+
console.log('API Key:', process.env.ZAPPER_API_KEY?.substring(0, 10) + '...\n');
|
|
7
|
+
|
|
8
|
+
const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'; // Vitalik
|
|
9
|
+
|
|
10
|
+
console.log('Testing getTotalNetworth()...');
|
|
11
|
+
try {
|
|
12
|
+
const result = await zapper.getTotalNetworth(address);
|
|
13
|
+
console.log('โ
SUCCESS - Total Net Worth: $' + result.toLocaleString());
|
|
14
|
+
} catch (e) {
|
|
15
|
+
console.log('โ ERROR:', e.message);
|
|
16
|
+
console.log(' Code:', e.code);
|
|
17
|
+
console.log(' Status:', e.statusCode);
|
|
18
|
+
console.log(' Name:', e.name);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log('\nTesting getPortfolio()...');
|
|
22
|
+
try {
|
|
23
|
+
const portfolio = await zapper.getPortfolio(address);
|
|
24
|
+
console.log('โ
SUCCESS - Balances:', portfolio.balances?.length || 0);
|
|
25
|
+
console.log(' Total Net Worth: $' + (portfolio.totalNetWorth || 0).toLocaleString());
|
|
26
|
+
} catch (e) {
|
|
27
|
+
console.log('โ ERROR:', e.message);
|
|
28
|
+
console.log(' Code:', e.code);
|
|
29
|
+
console.log(' Status:', e.statusCode);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
test().catch(console.error);
|
package/test-raw-api.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require('dotenv').config({ path: '../../../services/pioneer-server/.env' });
|
|
2
|
+
const axios = require('axios');
|
|
3
|
+
|
|
4
|
+
async function testRawAPI() {
|
|
5
|
+
const API_KEY = process.env.ZAPPER_API_KEY;
|
|
6
|
+
console.log('\n๐งช Testing Raw Zapper GraphQL API...\n');
|
|
7
|
+
console.log('API Key:', API_KEY?.substring(0, 10) + '...\n');
|
|
8
|
+
|
|
9
|
+
const query = {
|
|
10
|
+
query: `
|
|
11
|
+
query PortfolioTotals($addresses: [Address!]!) {
|
|
12
|
+
portfolioV2(addresses: $addresses) {
|
|
13
|
+
tokenBalances {
|
|
14
|
+
totalBalanceUSD
|
|
15
|
+
}
|
|
16
|
+
appBalances {
|
|
17
|
+
totalBalanceUSD
|
|
18
|
+
}
|
|
19
|
+
nftBalances {
|
|
20
|
+
totalBalanceUSD
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
`,
|
|
25
|
+
variables: {
|
|
26
|
+
addresses: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045']
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const response = await axios.post(
|
|
32
|
+
'https://public.zapper.xyz/graphql',
|
|
33
|
+
query,
|
|
34
|
+
{
|
|
35
|
+
headers: {
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
'x-zapper-api-key': API_KEY
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
console.log('๐ฅ RAW API RESPONSE:');
|
|
43
|
+
console.log(JSON.stringify(response.data, null, 2));
|
|
44
|
+
|
|
45
|
+
if (response.data.errors) {
|
|
46
|
+
console.log('\nโ ERRORS DETECTED:');
|
|
47
|
+
response.data.errors.forEach(err => {
|
|
48
|
+
console.log(' - Code:', err.extensions?.code);
|
|
49
|
+
console.log(' - Message:', err.extensions?.message || err.message);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (response.data.data) {
|
|
54
|
+
console.log('\nโ
DATA RECEIVED:');
|
|
55
|
+
const portfolio = response.data.data.portfolioV2;
|
|
56
|
+
console.log(' Tokens USD:', portfolio?.tokenBalances?.totalBalanceUSD);
|
|
57
|
+
console.log(' Apps USD:', portfolio?.appBalances?.totalBalanceUSD);
|
|
58
|
+
console.log(' NFTs USD:', portfolio?.nftBalances?.totalBalanceUSD);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
} catch (e) {
|
|
62
|
+
console.log('โ REQUEST FAILED:', e.message);
|
|
63
|
+
if (e.response) {
|
|
64
|
+
console.log('Status:', e.response.status);
|
|
65
|
+
console.log('Data:', JSON.stringify(e.response.data, null, 2));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
testRawAPI();
|