@taskon/core 0.0.1-beta.1 → 0.0.1-beta.3

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/dist/index.js CHANGED
@@ -195,9 +195,14 @@ function createTaskOnClient(config) {
195
195
  if (userToken) {
196
196
  mergedHeaders["Authorization"] = userToken;
197
197
  }
198
- // Setup timeout
198
+ // Setup timeout.
199
+ // We keep a local flag so abort errors can be classified as timeout vs external abort.
199
200
  const controller = new AbortController();
200
- const timeoutId = setTimeout(() => controller.abort(), timeout);
201
+ let isTimedOut = false;
202
+ const timeoutId = setTimeout(() => {
203
+ isTimedOut = true;
204
+ controller.abort();
205
+ }, timeout);
201
206
  const signal = externalSignal
202
207
  ? combineSignals(externalSignal, controller.signal)
203
208
  : controller.signal;
@@ -213,13 +218,53 @@ function createTaskOnClient(config) {
213
218
  }
214
219
  catch (err) {
215
220
  clearTimeout(timeoutId);
216
- throw err;
221
+ // Normalize transport-layer errors into ApiError so all callers can rely on `code`.
222
+ if (err instanceof ApiError) {
223
+ throw err;
224
+ }
225
+ const isAbortError = err instanceof DOMException
226
+ ? err.name === "AbortError"
227
+ : err instanceof Error
228
+ ? err.name === "AbortError"
229
+ : false;
230
+ if (isAbortError) {
231
+ if (isTimedOut) {
232
+ throw new ApiError("TIMEOUT", `Request timed out after ${timeout}ms`, { timeout, url: fullURL });
233
+ }
234
+ throw new ApiError("REQUEST_ABORTED", "Request was aborted", {
235
+ url: fullURL,
236
+ });
237
+ }
238
+ throw new ApiError("NETWORK_ERROR", err instanceof Error ? err.message : "Network request failed", { url: fullURL, cause: err });
217
239
  }
218
240
  }
