@metamask/social-controllers 3.7.0 → 3.9.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.
@@ -4,7 +4,7 @@ import type { CreateServicePolicyOptions } from '@metamask/controller-utils';
4
4
  import type { Messenger } from '@metamask/messenger';
5
5
  import type { AuthenticationController } from '@metamask/profile-sync-controller';
6
6
  import { serviceName } from './social-constants.js';
7
- import type { BlockedContentResponse, BlockedProfilesResponse, BlockOptions, CommentEngagement, CreateSwapCommentOptions, FeedResponse, FetchBlockedListOptions, FetchFeedOptions, FetchFollowersOptions, FetchTraderFollowingOptions, FetchLeaderboardOptions, FetchPositionByIdOptions, FetchPositionsOptions, FetchTokenFeedOptions, FetchTraderFeedOptions, FetchTraderProfileOptions, FollowersResponse, FollowingResponse, FollowOptions, FollowResponse, LeaderboardResponse, Position, PositionsResponse, ReactToCommentOptions, RemoveCommentReactionOptions, SwapCommentResponse, TraderProfileResponse, UnfollowOptions, UnfollowResponse } from './social-types.js';
7
+ import type { BlockedContentResponse, BlockedProfilesResponse, BlockOptions, CommentEngagement, CopyTradeIntentResponse, CreateCopyTradeIntentOptions, CreateSwapCommentOptions, FeedResponse, FetchBlockedListOptions, FetchFeedOptions, FetchFollowersOptions, FetchTraderFollowingOptions, FetchLeaderboardOptions, FetchPositionByIdOptions, FetchPositionsOptions, FetchTokenFeedOptions, FetchTraderFeedOptions, FetchTraderProfileOptions, FollowersResponse, FollowingResponse, FollowOptions, FollowResponse, LeaderboardResponse, Position, PositionsResponse, ReactToCommentOptions, RemoveCommentReactionOptions, SwapCommentResponse, TraderProfileResponse, UnfollowOptions, UnfollowResponse } from './social-types.js';
8
8
  import type { SocialServiceMethodActions } from './SocialService-method-action-types.js';
9
9
  export type SocialServiceActions = SocialServiceMethodActions | DataServiceInvalidateQueriesAction<typeof serviceName>;
10
10
  export type SocialServiceEvents = DataServiceCacheUpdatedEvent<typeof serviceName> | DataServiceGranularCacheUpdatedEvent<typeof serviceName>;
@@ -35,6 +35,9 @@ export declare class SocialService extends BaseDataService<typeof serviceName, S
35
35
  *
36
36
  * Calls `GET ${baseUrl}/traders/${addressOrId}/profile`.
37
37
  *
38
+ * `profile.createdAt` is optional. When present it is an ISO-8601 timestamp
39
+ * for when the social-api profile row was inserted.
40
+ *
38
41
  * @param options - Options bag.
39
42
  * @param options.addressOrId - Wallet address or Clicker profile ID.
40
43
  * @returns The trader profile response.
@@ -117,7 +120,8 @@ export declare class SocialService extends BaseDataService<typeof serviceName, S
117
120
  * `pagination.newerCursor` as `newerThan` to fetch newer items.
118
121
  *
119
122
  * @param options - Options bag.
120
- * @param options.scope - `following` (default) or `leaderboard`.
123
+ * @param options.scope - `following` (default), `leaderboard`, `all`, or
124
+ * `trending`.
121
125
  * @param options.chains - Filter by one or more chains.
122
126
  * @param options.limit - Number of results per page.
123
127
  * @param options.olderThan - Cursor for older items (scroll down).
@@ -216,6 +220,23 @@ export declare class SocialService extends BaseDataService<typeof serviceName, S
216
220
  * @returns The created swap comment.
217
221
  */
218
222
  createSwapComment(options: CreateSwapCommentOptions): Promise<SwapCommentResponse>;
223
+ /**
224
+ * Records that the current user is copying a trade from a social post, so
225
+ * the copy can be detected and attributed to the post's author.
226
+ *
227
+ * Calls `POST ${baseUrl}/copy-trade-intents`. Send swaps before submission
228
+ * with the Bridge quote id, and perps right after submission with the
229
+ * returned order id. The endpoint is idempotent per profile, origin, and
230
+ * execution id: it answers 201 for a new intent and 200 with the existing
231
+ * one on a retry.
232
+ *
233
+ * @param options - Options bag.
234
+ * @param options.origin - Comment the trade was copied from.
235
+ * @param options.copierAccount - CAIP-10 account placing the trade.
236
+ * @param options.execution - Swap quote id or perps order id.
237
+ * @returns The created or existing copy-trade intent.
238
+ */
239
+ createCopyTradeIntent(options: CreateCopyTradeIntentOptions): Promise<CopyTradeIntentResponse>;
219
240
  /**
220
241
  * Fetches the list of traders the current user is following.
221
242
  *
@@ -1 +1 @@
1
- {"version":3,"file":"SocialService.d.ts","sourceRoot":"","sources":["../src/SocialService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SocialService.d.ts","sourceRoot":"","sources":["../src/SocialService.ts"],"names":[],"mappings":"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"}
@@ -1,254 +1,10 @@
1
1
  var _a;
2
2
  import { BaseDataService } from '@metamask/base-data-service';
3
3
  import { HttpError } from '@metamask/controller-utils';
4
- import { array, assign, boolean, enums, is, nullable, number, optional, record, string, type as structType, } from '@metamask/superstruct';
4
+ import { is } from '@metamask/superstruct';
5
5
  import { serviceName, SocialServiceErrorMessage } from './social-constants.js';
6
- import { TRADER_RANKING_TAGS, TradeStruct } from './social-types.js';
6
+ import { BlockedContentResponseStruct, BlockedProfilesResponseStruct, CommentEngagementStruct, CopyTradeIntentResponseStruct, FollowResponseStruct, FollowersResponseStruct, FollowingResponseStruct, LeaderboardResponseStruct, PositionStruct, PositionsResponseStruct, SwapCommentResponseStruct, TraderProfileResponseStruct, UnfollowResponseStruct, parseFeedResponse, } from './structs.js';
7
7
  // ---------------------------------------------------------------------------
8
- // Superstruct validation schemas
9
- // ---------------------------------------------------------------------------
10
- const SocialHandlesStruct = structType({
11
- twitter: optional(nullable(string())),
12
- farcaster: optional(nullable(string())),
13
- ens: optional(nullable(string())),
14
- lens: optional(nullable(string())),
15
- });
16
- const ProfileSummaryStruct = structType({
17
- profileId: string(),
18
- address: string(),
19
- name: string(),
20
- imageUrl: optional(nullable(string())),
21
- });
22
- const FeedActorStruct = assign(ProfileSummaryStruct, structType({
23
- winRate30d: optional(nullable(number())),
24
- pnl30d: optional(nullable(number())),
25
- tradeCount30d: optional(nullable(number())),
26
- followerCount: optional(nullable(number())),
27
- }));
28
- const PositionStruct = structType({
29
- positionId: string(),
30
- tokenSymbol: string(),
31
- tokenName: string(),
32
- tokenAddress: string(),
33
- chain: string(),
34
- positionAmount: number(),
35
- isOpen: optional(boolean()),
36
- // Incomplete Clicker metrics serialize these as `null` (`undefined + n`
37
- // becomes `NaN`, then JSON `null`). Rejecting the field used to fail the
38
- // entire feed page, so they are nullable here.
39
- boughtUsd: nullable(number()),
40
- soldUsd: nullable(number()),
41
- realizedPnl: nullable(number()),
42
- costBasis: nullable(number()),
43
- trades: array(TradeStruct),
44
- lastTradeAt: number(),
45
- tokenImageUrl: optional(nullable(string())),
46
- currentValueUSD: optional(nullable(number())),
47
- pnlValueUsd: optional(nullable(number())),
48
- pnlPercent: optional(nullable(number())),
49
- perpPositionType: optional(nullable(enums(['long', 'short']))),
50
- perpLeverage: optional(nullable(number())),
51
- positionAmountWithLeverage: optional(nullable(number())),
52
- });
53
- const PaginationStruct = structType({
54
- hasMore: boolean(),
55
- nextPage: optional(number()),
56
- });
57
- const LeaderboardEntryStruct = structType({
58
- rank: number(),
59
- addresses: array(string()),
60
- profileId: string(),
61
- name: string(),
62
- imageUrl: optional(nullable(string())),
63
- pnl30d: number(),
64
- winRate30d: optional(nullable(number())),
65
- roiPercent30d: optional(nullable(number())),
66
- tradeCount30d: optional(nullable(number())),
67
- pnl7d: optional(nullable(number())),
68
- winRate7d: optional(nullable(number())),
69
- roiPercent7d: optional(nullable(number())),
70
- tradeCount7d: optional(nullable(number())),
71
- pnlPerChain: record(string(), number()),
72
- followerCount: number(),
73
- socialHandles: SocialHandlesStruct,
74
- });
75
- const LeaderboardResponseStruct = structType({
76
- traders: array(LeaderboardEntryStruct),
77
- });
78
- const TraderProfileStruct = structType({
79
- profileId: string(),
80
- address: string(),
81
- allAddresses: array(string()),
82
- name: string(),
83
- imageUrl: optional(nullable(string())),
84
- });
85
- const TraderStatsStruct = structType({
86
- pnl30d: optional(nullable(number())),
87
- winRate30d: optional(nullable(number())),
88
- roiPercent30d: optional(nullable(number())),
89
- tradeCount30d: optional(nullable(number())),
90
- volumeUsd30d: optional(nullable(number())),
91
- pnl7d: optional(nullable(number())),
92
- winRate7d: optional(nullable(number())),
93
- roiPercent7d: optional(nullable(number())),
94
- tradeCount7d: optional(nullable(number())),
95
- medianHoldMinutes: optional(nullable(number())),
96
- });
97
- const PerChainBreakdownStruct = structType({
98
- perChainPnl: record(string(), number()),
99
- perChainRoi: record(string(), nullable(number())),
100
- perChainVolume: record(string(), number()),
101
- perChainPnl7d: optional(record(string(), number())),
102
- perChainRoi7d: optional(record(string(), nullable(number()))),
103
- perChainVolume7d: optional(record(string(), number())),
104
- });
105
- const CopytradedAllTimeStruct = structType({
106
- count: number(),
107
- volumeUSD: number(),
108
- distinctActors: number(),
109
- });
110
- const TraderProfileResponseStruct = structType({
111
- profile: TraderProfileStruct,
112
- stats: TraderStatsStruct,
113
- perChainBreakdown: PerChainBreakdownStruct,
114
- socialHandles: SocialHandlesStruct,
115
- followerCount: number(),
116
- followingCount: number(),
117
- copytradedAllTime: CopytradedAllTimeStruct,
118
- rankingTag: optional(nullable(enums(TRADER_RANKING_TAGS))),
119
- });
120
- const PositionsResponseStruct = structType({
121
- positions: array(PositionStruct),
122
- pagination: PaginationStruct,
123
- computedAt: optional(nullable(string())),
124
- });
125
- // A feed item is a position plus the trader who made the trade (`actor`) and
126
- // the item's creation timestamp. Reuses PositionStruct so the trade/position
127
- // fields stay in lockstep with the positions endpoints.
128
- const CommentReactionProfileStruct = structType({
129
- id: string(),
130
- name: string(),
131
- });
132
- const CommentReactionStruct = structType({
133
- emotion: string(),
134
- count: number(),
135
- profiles: array(CommentReactionProfileStruct),
136
- });
137
- const CommentEngagementStruct = structType({
138
- reactions: array(CommentReactionStruct),
139
- userReaction: nullable(string()),
140
- replyCount: optional(number()),
141
- });
142
- const AuthorCommentStruct = structType({
143
- uid: string(),
144
- text: string(),
145
- timestamp: number(),
146
- engagement: CommentEngagementStruct,
147
- });
148
- const SwapCommentAuthorStruct = structType({
149
- id: string(),
150
- name: string(),
151
- images: optional(structType({
152
- raw: nullable(string()),
153
- xs: nullable(string()),
154
- sm: nullable(string()),
155
- })),
156
- addresses: optional(array(string())),
157
- externalId: optional(string()),
158
- });
159
- const SwapCommentResponseStruct = structType({
160
- uid: string(),
161
- transactionHash: string(),
162
- chain: string(),
163
- tokenAddress: string(),
164
- commentText: string(),
165
- author: SwapCommentAuthorStruct,
166
- timestamp: number(),
167
- isAppUserComment: boolean(),
168
- metrics: CommentEngagementStruct,
169
- });
170
- const FeedItemStruct = assign(PositionStruct, structType({
171
- actor: FeedActorStruct,
172
- timestamp: number(),
173
- authorComment: optional(nullable(AuthorCommentStruct)),
174
- commentCount: optional(number()),
175
- replyCount: optional(number()),
176
- firstTradeAt: optional(nullable(number())),
177
- holdTimeMs: optional(nullable(number())),
178
- entryPriceUsd: optional(nullable(number())),
179
- }));
180
- const FeedPaginationStruct = structType({
181
- olderCursor: nullable(string()),
182
- newerCursor: nullable(string()),
183
- });
184
- const FeedResponseStruct = structType({
185
- items: array(FeedItemStruct),
186
- pagination: FeedPaginationStruct,
187
- });
188
- /**
189
- * One malformed feed item must not blank the page. When the envelope is
190
- * well-shaped, keep items that match {@link FeedItemStruct} and drop the rest.
191
- * Still throw when `items` or `pagination` themselves are unusable.
192
- *
193
- * @param feedData - Parsed JSON body from a feed endpoint.
194
- * @param invalidMessage - Error message to throw when the envelope is unusable.
195
- * @returns The validated feed response, possibly with invalid items dropped.
196
- */
197
- const parseFeedResponse = (feedData, invalidMessage) => {
198
- if (is(feedData, FeedResponseStruct)) {
199
- return feedData;
200
- }
201
- if (typeof feedData !== 'object' ||
202
- feedData === null ||
203
- !('items' in feedData) ||
204
- !('pagination' in feedData)) {
205
- throw new Error(invalidMessage);
206
- }
207
- const { items, pagination } = feedData;
208
- if (!Array.isArray(items) || !is(pagination, FeedPaginationStruct)) {
209
- throw new Error(invalidMessage);
210
- }
211
- return {
212
- items: items.filter((item) => is(item, FeedItemStruct)),
213
- pagination,
214
- };
215
- };
216
- const FollowersResponseStruct = structType({
217
- followers: array(ProfileSummaryStruct),
218
- count: number(),
219
- });
220
- const FollowingResponseStruct = structType({
221
- following: array(ProfileSummaryStruct),
222
- count: number(),
223
- });
224
- const FollowResponseStruct = structType({
225
- followed: array(ProfileSummaryStruct),
226
- });
227
- const UnfollowResponseStruct = structType({
228
- unfollowed: array(ProfileSummaryStruct),
229
- });
230
- const BlockedProfileStruct = structType({
231
- blockedAt: number(),
232
- reason: nullable(string()),
233
- profile: ProfileSummaryStruct,
234
- });
235
- const BlockedProfilesResponseStruct = structType({
236
- items: array(BlockedProfileStruct),
237
- cursor: nullable(string()),
238
- });
239
- const BlockedContentStruct = structType({
240
- blockedAt: number(),
241
- reason: nullable(string()),
242
- type: enums(['comment', 'reply']),
243
- id: string(),
244
- text: string(),
245
- createdAt: number(),
246
- author: nullable(ProfileSummaryStruct),
247
- });
248
- const BlockedContentResponseStruct = structType({
249
- items: array(BlockedContentStruct),
250
- cursor: nullable(string()),
251
- });
252
8
  // ---------------------------------------------------------------------------