219
241
  async function request(options) {
220
242
  // Execute request
221
243
  const response = await executeRequest(options);
222
- const result = (await response.json());
244
+ let result = null;
245
+ // Best-effort JSON parsing:
246
+ // - For non-2xx responses we still want to extract backend error payload if present.
247
+ // - For 2xx responses, invalid JSON should be treated as protocol error.
248
+ try {
249
+ result = (await response.json());
250
+ }
251
+ catch {
252
+ result = null;
253
+ }
254
+ // Fail fast on HTTP non-2xx.
255
+ // fetch() does not throw for HTTP errors, so we must convert them into ApiError manually.
256
+ if (!response.ok) {
257
+ const httpError = new ApiError(result?.error?.code ?? `HTTP_${response.status}`, result?.error?.message ??
258
+ `Request failed with HTTP status ${response.status}`, result?.error?.data);
259
+ if (onAuthError && (response.status === 403 || isAuthError(httpError.code))) {
260
+ onAuthError(httpError);
261
+ }
262
+ throw httpError;
263
+ }
264
+ // HTTP is 2xx but body is not valid JSON: treat as invalid response shape.
265
+ if (!result) {
266
+ throw new ApiError("INVALID_RESPONSE", "Invalid response format: expected JSON body");
267
+ }
223
268
  // Check for auth error (HTTP 403 or specific error codes like NEED_LOGIN, INVALID_USER)
224
269
  if (onAuthError) {
225
270
  if (response.status === 403 || isAuthError(result.error?.code)) {
@@ -1340,14 +1385,15 @@ function normalizeTwitterReply(task) {
1340
1385
  const username = params.twitter_handle || "";
1341
1386
  const desc = params.desc || "";
1342
1387
  const tagEnabled = params.tag_enabled || false;
1343
- const friendsCount = params.friends_count || 0;
1344
1388
  // 生成推文链接
1345
1389
  const tweetLink = username
1346
1390
  ? getTweetUrl(username, tweetId)
1347
1391
  : `https://x.com/i/status/${tweetId}`;
1348
1392
  // 根据 tag_enabled 确定标题
1393
+ // 与 Vue 原版保持一致:ReplyTweet 的好友数量文案固定为 "3 friends"
1394
+ // 不读取 friends_count,避免出现 "0 friends" 等与原版不一致的展示
1349
1395
  const customTitle = tagEnabled
1350
- ? `Reply tweet & tag ${friendsCount} friends`
1396
+ ? "Reply tweet & tag 3 friends"
1351
1397
  : "Reply tweet";
1352
1398
  // Reply 任务使用推文链接作为 action,用户点击后手动回复
1353
1399
  const templateValue = {
@@ -1368,7 +1414,13 @@ function normalizeTwitterReply(task) {
1368
1414
  : [],
1369
1415
  user_identity_type: "Twitter",
1370
1416
  };
1371
- return normalizeTaskParams(task, templateValue);
1417
+ // Vue 原版 Reply 专用组件逻辑保持一致:
1418
+ // Reply 系列标题不使用运营编辑后的 task.name,统一回退到 template_name。
1419
+ const result = normalizeTaskParams(task, templateValue);
1420
+ return {
1421
+ ...result,
1422
+ name: task.template.template_name,
1423
+ };
1372
1424
  }
1373
1425
  /**
1374
1426
  * 标准化 Twitter Reply with HashTag 任务
@@ -1397,14 +1449,15 @@ function normalizeTwitterReplyHashTag(task) {
1397
1449
  const hashTag = params.hash_tag || "";
1398
1450
  const desc = params.desc || "";
1399
1451
  const tagEnabled = params.tag_enabled || false;
1400
- const friendsCount = params.friends_count || 0;
1401
1452
  // 格式化 Hashtag
1402
1453
  const formattedHashTag = formatHashtagLabel(hashTag);
1403
1454
  // 生成推文链接
1404
1455
  const tweetLink = getTweetUrl(username, tweetId);
1405
1456
  // 根据 tag_enabled 确定标题
1457
+ // 与 Vue 原版保持一致:ReplyTweetAndHashTag 的好友数量文案固定为 "3 friends"
1458
+ // 不读取 friends_count,避免出现与原版不一致的动态人数
1406
1459
  const customTitle = tagEnabled
1407
- ? `Reply tweet with hashtag & tag ${friendsCount} friends`
1460
+ ? "Reply tweet with hashtag & tag 3 friends"
1408
1461
  : "Reply tweet with hashtag";
1409
1462
  const templateValue = {
1410
1463
  custom_title: customTitle,
@@ -1422,7 +1475,13 @@ function normalizeTwitterReplyHashTag(task) {
1422
1475
  : [],
1423
1476
  user_identity_type: "Twitter",
1424
1477
  };
1425
- return normalizeTaskParams(task, templateValue);
1478
+ // Vue 原版 Reply 专用组件逻辑保持一致:
1479
+ // Reply 系列标题不使用运营编辑后的 task.name,统一回退到 template_name。
1480
+ const result = normalizeTaskParams(task, templateValue);
1481
+ return {
1482
+ ...result,
1483
+ name: task.template.template_name,
1484
+ };
1426
1485
  }
1427
1486
  /**
1428
1487
  * 标准化 Twitter Quote 任务
@@ -1668,16 +1727,7 @@ function normalizeTelegramJoin(task) {
1668
1727
  user_identity_type: "Telegram",
1669
1728
  is_link_task: !needVerifyBot, // 不需要验证时等同于链接任务
1670
1729
  };
1671
- const normalized = normalizeTaskParams(task, templateValue);
1672
- // Vue 版本 TelegramJoin.vue 无条件使用富文本渲染 desc
1673
- // 这里强制设置 is_rich_text: true 以保持一致
1674
- return {
1675
- ...normalized,
1676
- template: {
1677
- ...normalized.template,
1678
- is_rich_text: true,
1679
- },
1680
- };
1730
+ return normalizeTaskParams(task, templateValue);
1681
1731
  }
1682
1732
 
1683
1733
  /**
@@ -1783,10 +1833,7 @@ function normalizeOuterAPI$1(task) {
1783
1833
  ? SNS_TYPE_MAP[params.sns_type]
1784
1834
  : undefined,
1785
1835
  };
1786
- // OuterAPI 总是作为富文本处理,与 Vue 版本保持一致
1787
- const normalized = normalizeTaskParams(task, normalizedParams);
1788
- normalized.template.is_rich_text = true;
1789
- return normalized;
1836
+ return normalizeTaskParams(task, normalizedParams);
1790
1837
  }
1791
1838
  /**
1792
1839
  * 标准化 OuterPointAPI 任务
@@ -1843,10 +1890,7 @@ function normalizeOuterPointAPI(task) {
1843
1890
  ? SNS_TYPE_MAP[params.sns_type]
1844
1891
  : undefined,
1845
1892
  };
1846
- // OuterPointAPI 总是作为富文本处理,与 Vue 版本保持一致
1847
- const normalized = normalizeTaskParams(task, normalizedParams);
1848
- normalized.template.is_rich_text = true;
1849
- return normalized;
1893
+ return normalizeTaskParams(task, normalizedParams);
1850
1894
  }
1851
1895
 
1852
1896
  /**
@@ -2211,6 +2255,17 @@ function createCommunityTaskApi(client) {
2211
2255
  // Normalize task cards to standardize simple tasks into common template format
2212
2256
  return normalizeTaskCards(res.result);
2213
2257
  },
2258
+ /**
2259
+ * 获取单个社区任务卡片详情
2260
+ * POST /community/v1/getCommunityTaskCardInfo
2261
+ */
2262
+ async getCommunityTaskCardInfo(params) {
2263
+ const res = await client.request({
2264
+ url: "/community/v1/getCommunityTaskCardInfo",
2265
+ data: params,
2266
+ });
2267
+ return normalizeTaskCard(res.result);
2268
+ },
2214
2269
  /**
2215
2270
  * 提交/验证任务
2216
2271
  * POST /community/v1/submitTask
@@ -3577,13 +3632,14 @@ function normalizeReplyTweet(task) {
3577
3632
  const tweetId = params.tweet_id || "";
3578
3633
  const desc = params.desc || "";
3579
3634
  const tagEnabled = params.tag_enabled;
3580
- const friendsCount = params.friends_count || 3;
3581
3635
  // 使用 Twitter intent URL(与 Vue 原版一致)
3582
3636
  const tweetLink = `https://twitter.com/intent/tweet?in_reply_to=${tweetId}`;
3583
3637
  // 构造 title_express:Reply this tweet & tag 3 friends on Twitter
3584
3638
  let titleExpress;
3585
3639
  if (tagEnabled) {
3586
- titleExpress = `Reply {this tweet}[link=${tweetLink}] & tag ${friendsCount} friends on Twitter`;
3640
+ // Vue 原版保持一致:文案固定为 "tag 3 friends"
3641
+ // 不读取 friends_count,避免与原版展示不一致
3642
+ titleExpress = `Reply {this tweet}[link=${tweetLink}] & tag 3 friends on Twitter`;
3587
3643
  }
3588
3644
  else {
3589
3645
  titleExpress = `Reply {this tweet}[link=${tweetLink}]`;
@@ -3605,7 +3661,6 @@ function normalizeReplyTweetAndHashTag(task) {
3605
3661
  const tweetId = params.tweet_id || "";
3606
3662
  const hashTag = params.hash_tag || "";
3607
3663
  const tagEnabled = params.tag_enabled;
3608
- const friendsCount = params.friends_count || 3;
3609
3664
  // 格式化 hashtag 显示(逗号分隔 -> #tag1 #tag2)
3610
3665
  const hashtagDisplay = hashTag
3611
3666
  .split(",")
@@ -3618,10 +3673,12 @@ function normalizeReplyTweetAndHashTag(task) {
3618
3673
  // 构造 title_express:Reply this tweet & tag 3 friends & include "#xxx #yyy" on Twitter
3619
3674
  let titleExpress;
3620
3675
  if (tagEnabled && hashtagDisplay) {
3621
- titleExpress = `Reply {this tweet}[link=${tweetLink}] & tag ${friendsCount} friends & include "${hashtagDisplay}" on Twitter`;
3676
+ // Vue 原版保持一致:文案固定为 "tag 3 friends"
3677
+ // 不读取 friends_count,避免与原版展示不一致
3678
+ titleExpress = `Reply {this tweet}[link=${tweetLink}] & tag 3 friends & include "${hashtagDisplay}" on Twitter`;
3622
3679
  }
3623
3680
  else if (tagEnabled) {
3624
- titleExpress = `Reply {this tweet}[link=${tweetLink}] & tag ${friendsCount} friends on Twitter`;
3681
+ titleExpress = `Reply {this tweet}[link=${tweetLink}] & tag 3 friends on Twitter`;
3625
3682
  }
3626
3683
  else if (hashtagDisplay) {
3627
3684
  titleExpress = `Reply {this tweet}[link=${tweetLink}] & include "${hashtagDisplay}" on Twitter`;
@@ -3734,7 +3791,6 @@ function normalizeJoinTelegram(task) {
3734
3791
  action_label: "Join",
3735
3792
  action_link: inviteLink,
3736
3793
  desc: desc || undefined,
3737
- is_rich_text: true,
3738
3794
  user_identity_type: UserIdentityType.Telegram,
3739
3795
  };
3740
3796
  }
@@ -3778,7 +3834,7 @@ const OUTER_API_SNS_MAP = {
3778
3834
  * 与 CommunityTask normalizer 保持一致:
3779
3835
  * - 有 target_url 时,title 为可点击链接(title_express),按钮文案为 "Start"
3780
3836
  * - 无 target_url 时,使用 custom_title 纯文本
3781
- * - 描述始终以富文本方式渲染(is_rich_text: true)
3837
+ * - 描述由 widget 层统一按富文本方式渲染
3782
3838
  * - 根据 account_type 设置 user_identity_type / network
3783
3839
  */
3784
3840
  function normalizeOuterAPI(task) {
@@ -3786,7 +3842,6 @@ function normalizeOuterAPI(task) {
3786
3842
  return {
3787
3843
  // 描述(富文本)
3788
3844
  desc: params.desc || undefined,
3789
- is_rich_text: true,
3790
3845
  // 图标
3791
3846
  icon: params.icon || undefined,
3792
3847
  // 标题:有 target_url 时使用 title_express 让标题可点击
@@ -4462,23 +4517,9 @@ function createUserCenterApi(client) {
4462
4517
  });
4463
4518
  return res.result;
4464
4519
  },
4465
- async tokenWithdrawFromGasStation(params) {
4520
+ async getTokenWithdrawByNonce(params) {
4466
4521
  const res = await client.request({
4467
- url: "/v1/tokenWithdrawFromGasStation",
4468
- data: params,
4469
- });
4470
- return res.result;
4471
- },
4472
- async getGasStationAirdropResult(params) {
4473
- const res = await client.request({
4474
- url: "/v1/getGasStationAirdropResult",
4475
- data: params,
4476
- });
4477
- return res.result;
4478
- },
4479
- async getTokenWithdrawGasFreeTimes(params) {
4480
- const res = await client.request({
4481
- url: "/v1/getTokenWithdrawGasFreeTimes",
4522
+ url: "/v1/getTokenWithdrawByNonce",
4482
4523
  data: params,
4483
4524
  });
4484
4525
  return res.result;
@@ -4590,20 +4631,6 @@ var LockedType;
4590
4631
  /** 社区里程碑锁定 */
4591
4632
  LockedType["CommunityMilestone"] = "CommunityMilestone";
4592
4633
  })(LockedType || (LockedType = {}));
4593
- // ============================================================================
4594
- // Gas Station(免 Gas 提现)类型
4595
- // ============================================================================
4596
- /**
4597
- * Gas Station 请求状态
4598
- */
4599
- var GasStationRequestStatus;
4600
- (function (GasStationRequestStatus) {
4601
- GasStationRequestStatus["All"] = "All";
4602
- GasStationRequestStatus["Pending"] = "Pending";
4603
- GasStationRequestStatus["Processing"] = "Processing";
4604
- GasStationRequestStatus["Success"] = "Success";
4605
- GasStationRequestStatus["Failed"] = "Failed";
4606
- })(GasStationRequestStatus || (GasStationRequestStatus = {}));
4607
4634
  /**
4608
4635
  * 奖励分发方式
4609
4636
  */
@@ -4992,12 +5019,13 @@ function createNftClaimApi(client) {
4992
5019
  });
4993
5020
  return res.result;
4994
5021
  },
4995
- // =========== Gas Station ===========
4996
- async claimCampaignRewardFromGasStation(params) {
4997
- await client.request({
4998
- url: "/v1/claimCampaignRewardFromGasStation",
5022
+ // =========== Standard NFT ===========
5023
+ async nftWithdraw(params) {
5024
+ const res = await client.request({
5025
+ url: "/v1/nftWithdraw",
4999
5026
  data: params,
5000
5027
  });
5028
+ return res.result;
5001
5029
  },
5002
5030
  };
5003
5031
  }
@@ -5039,8 +5067,6 @@ var NftClaimErrorType;
5039
5067
  // ========== API 相关 ==========
5040
5068
  /** 获取签名失败 */
5041
5069
  NftClaimErrorType["SignatureError"] = "SIGNATURE_ERROR";
5042
- /** Gas Station 次数不足 */
5043
- NftClaimErrorType["GasStationNotEnough"] = "GAS_STATION_NOT_ENOUGH";
5044
5070
  /** API 请求失败 */
5045
5071
  NftClaimErrorType["ApiError"] = "API_ERROR";
5046
5072
  // ========== 数据相关 ==========
@@ -5054,6 +5080,28 @@ var NftClaimErrorType;
5054
5080
  /** 未知错误 */
5055
5081
  NftClaimErrorType["Unknown"] = "UNKNOWN";
5056
5082
  })(NftClaimErrorType || (NftClaimErrorType = {}));
5083
+ /**
5084
+ * 判断 unknown 是否是对象 Record
5085
+ */
5086
+ function isRecord(value) {
5087
+ return typeof value === "object" && value !== null;
5088
+ }
5089
+ /**
5090
+ * 规范化错误字符串。
5091
+ *
5092
+ * 说明:
5093
+ * - 过滤空字符串和 "[object Object]",避免 UI 直接显示不可读文案。
5094
+ */
5095
+ function normalizeErrorText(value) {
5096
+ if (typeof value !== "string") {
5097
+ return null;
5098
+ }
5099
+ const trimmed = value.trim();
5100
+ if (!trimmed || trimmed === "[object Object]") {
5101
+ return null;
5102
+ }
5103
+ return trimmed;
5104
+ }
5057
5105
  // ============================================================================
5058
5106
  // 错误类
5059
5107
  // ============================================================================
@@ -5088,21 +5136,29 @@ class NftClaimError extends Error {
5088
5136
  if (error instanceof NftClaimError) {
5089
5137
  return error;
5090
5138
  }
5091
- const message = error instanceof Error ? error.message : String(error);
5139
+ const message = NftClaimError.extractErrorMessage(error);
5092
5140
  const cause = error instanceof Error ? error : undefined;
5093
5141
  // 尝试识别常见错误类型
5094
- const type = NftClaimError.inferErrorType(message);
5095
- return new NftClaimError(type, message, cause);
5142
+ const type = NftClaimError.inferErrorType(message, error);
5143
+ // 如果解析不出可读文案,则回退到类型默认文案。
5144
+ const fallbackMessage = DEFAULT_ERROR_MESSAGES[type] ?? DEFAULT_ERROR_MESSAGES[NftClaimErrorType.Unknown];
5145
+ const finalMessage = normalizeErrorText(message) ?? fallbackMessage;
5146
+ return new NftClaimError(type, finalMessage, cause);
5096
5147
  }
5097
5148
  /**
5098
5149
  * 根据错误消息推断错误类型
5099
5150
  */
5100
- static inferErrorType(message) {
5151
+ static inferErrorType(message, error) {
5101
5152
  const lowerMessage = message.toLowerCase();
5102
5153
  // 用户拒绝
5103
- if (lowerMessage.includes("user rejected") ||
5154
+ if (NftClaimError.hasUserRejectedCode(error) ||
5155
+ lowerMessage.includes("user rejected") ||
5104
5156
  lowerMessage.includes("user denied") ||
5105
- lowerMessage.includes("cancelled")) {
5157
+ lowerMessage.includes("rejected the request") ||
5158
+ lowerMessage.includes("request rejected") ||
5159
+ lowerMessage.includes("denied transaction") ||
5160
+ lowerMessage.includes("cancelled") ||
5161
+ lowerMessage.includes("canceled")) {
5106
5162
  return NftClaimErrorType.WalletRejected;
5107
5163
  }
5108
5164
  // Gas 不足
@@ -5117,6 +5173,122 @@ class NftClaimError extends Error {
5117
5173
  }
5118
5174
  return NftClaimErrorType.Unknown;
5119
5175
  }
5176
+ /**
5177
+ * 从 unknown 错误中尽量提取可读 message,避免落到 "[object Object]"。
5178
+ */
5179
+ static extractErrorMessage(error) {
5180
+ const visited = new WeakSet();
5181
+ const walk = (value) => {
5182
+ const directText = normalizeErrorText(value);
5183
+ if (directText) {
5184
+ return directText;
5185
+ }
5186
+ if (Array.isArray(value)) {
5187
+ for (const item of value) {
5188
+ const nestedText = walk(item);
5189
+ if (nestedText) {
5190
+ return nestedText;
5191
+ }
5192
+ }
5193
+ return null;
5194
+ }
5195
+ if (value instanceof Error) {
5196
+ const messageText = normalizeErrorText(value.message);
5197
+ if (messageText) {
5198
+ return messageText;
5199
+ }
5200
+ const errorWithCause = value;
5201
+ if ("cause" in errorWithCause) {
5202
+ const causeText = walk(errorWithCause.cause);
5203
+ if (causeText) {
5204
+ return causeText;
5205
+ }
5206
+ }
5207
+ }
5208
+ if (!isRecord(value)) {
5209
+ return null;
5210
+ }
5211
+ if (visited.has(value)) {
5212
+ return null;
5213
+ }
5214
+ visited.add(value);
5215
+ // 常见钱包 / RPC 错误字段优先级
5216
+ const preferredMessageKeys = ["shortMessage", "reason", "details", "message"];
5217
+ for (const key of preferredMessageKeys) {
5218
+ const keyText = normalizeErrorText(value[key]);
5219
+ if (keyText) {
5220
+ return keyText;
5221
+ }
5222
+ }
5223
+ // 常见嵌套错误字段
5224
+ const nestedKeys = [
5225
+ "cause",
5226
+ "error",
5227
+ "data",
5228
+ "originalError",
5229
+ "innerError",
5230
+ "response",
5231
+ ];
5232
+ for (const key of nestedKeys) {
5233
+ const nestedText = walk(value[key]);
5234
+ if (nestedText) {
5235
+ return nestedText;
5236
+ }
5237
+ }
5238
+ return null;
5239
+ };
5240
+ return walk(error) ?? "";
5241
+ }
5242
+ /**
5243
+ * 通过常见错误码识别是否为用户主动取消。
5244
+ */
5245
+ static hasUserRejectedCode(error) {
5246
+ const visited = new WeakSet();
5247
+ const walk = (value) => {
5248
+ if (Array.isArray(value)) {
5249
+ return value.some((item) => walk(item));
5250
+ }
5251
+ if (!isRecord(value)) {
5252
+ return false;
5253
+ }
5254
+ if (visited.has(value)) {
5255
+ return false;
5256
+ }
5257
+ visited.add(value);
5258
+ const errorCode = value.code;
5259
+ if (typeof errorCode === "number" && errorCode === 4001) {
5260
+ return true;
5261
+ }
5262
+ if (typeof errorCode === "string") {
5263
+ const normalizedCode = errorCode.toUpperCase();
5264
+ if (normalizedCode.includes("USER_REJECT") ||
5265
+ normalizedCode.includes("ACTION_REJECTED") ||
5266
+ normalizedCode.includes("REJECTED_REQUEST")) {
5267
+ return true;
5268
+ }
5269
+ }
5270
+ const errorName = value.name;
5271
+ if (typeof errorName === "string" &&
5272
+ errorName.toLowerCase().includes("userrejected")) {
5273
+ return true;
5274
+ }
5275
+ const nestedKeys = [
5276
+ "cause",
5277
+ "error",
5278
+ "data",
5279
+ "originalError",
5280
+ "innerError",
5281
+ "response",
5282
+ ];
5283
+ for (const key of nestedKeys) {
5284
+ if (walk(value[key])) {
5285
+ return true;
5286
+ }
5287
+ }
5288
+ return false;
5289
+ };
5290
+ return walk(error);
5291
+ }
5120
5292
  /**
5121
5293
  * 判断是否是用户主动取消
5122
5294
  */
@@ -5153,7 +5325,6 @@ const DEFAULT_ERROR_MESSAGES = {
5153
5325
  [NftClaimErrorType.TransactionFailed]: "Transaction failed.",
5154
5326
  [NftClaimErrorType.InsufficientGas]: "Insufficient gas. Please add more funds to your wallet.",
5155
5327
  [NftClaimErrorType.SignatureError]: "Failed to get signature from server.",
5156
- [NftClaimErrorType.GasStationNotEnough]: "Gas station quota exceeded. Please try again later.",
5157
5328
  [NftClaimErrorType.ApiError]: "API request failed. Please try again.",
5158
5329
  [NftClaimErrorType.MissingRewardId]: "Missing reward information.",
5159
5330
  [NftClaimErrorType.NotClaimable]: "This NFT is not claimable.",
@@ -5233,6 +5404,239 @@ class NftTransaction {
5233
5404
  }
5234
5405
  }
5235
5406
 
5407
+ var nftWithdrawAbi = [
5408
+ {
5409
+ inputs: [
5410
+ {
5411
+ internalType: "uint256",
5412
+ name: "userId",
5413
+ type: "uint256"
5414
+ },
5415
+ {
5416
+ internalType: "enum TaskonFundNFT.NFTType",
5417
+ name: "ty",
5418
+ type: "uint8"
5419
+ },
5420
+ {
5421
+ internalType: "address",
5422
+ name: "nftCollection",
5423
+ type: "address"
5424
+ },
5425
+ {
5426
+ components: [
5427
+ {
5428
+ internalType: "uint256",
5429
+ name: "tokenId",
5430
+ type: "uint256"
5431
+ },
5432
+ {
5433
+ internalType: "uint256",
5434
+ name: "amount",
5435
+ type: "uint256"
5436
+ }
5437
+ ],
5438
+ internalType: "struct TaskonFundNFT.WithdrawTokenAmount[]",
5439
+ name: "tokenAmounts",
5440
+ type: "tuple[]"
5441
+ },
5442
+ {
5443
+ internalType: "address",
5444
+ name: "receiver",
5445
+ type: "address"
5446
+ },
5447
+ {
5448
+ internalType: "uint256",
5449
+ name: "nonce",
5450
+ type: "uint256"
5451
+ },
5452
+ {
5453
+ internalType: "uint256",
5454
+ name: "expiredHeight",
5455
+ type: "uint256"
5456
+ },
5457
+ {
5458
+ internalType: "bytes[]",
5459
+ name: "sigs",
5460
+ type: "bytes[]"
5461
+ }
5462
+ ],
5463
+ name: "withdraw",
5464
+ outputs: [
5465
+ ],
5466
+ stateMutability: "nonpayable",
5467
+ type: "function"
5468
+ }
5469
+ ];
5470
+
5471
+ /**
5472
+ * Withdraw Standard NFT 交易类
5473
+ *
5474
+ * 用于领取普通 NFT 奖励(RewardType.Nft)
5475
+ * 逻辑与主站 WithdrawNft 保持一致:
5476
+ * 1. 调 /v1/nftWithdraw 获取签名参数
5477
+ * 2. 调 TaskOnFundNFT 合约 withdraw 方法
5478
+ */
5479
+ /**
5480
+ * 获取 NFT 类型枚举值(与主站保持一致)
5481
+ * - ERC721 => 0
5482
+ * - ERC1155 => 1
5483
+ */
5484
+ function getNftTypeValue(nftType) {
5485
+ return nftType === "ERC1155" ? 1 : 0;
5486
+ }
5487
+ /**
5488
+ * 将 token 数组转换成合约 withdraw 参数格式
5489
+ */
5490
+ function toWithdrawTokenAmounts(tokens) {
5491
+ return tokens.map((item) => ({
5492
+ tokenId: BigInt(item.tokenId),
5493
+ amount: BigInt(item.amount),
5494
+ }));
5495
+ }
5496
+ /**
5497
+ * 简易 ABI 编码器
5498
+ *
5499
+ * 由于 core 模块保持框架无关,不直接依赖 viem/ethers 编码。
5500
+ * 这里返回结构化数据供上层钱包实现处理。
5501
+ */
5502
+ function encodeWithdrawData(params) {
5503
+ return JSON.stringify({
5504
+ method: "withdraw",
5505
+ params: {
5506
+ userId: params.userId,
5507
+ nftType: getNftTypeValue(params.nftType),
5508
+ nftContract: params.nftContract,
5509
+ tokens: params.tokens,
5510
+ receiverAddress: params.receiverAddress,
5511
+ nonce: params.nonce,
5512
+ expiredHeight: params.expiredHeight,
5513
+ signatures: params.signatures,
5514
+ },
5515
+ abi: nftWithdrawAbi,
5516
+ });
5517
+ }
5518
+ /**
5519
+ * Standard NFT Withdraw 交易类
5520
+ */
5521
+ class WithdrawNft extends NftTransaction {
5522
+ /** API 实例 */
5523
+ api;
5524
+ /** 用户 ID */
5525
+ userId;
5526
+ /** 链名称 */
5527
+ chainName;
5528
+ /** target id(campaign/event id) */
5529
+ targetId;
5530
+ /** target type */
5531
+ targetType;
5532
+ /** 奖励 ID */
5533
+ rewardId;
5534
+ /** TaskOnFund NFT 合约地址 */
5535
+ taskonfundNftContract;
5536
+ /** NFT collection id */
5537
+ collectionId;
5538
+ /** NFT 合约地址 */
5539
+ nftContract;
5540
+ /** NFT 类型 */
5541
+ nftType;
5542
+ /** token 列表 */
5543
+ tokens;
5544
+ /** 重发接收地址 */
5545
+ receiveAddress;
5546
+ /** 重发 nonce */
5547
+ nonce;
5548
+ constructor(params) {
5549
+ super(params);
5550
+ this.api = params.api;
5551
+ this.userId = params.userId;
5552
+ this.chainName = params.chainName;
5553
+ this.targetId = params.targetId;
5554
+ this.targetType = params.targetType;
5555
+ this.rewardId = params.rewardId;
5556
+ this.taskonfundNftContract = params.taskonfundNftContract;
5557
+ this.collectionId = params.collectionId;
5558
+ this.nftContract = params.nftContract;
5559
+ this.nftType = params.nftType;
5560
+ this.tokens = params.tokens;
5561
+ this.receiveAddress = params.receiveAddress;
5562
+ this.nonce = params.nonce;
5563
+ }
5564
+ /**
5565
+ * 执行 Standard NFT withdraw
5566
+ */
5567
+ async withdraw() {
5568
+ await this.checkAccountAndNetwork();
5569
+ const isResend = Boolean(this.receiveAddress && this.nonce);
5570
+ const receiverAddress = isResend
5571
+ ? this.receiveAddress
5572
+ : this.userAddress;
5573
+ const sigRes = await this.api.nftWithdraw({
5574
+ chain: this.chainName,
5575
+ collection_id: this.collectionId,
5576
+ receiver_address: receiverAddress,
5577
+ token_ids: this.tokens.map((item) => ({
5578
+ token_id: item.tokenId,
5579
+ quantity: item.amount,
5580
+ })),
5581
+ ...(this.targetType === "campaign" || this.targetType === "event"
5582
+ ? {
5583
+ campaign_id: this.targetId,
5584
+ reward_id: this.rewardId,
5585
+ }
5586
+ : undefined),
5587
+ ...(isResend
5588
+ ? {
5589
+ nonce: this.nonce,
5590
+ }
5591
+ : undefined),
5592
+ });
5593
+ return this.invokeWithdraw(sigRes, receiverAddress);
5594
+ }
5595
+ /**
5596
+ * 与 NftTransaction 接口保持一致
5597
+ */
5598
+ async claim() {
5599
+ return this.withdraw();
5600
+ }
5601
+ /**
5602
+ * 获取合约调用参数(供外部编码库使用)
5603
+ */
5604
+ getContractCallParams(withdrawResult) {
5605
+ const receiverAddress = this.receiveAddress ?? this.userAddress;
5606
+ return {
5607
+ contractAddress: this.taskonfundNftContract,
5608
+ methodName: "withdraw",
5609
+ args: [
5610
+ BigInt(this.userId),
5611
+ getNftTypeValue(this.nftType),
5612
+ this.nftContract,
5613
+ toWithdrawTokenAmounts(this.tokens),
5614
+ receiverAddress,
5615
+ BigInt(withdrawResult.nonce),
5616
+ BigInt(withdrawResult.expired_height),
5617
+ withdrawResult.signatures,
5618
+ ],
5619
+ abi: nftWithdrawAbi,
5620
+ };
5621
+ }
5622
+ /**
5623
+ * 执行链上 withdraw 调用
5624
+ */
5625
+ async invokeWithdraw(withdrawResult, receiverAddress) {
5626
+ const data = encodeWithdrawData({
5627
+ userId: this.userId,
5628
+ nftType: this.nftType,
5629
+ nftContract: this.nftContract,
5630
+ tokens: this.tokens,
5631
+ receiverAddress,
5632
+ nonce: withdrawResult.nonce,
5633
+ expiredHeight: withdrawResult.expired_height,
5634
+ signatures: withdrawResult.signatures,
5635
+ });
5636
+ return this.sendTransaction(this.taskonfundNftContract, data);
5637
+ }
5638
+ }
5639
+
5236
5640
  var bMintedNftAbi = [
5237
5641
  {
5238
5642
  inputs: [
@@ -5568,6 +5972,7 @@ function encodeMintData(account, cid, tokenUri, limit, unsigned, signature) {
5568
5972
  * chainId: 1,
5569
5973
  * userAddress: '0x...',
5570
5974
  * sigRes: apiResponse,
5975
+ * contractAddress: chain.contract,
5571
5976
  * });
5572
5977
  *
5573
5978
  * const txHash = await tx.claim();
@@ -5576,9 +5981,12 @@ function encodeMintData(account, cid, tokenUri, limit, unsigned, signature) {
5576
5981
  class ClaimCapNft extends NftTransaction {
5577
5982
  /** API 返回的签名响应 */
5578
5983
  sigRes;
5984
+ /** CAP NFT 合约地址(对齐主站 chain.contract) */
5985
+ contractAddress;
5579
5986
  constructor(params) {
5580
5987
  super(params);
5581
5988
  this.sigRes = params.sigRes;
5989
+ this.contractAddress = params.contractAddress;
5582
5990
  }
5583
5991
  /**
5584
5992
  * 执行 Claim 操作
@@ -5595,7 +6003,7 @@ class ClaimCapNft extends NftTransaction {
5595
6003
  // 2. 编码合约调用数据
5596
6004
  const data = encodeMintData(this.userAddress, BigInt(this.sigRes.campaign_id), this.sigRes.token_uri, BigInt(this.sigRes.total), this.sigRes.hash, this.sigRes.signature);
5597
6005
  // 3. 调用合约
5598
- return this.sendTransaction(this.sigRes.contract_address, data);
6006
+ return this.sendTransaction(this.contractAddress, data);
5599
6007
  }
5600
6008
  /**
5601
6009
  * 获取合约调用参数(用于外部编码)
@@ -5604,7 +6012,7 @@ class ClaimCapNft extends NftTransaction {
5604
6012
  */
5605
6013
  getContractCallParams() {
5606
6014
  return {
5607
- contractAddress: this.sigRes.contract_address,
6015
+ contractAddress: this.contractAddress,
5608
6016
  methodName: "mint",
5609
6017
  args: [
5610
6018
  this.userAddress,
@@ -5636,17 +6044,15 @@ class ClaimCapNft extends NftTransaction {
5636
6044
  * }
5637
6045
  * }
5638
6046
  *
5639
- * pendingKey 格式:
5640
- * - Minted NFT: `minted-${campaignId}-${rewardId}`
5641
- * - CAP NFT: `cap-${campaignId}-${rewardId}`
6047
+ * pendingKey 格式(与主站保持一致):
6048
+ * - Campaign: `campaign-${targetId}-${rewardId}`
6049
+ * - Event: `event-${targetId}-${rewardId}`
5642
6050
  */
5643
6051
  // ============================================================================
5644
6052
  // 常量定义
5645
6053
  // ============================================================================
5646
6054
  /** localStorage 存储 key */
5647
6055
  const STORAGE_KEY = "taskon_nft_pending";
5648
- /** Pending 记录过期时间(24 小时) */
5649
- const PENDING_EXPIRE_TIME = 24 * 60 * 60 * 1000;
5650
6056
  // ============================================================================
5651
6057
  // 内部辅助函数
5652
6058
  // ============================================================================
@@ -5689,13 +6095,13 @@ function savePendingHashMap(map) {
5689
6095
  /**
5690
6096
  * 生成 Pending Key
5691
6097
  *
5692
- * @param nftType - NFT 类型(minted / cap)
6098
+ * @param targetType - claim 目标类型(campaign / event / 其他业务前缀)
5693
6099
  * @param campaignId - Campaign ID
5694
6100
  * @param rewardId - 奖励 ID
5695
6101
  * @returns 格式化的 pending key
5696
6102
  */
5697
- function generatePendingKey(nftType, campaignId, rewardId) {
5698
- return `${nftType}-${campaignId}-${rewardId}`;
6103
+ function generatePendingKey(targetType, campaignId, rewardId) {
6104
+ return `${targetType}-${campaignId}-${rewardId}`;
5699
6105
  }
5700
6106
  /**
5701
6107
  * 设置 Pending Hash
@@ -5724,7 +6130,7 @@ function setPendingHash(userId, pendingKey, hash, chainName) {
5724
6130
  *
5725
6131
  * @param userId - 用户 ID
5726
6132
  * @param pendingKey - Pending Key
5727
- * @returns Pending 信息,如果不存在或已过期则返回 null
6133
+ * @returns Pending 信息,如果不存在则返回 null
5728
6134
  */
5729
6135
  function getPendingHash(userId, pendingKey) {
5730
6136
  const map = getPendingHashMap();
@@ -5732,12 +6138,8 @@ function getPendingHash(userId, pendingKey) {
5732
6138
  if (!pending) {
5733
6139
  return null;
5734
6140
  }
5735
- // 检查是否过期
5736
- if (Date.now() - pending.timestamp > PENDING_EXPIRE_TIME) {
5737
- // 清除过期的 pending
5738
- clearPendingHash(userId, pendingKey);
5739
- return null;
5740
- }
6141
+ // 与原版 Vue 行为保持一致:
6142
+ // pending 记录不做自动过期清理,仅在业务显式 clear 时移除。
5741
6143
  return pending;
5742
6144
  }
5743
6145
  /**
@@ -5765,15 +6167,9 @@ function clearPendingHash(userId, pendingKey) {
5765
6167
  */
5766
6168
  function getUserPendingHashes(userId) {
5767
6169
  const map = getPendingHashMap();
5768
- const userPending = map[userId] || {};
5769
- const result = {};
5770
- // 过滤掉过期的
5771
- for (const [key, pending] of Object.entries(userPending)) {
5772
- if (Date.now() - pending.timestamp <= PENDING_EXPIRE_TIME) {
5773
- result[key] = pending;
5774
- }
5775
- }
5776
- return result;
6170
+ // 返回浅拷贝,避免调用方直接改写内部引用对象。
6171
+ // 这里不做任何 TTL 过滤,策略与原版保持一致。
6172
+ return { ...(map[userId] || {}) };
5777
6173
  }
5778
6174
  /**
5779
6175
  * 清除用户所有的 Pending Hash
@@ -5789,45 +6185,21 @@ function clearAllUserPendingHashes(userId) {
5789
6185
  }
5790
6186
  /**
5791
6187
  * 清除所有过期的 Pending Hash
5792
- * 可以在应用启动时调用
6188
+ *
6189
+ * 为兼容历史 API 而保留:
6190
+ * 当前策略已改为与原版一致(无自动过期),因此该函数不执行任何操作。
5793
6191
  */
5794
6192
  function cleanupExpiredPendingHashes() {
5795
- const map = getPendingHashMap();
5796
- let hasChanges = false;
5797
- for (const userId of Object.keys(map)) {
5798
- const numUserId = Number(userId);
5799
- const userMap = map[numUserId];
5800
- // 跳过不存在的用户映射
5801
- if (!userMap) {
5802
- continue;
5803
- }
5804
- for (const pendingKey of Object.keys(userMap)) {
5805
- const pending = userMap[pendingKey];
5806
- // 跳过不存在的 pending
5807
- if (!pending) {
5808
- continue;
5809
- }
5810
- if (Date.now() - pending.timestamp > PENDING_EXPIRE_TIME) {
5811
- delete userMap[pendingKey];
5812
- hasChanges = true;
5813
- }
5814
- }
5815
- // 如果用户没有其他 pending,清除用户条目
5816
- if (Object.keys(userMap).length === 0) {
5817
- delete map[numUserId];
5818
- hasChanges = true;
5819
- }
5820
- }
5821
- if (hasChanges) {
5822
- savePendingHashMap(map);
5823
- }
6193
+ // 兼容导出 API:
6194
+ // 旧版本存在基于 24h TTL 的自动清理逻辑;
6195
+ // 当前为对齐原版,此函数改为 no-op,保留仅用于避免破坏性升级。
5824
6196
  }
5825
6197
 
5826
6198
  /**
5827
6199
  * NftClaim 模块类型定义
5828
6200
  *
5829
6201
  * 包含 NFT Claim 所需的所有类型定义
5830
- * 支持 Minted NFT CAP NFT 两种类型
6202
+ * 支持 Standard NFT / Minted NFT / CAP NFT 三种类型
5831
6203
  */
5832
6204
  // ============================================================================
5833
6205
  // NFT 类型枚举
@@ -5837,6 +6209,8 @@ function cleanupExpiredPendingHashes() {
5837
6209
  */
5838
6210
  var NftClaimType;
5839
6211
  (function (NftClaimType) {
6212
+ /** 标准 NFT(使用 TaskOnFundNFT withdraw 方法) */
6213
+ NftClaimType["Standard"] = "standard";
5840
6214
  /** B 端铸造的 NFT(使用 claim 合约方法) */
5841
6215
  NftClaimType["Minted"] = "minted";
5842
6216
  /** TaskOn 平台 NFT(使用 mint 合约方法) */
@@ -5867,8 +6241,17 @@ function isMintedNftReward(value) {
5867
6241
  * CAP NFT 特征:有 gas_covered_by 字段但没有 nft_address
5868
6242
  */
5869
6243
  function isCapNftReward(value) {
5870
- return ("gas_covered_by" in value &&
5871
- !("nft_address" in value));
6244
+ return "gas_covered_by" in value && !("nft_address" in value);
6245
+ }
6246
+ /**
6247
+ * 判断 NFT 奖励值是否是 Standard NFT 类型
6248
+ *
6249
+ * Standard NFT 特征:有 nft_address 且没有 gas_covered_by
6250
+ */
6251
+ function isStandardNftReward(value) {
6252
+ return ("nft_address" in value &&
6253
+ !("gas_covered_by" in value) &&
6254
+ typeof value.nft_address === "string");
5872
6255
  }
5873
6256
  /**
5874
6257
  * 获取 NFT Claim 类型
@@ -5880,7 +6263,10 @@ function getNftClaimType(value) {
5880
6263
  if (isCapNftReward(value)) {
5881
6264
  return NftClaimType.Cap;
5882
6265
  }
5883
- return NftClaimType.Minted;
6266
+ if (isMintedNftReward(value)) {
6267
+ return NftClaimType.Minted;
6268
+ }
6269
+ return NftClaimType.Standard;
5884
6270
  }
5885
6271
  // ============================================================================
5886
6272
  // 奖励值属性提取
@@ -5906,17 +6292,6 @@ function getGasCoveredBy(value) {
5906
6292
  }
5907
6293
  return undefined;
5908
6294
  }
5909
- /**
5910
- * 判断是否使用 Gas Station(项目方/TaskOn 代付 Gas)
5911
- *
5912
- * @param value - NFT 奖励值
5913
- * @returns 是否使用 Gas Station
5914
- */
5915
- function shouldUseGasStation(value) {
5916
- const gasCoveredBy = getGasCoveredBy(value);
5917
- return (gasCoveredBy === GasCoveredByType$1.Creator ||
5918
- gasCoveredBy === GasCoveredByType$1.Taskon);
5919
- }
5920
6295
  /**
5921
6296
  * 获取 NFT 的 collection_id
5922
6297
  *
@@ -6230,4 +6605,4 @@ function parsePageBuilderConfig(configJson) {
6230
6605
  }
6231
6606
  }
6232
6607
 
6233
- export { ApiError, AutomaticallyWinnerDrawType$1 as AutomaticallyWinnerDrawType, CampaignAuditResult, CampaignStatus, CampaignType$1 as CampaignType, Chain$1 as Chain, ChainType, ChangeType, ClaimCapNft, ClaimMintedNft, CommonTemplateAssetType, CommunityStatus, DEFAULT_DISPLAY_OPTIONS, DEFAULT_ERROR_MESSAGES, DEFAULT_PAGE_BUILDER_CONFIG, EligibilityTemplateId, EligibilityType, EligiblityExpression, ErrorCode, FROZEN_ASSETS_PAGE_SIZE, GasCoveredByType$1 as GasCoveredByType, GasStationRequestStatus, GetTaskClass, LEADERBOARD_ROWS_OPTIONS, LEADERBOARD_TABLE_COLUMNS_BY_TYPE, LEADERBOARD_TYPE_LABELS, LeaderboardContentType, LeaderboardTableColumn, LeaderboardTableColumnRequirement, LockedType, MediaType$1 as MediaType, MeetConditionStatus, MilestoneMetricType$1 as MilestoneMetricType, NftClaimError, NftClaimErrorType, NftClaimType, NftTransaction, Operator, OuterAPIAccountType, OuterAPISnsType, PAGE_BUILDER_CONFIG_VERSION, PowTaskType, ProjectCategory, AutomaticallyWinnerDrawType as QuestAutomaticallyWinnerDrawType, MilestoneMetricType as QuestMilestoneMetricType, NftType$1 as QuestNftType, RecurrenceType as QuestRecurrenceType, RewardType as QuestRewardType, RewardsDistributeType as QuestRewardsDistributeType, TokenType as QuestTokenType, WinnerDrawType as QuestWinnerDrawType, WinnerRangeType as QuestWinnerRangeType, RecurrenceType$1 as RecurrenceType, RewardDistributedByType$1 as RewardDistributedByType, RewardType, RewardWhiteListType, RewardsDistributeType$1 as RewardsDistributeType, RouletteRewardType, SECTION_LAYOUT_RATIOS, SectionLayoutType, SnsType, TaskCardType, TaskReviewResult, TaskStatus, TaskTemplateId, TokenType$1 as TokenType, USER_CENTER_PAGE_SIZE, USER_CENTER_REWARD_CARD_LABELS, USER_CENTER_REWARD_CARD_TYPES, USER_CENTER_TAB_LABELS, UserCenterAccountType, UserCenterChainType, UserCenterRewardCardType, UserCenterTabType, UserEligibleStatus, UserIdentityType, VerifyCodeType, WidgetTypeEnum, WinnerDrawType$1 as WinnerDrawType, WinnerRangeType$1 as WinnerRangeType, apiIcon, bMintedNftAbi, buildSwapTokenText, calculatePrizePool, capNftAbi, checkinIcon, cleanupExpiredPendingHashes, clearAllUserPendingHashes, clearPendingHash, contractInteractiveIcon, createChainApi, createCommonApi, createCommunityTaskApi, createLeaderboardApi, createNftClaimApi, createPageBuilderApi, createQuestApi, createTaskOnClient, createUserApi, createUserCenterApi, createWidgetApi, discordIcon, filterEnabledAccounts, filterEnabledCards, filterEnabledTabs, filterEnabledWallets, formatAddress, formatLocalDate, formatLongNumber, formatRankRange, formatRewardText, formatSwapTokensForDisplay, formatTokenAmount, formatTxHash, formatUtcDuration, formatUtcTime, formatWalletAddress, generateLeaderboardId, generatePendingKey, getChainIcon, getChainName, getCollectionId, getDefaultColumns, getDefaultTabConfig, getDefaultTitle, getGasCoveredBy, getNftChainName, getNftClaimType, getPendingHash, getReceiverAddress, getSocialIcon, getSwapDexTitleExpress, getTxExplorerLink, getTxExplorerUrl, getUserPendingHashes, isAllTimeResponse, isCampaignResponse, isCapNftReward, isManualDrop, isMintedNftReward, isNftClaimable, isNftClaimed, isUnauthorizedError, linkIcon, needsCustomComponent, normalizeCampaignInfo, normalizeQuestTask, normalizeQuestTaskInput, normalizeQuestTasks, normalizeTask, normalizeTaskCards, openInNewTab, parsePageBuilderConfig, parseTitleExpress, parseWidgetConfig, powIcon, quizIcon, retweetIcon, setPendingHash, shouldUseGasStation, signMessage, telegramIcon, toWei, tokenIcon, truncateAddress, twitterIcon };
6608
+ export { ApiError, AutomaticallyWinnerDrawType$1 as AutomaticallyWinnerDrawType, CampaignAuditResult, CampaignStatus, CampaignType$1 as CampaignType, Chain$1 as Chain, ChainType, ChangeType, ClaimCapNft, ClaimMintedNft, CommonTemplateAssetType, CommunityStatus, DEFAULT_DISPLAY_OPTIONS, DEFAULT_ERROR_MESSAGES, DEFAULT_PAGE_BUILDER_CONFIG, EligibilityTemplateId, EligibilityType, EligiblityExpression, ErrorCode, FROZEN_ASSETS_PAGE_SIZE, GasCoveredByType$1 as GasCoveredByType, GetTaskClass, LEADERBOARD_ROWS_OPTIONS, LEADERBOARD_TABLE_COLUMNS_BY_TYPE, LEADERBOARD_TYPE_LABELS, LeaderboardContentType, LeaderboardTableColumn, LeaderboardTableColumnRequirement, LockedType, MediaType$1 as MediaType, MeetConditionStatus, MilestoneMetricType$1 as MilestoneMetricType, NftClaimError, NftClaimErrorType, NftClaimType, NftTransaction, Operator, OuterAPIAccountType, OuterAPISnsType, PAGE_BUILDER_CONFIG_VERSION, PowTaskType, ProjectCategory, AutomaticallyWinnerDrawType as QuestAutomaticallyWinnerDrawType, MilestoneMetricType as QuestMilestoneMetricType, NftType$1 as QuestNftType, RecurrenceType as QuestRecurrenceType, RewardType as QuestRewardType, RewardsDistributeType as QuestRewardsDistributeType, TokenType as QuestTokenType, WinnerDrawType as QuestWinnerDrawType, WinnerRangeType as QuestWinnerRangeType, RecurrenceType$1 as RecurrenceType, RewardDistributedByType$1 as RewardDistributedByType, RewardType, RewardWhiteListType, RewardsDistributeType$1 as RewardsDistributeType, RouletteRewardType, SECTION_LAYOUT_RATIOS, SectionLayoutType, SnsType, TaskCardType, TaskReviewResult, TaskStatus, TaskTemplateId, TokenType$1 as TokenType, USER_CENTER_PAGE_SIZE, USER_CENTER_REWARD_CARD_LABELS, USER_CENTER_REWARD_CARD_TYPES, USER_CENTER_TAB_LABELS, UserCenterAccountType, UserCenterChainType, UserCenterRewardCardType, UserCenterTabType, UserEligibleStatus, UserIdentityType, VerifyCodeType, WidgetTypeEnum, WinnerDrawType$1 as WinnerDrawType, WinnerRangeType$1 as WinnerRangeType, WithdrawNft, apiIcon, bMintedNftAbi, buildSwapTokenText, calculatePrizePool, capNftAbi, checkinIcon, cleanupExpiredPendingHashes, clearAllUserPendingHashes, clearPendingHash, contractInteractiveIcon, createChainApi, createCommonApi, createCommunityTaskApi, createLeaderboardApi, createNftClaimApi, createPageBuilderApi, createQuestApi, createTaskOnClient, createUserApi, createUserCenterApi, createWidgetApi, discordIcon, filterEnabledAccounts, filterEnabledCards, filterEnabledTabs, filterEnabledWallets, formatAddress, formatLocalDate, formatLongNumber, formatRankRange, formatRewardText, formatSwapTokensForDisplay, formatTokenAmount, formatTxHash, formatUtcDuration, formatUtcTime, formatWalletAddress, generateLeaderboardId, generatePendingKey, getChainIcon, getChainName, getCollectionId, getDefaultColumns, getDefaultTabConfig, getDefaultTitle, getGasCoveredBy, getNftChainName, getNftClaimType, getPendingHash, getReceiverAddress, getSocialIcon, getSwapDexTitleExpress, getTxExplorerLink, getTxExplorerUrl, getUserPendingHashes, isAllTimeResponse, isCampaignResponse, isCapNftReward, isManualDrop, isMintedNftReward, isNftClaimable, isNftClaimed, isStandardNftReward, isUnauthorizedError, linkIcon, needsCustomComponent, nftWithdrawAbi, normalizeCampaignInfo, normalizeQuestTask, normalizeQuestTaskInput, normalizeQuestTasks, normalizeTask, normalizeTaskCards, openInNewTab, parsePageBuilderConfig, parseTitleExpress, parseWidgetConfig, powIcon, quizIcon, retweetIcon, setPendingHash, signMessage, telegramIcon, toWei, tokenIcon, truncateAddress, twitterIcon };