253
9
  // Messenger types
254
10
  // ---------------------------------------------------------------------------
@@ -269,6 +25,7 @@ const MESSENGER_EXPOSED_METHODS = [
269
25
  'reactToComment',
270
26
  'removeCommentReaction',
271
27
  'createSwapComment',
28
+ 'createCopyTradeIntent',
272
29
  'follow',
273
30
  'unfollow',
274
31
  'optOutOfLeaderboard',
@@ -362,6 +119,9 @@ export class SocialService extends BaseDataService {
362
119
  *
363
120
  * Calls `GET ${baseUrl}/traders/${addressOrId}/profile`.
364
121
  *
122
+ * `profile.createdAt` is optional. When present it is an ISO-8601 timestamp
123
+ * for when the social-api profile row was inserted.
124
+ *
365
125
  * @param options - Options bag.
366
126
  * @param options.addressOrId - Wallet address or Clicker profile ID.
367
127
  * @returns The trader profile response.
@@ -435,6 +195,7 @@ export class SocialService extends BaseDataService {
435
195
  const mutualsOnly = mutuals === true;
436
196
  const followersResponse = await this.fetchQuery({
437
197
  queryKey: [`${this.name}:fetchFollowers`, addressOrId, mutualsOnly],
198
+ staleTime: 0,
438
199
  queryFn: async () => {
439
200
  const url = new URL(`${this.#v1Url}/traders/${encodeURIComponent(addressOrId)}/followers`);
440
201
  if (mutualsOnly) {
@@ -467,6 +228,7 @@ export class SocialService extends BaseDataService {
467
228
  const { addressOrId } = options;
468
229
  const followingResponse = await this.fetchQuery({
469
230
  queryKey: [`${this.name}:fetchTraderFollowing`, addressOrId],
231
+ staleTime: 0,
470
232
  queryFn: async () => {
471
233
  const url = `${this.#v1Url}/traders/${encodeURIComponent(addressOrId)}/following`;
472
234
  const authHeaders = await this.#getAuthHeaders();
@@ -520,7 +282,8 @@ export class SocialService extends BaseDataService {
520
282
  * `pagination.newerCursor` as `newerThan` to fetch newer items.
521
283
  *
522
284
  * @param options - Options bag.
523
- * @param options.scope - `following` (default) or `leaderboard`.
285
+ * @param options.scope - `following` (default), `leaderboard`, `all`, or
286
+ * `trending`.
524
287
  * @param options.chains - Filter by one or more chains.
525
288
  * @param options.limit - Number of results per page.
526
289
  * @param options.olderThan - Cursor for older items (scroll down).
@@ -786,6 +549,47 @@ export class SocialService extends BaseDataService {
786
549
  },
787
550
  });
788
551
  }
552
+ /**
553
+ * Records that the current user is copying a trade from a social post, so
554
+ * the copy can be detected and attributed to the post's author.
555
+ *
556
+ * Calls `POST ${baseUrl}/copy-trade-intents`. Send swaps before submission
557
+ * with the Bridge quote id, and perps right after submission with the
558
+ * returned order id. The endpoint is idempotent per profile, origin, and
559
+ * execution id: it answers 201 for a new intent and 200 with the existing
560
+ * one on a retry.
561
+ *
562
+ * @param options - Options bag.
563
+ * @param options.origin - Comment the trade was copied from.
564
+ * @param options.copierAccount - CAIP-10 account placing the trade.
565
+ * @param options.execution - Swap quote id or perps order id.
566
+ * @returns The created or existing copy-trade intent.
567
+ */
568
+ async createCopyTradeIntent(options) {
569
+ const { origin, copierAccount, execution } = options;
570
+ return await this.fetchQuery({
571
+ queryKey: [
572
+ `${this.name}:createCopyTradeIntent`,
573
+ { origin, copierAccount, execution },
574
+ ],
575
+ staleTime: 0,
576
+ queryFn: async () => {
577
+ const url = `${this.#v1Url}/copy-trade-intents`;
578
+ const authHeaders = await this.#getAuthHeaders();
579
+ const response = await fetch(url, {
580
+ method: 'POST',
581
+ headers: { ...authHeaders, 'Content-Type': 'application/json' },
582
+ body: JSON.stringify({ origin, copierAccount, execution }),
583
+ });
584
+ _a.#throwIfNotOk(response, SocialServiceErrorMessage.CREATE_COPY_TRADE_INTENT_FAILED);
585
+ const intent = (await response.json());
586
+ if (!is(intent, CopyTradeIntentResponseStruct)) {
587
+ throw new Error(SocialServiceErrorMessage.CREATE_COPY_TRADE_INTENT_INVALID_RESPONSE);
588
+ }
589
+ return intent;
590
+ },
591
+ });
592
+ }
789
593
  /**
790
594
  * Fetches the list of traders the current user is following.
791
595
  *