@eluvio/elv-client-js 3.2.5 → 3.2.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eluvio/elv-client-js",
3
- "version": "3.2.5",
3
+ "version": "3.2.8",
4
4
  "description": "Javascript client for the Eluvio Content Fabric",
5
5
  "main": "src/index.js",
6
6
  "author": "Kevin Talmadge",
package/src/ElvClient.js CHANGED
@@ -609,7 +609,7 @@ class ElvClient {
609
609
  idToken,
610
610
  authToken,
611
611
  tenantId,
612
- provider: this.ethClient.provider,
612
+ provider: await this.ethClient.Provider(),
613
613
  extraData,
614
614
  unsignedPublicAuth
615
615
  });
@@ -24,6 +24,7 @@ exports.UserInfo = function() {
24
24
  if(!this.loggedIn) { return; }
25
25
 
26
26
  return {
27
+ name: this.__authorization.email || this.UserAddress(),
27
28
  address: this.UserAddress() ,
28
29
  email: this.__authorization.email,
29
30
  walletType: this.__authorization.walletType,
@@ -127,20 +128,18 @@ exports.UserWalletBalance = async function(checkOnboard=false) {
127
128
 
128
129
 
129
130
  /**
130
- * <b><i>Requires login</i></b>
131
- *
132
- * Returns basic contract info about the items the current user owns, organized by contract address + token ID
131
+ * Returns basic contract info about the items the specified/current user owns, organized by contract address + token ID
133
132
  *
134
133
  * This method is significantly faster than <a href="#.UserItems">UserItems</a>, but does not include any NFT metadata.
135
134
  *
136
135
  * @methodGroup User
136
+ * @namedParams
137
+ * @param {string=} userAddress - Address of the user to query for. If unspecified, will use the currently logged in user.
137
138
  *
138
139
  * @returns {Promise<Object>} - Basic info about all owned items.
139
140
  */
140
- exports.UserItemInfo = async function () {
141
- if(!this.loggedIn) { return {}; }
142
-
143
- const accountId = `iusr${Utils.AddressToHash(this.UserAddress())}`;
141
+ exports.UserItemInfo = async function ({userAddress}={}) {
142
+ const accountId = `iusr${Utils.AddressToHash(userAddress || this.UserAddress())}`;
144
143
  this.profileData = await this.client.ethClient.MakeProviderCall({
145
144
  methodName: "send",
146
145
  args: [
@@ -263,6 +262,35 @@ exports.UserSales = async function({sortBy="created", sortDesc=false, contractAd
263
262
  ).results;
264
263
  };
265
264
 
265
+ /**
266
+ * Return all transfers and sales for the current user. Not paginated.
267
+ *
268
+ * @methodGroup User
269
+ * @namedParams
270
+ * @param {string=} sortBy="created" - Sort order. Options: `created`, `price`, `name`
271
+ * @param {boolean=} sortDesc=false - Sort results descending instead of ascending
272
+ * @param {Object=} marketplaceParams - Filter results by marketplace
273
+ * @param {string=} contractAddress - Filter results by the address of the NFT contract
274
+ * @param {string=} tokenId - Filter by token ID (if filtering by contract address)
275
+ * @param {integer=} lastNDays - Filter by results listed in the past N days
276
+ *
277
+ * @returns {Promise<Array<Object>>} - List of current user's sales
278
+ */
279
+ exports.UserTransfers = async function({sortBy="created", sortDesc=false, contractAddress, tokenId, marketplaceParams}={}) {
280
+ return (
281
+ await this.FilteredQuery({
282
+ mode: "transfers",
283
+ start: 0,
284
+ limit: 10000,
285
+ sortBy,
286
+ sortDesc,
287
+ sellerAddress: this.UserAddress(),
288
+ marketplaceParams,
289
+ contractAddress,
290
+ tokenId
291
+ })
292
+ ).results;
293
+ };
266
294
 
267
295
  /* TENANT */
268
296
 
@@ -431,10 +459,28 @@ exports.Marketplace = async function ({marketplaceParams}) {
431
459
 
432
460
  /* NFTS */
433
461
 
462
+ /**
463
+ * Return info about the specified NFT contract, including the cap, current total supply, and total minted and burned.
464
+ *
465
+ * @methodGroup NFTs
466
+ * @namedParams
467
+ * @param {string} contractAddress - The contract address of the NFT
468
+ *
469
+ * @returns {Promise<Object>} - Information about the specified contract
470
+ */
471
+ exports.NFTContractStats = async function({contractAddress}) {
472
+ return await Utils.ResponseToJson(
473
+ this.client.authClient.MakeAuthServiceRequest({
474
+ path: UrlJoin("as", "nft", "info", contractAddress),
475
+ method: "GET"
476
+ })
477
+ );
478
+ };
479
+
434
480
  /**
435
481
  * Load full info for the specified NFT
436
482
  *
437
- * @methodGroup Items
483
+ * @methodGroup NFTs
438
484
  * @namedParams
439
485
  * @param {string} contractAddress - The contract address of the NFT
440
486
  * @param {string} tokenId - The token ID of the NFT
@@ -470,7 +516,7 @@ exports.NFT = async function({tokenId, contractAddress}) {
470
516
  *
471
517
  * Transfer the specified NFT owned by the current user to the specified address
472
518
  *
473
- * @methodGroup NFT
519
+ * @methodGroup NFTs
474
520
  * @namedParams
475
521
  * @param {string} contractAddress - The contract address of the NFT
476
522
  * @param {string} tokenId - The token ID of the NFT
@@ -650,6 +696,41 @@ exports.Sales = async function() {
650
696
  return this.FilteredQuery({mode: "sales", ...(arguments[0] || {})});
651
697
  };
652
698
 
699
+ /**
700
+ * Retrieve sales and transfers matching the specified parameters.
701
+ *
702
+ * @methodGroup Listings
703
+ * @namedParams
704
+ * @param {integer=} start=0 - PAGINATION: Index from which the results should start
705
+ * @param {integer=} limit=50 - PAGINATION: Maximum number of results to return
706
+ * @param {string=} sortBy="created" - Sort order. Options: `created`, `price`, `name`
707
+ * @param {boolean=} sortDesc=false - Sort results descending instead of ascending
708
+ * @param {string=} filter - Filter results by item name.
709
+ * <br /><br />
710
+ * NOTE: This string must be an <b>exact match</b> on the item name.
711
+ * You can retrieve all available item names from the <a href="#.ListingNames">ListingNames method</a>.
712
+ * @param {string=} editionFilter - Filter results by item edition.
713
+ * <br /><br />
714
+ * NOTE: This string must be an <b>exact match</b> on the edition name.
715
+ * You can retrieve all available item edition names from the <a href="#.ListingEditionNames">ListingEditionNames method</a>.
716
+ * @param {Array<Object>} attributeFilters - Filter results by item attributes. Each entry should include name and value (e.g. `[{name: "attribute-name", value: "attribute-value"}]`)
717
+ * <br /><br />
718
+ * NOTE: These filters must be an <b>exact match</b> on the attribute name and value.
719
+ * You can retrieve all available item attributes from the <a href="#.ListingAttributes">ListingAttributes method</a>.
720
+ * @param {string=} sellerAddress - Filter by a specific seller
721
+ * @param {string=} contractAddress - Filter results by the address of the NFT contract
722
+ * @param {string=} tokenId - Filter by token ID (if filtering by contract address)
723
+ * @param {string=} currency - Filter results by purchase currency. Available options: `usdc`
724
+ * @param {Object=} marketplaceParams - Filter results by marketplace
725
+ * @param {integer=} collectionIndex - If filtering by marketplace, filter by collection. The index refers to the index in the array `marketplace.collections`
726
+ * @param {integer=} lastNDays - Filter by results listed in the past N days
727
+ *
728
+ * @returns {Promise<Object>} - Results of the query and pagination info
729
+ */
730
+ exports.Transfers = async function() {
731
+ return this.FilteredQuery({mode: "transfers", ...(arguments[0] || {})});
732
+ };
733
+
653
734
  /**
654
735
  * Retrieve stats for listings matching the specified parameters.
655
736
  *
@@ -6,6 +6,12 @@ For information about the embedded wallet app frame client, see [here](https://e
6
6
 
7
7
  ## Initializing the Client
8
8
 
9
+ Import the client using the following path:
10
+
11
+ ```javascript
12
+ import {ElvWalletClient} from "@eluvio/elv-client-js/src/walletClient/index";
13
+ ```
14
+
9
15
  Initializing the client is as simple as calling the static Initialize method with the network (main or demo) and the mode (production or staging) the client should operate upon, as well as (optionally) the marketplace to associate the client with.
10
16
 
11
17
  ```javascript
@@ -3,6 +3,7 @@ const Configuration = require("./Configuration");
3
3
  const {LinkTargetHash, FormatNFT, ActionPopup} = require("./Utils");
4
4
  const UrlJoin = require("url-join");
5
5
  const Utils = require("../Utils");
6
+ const Ethers = require("ethers");
6
7
 
7
8
 
8
9
  /**
@@ -117,6 +118,89 @@ class ElvWalletClient {
117
118
 
118
119
  /* Login and authorization */
119
120
 
121
+ /**
122
+ * Check if this client can sign without opening a popup.
123
+ *
124
+ * Generally, Eluvio custodial wallet users will require a popup prompt, while Metamask and custom OAuth users will not.
125
+ *
126
+ * @methodGroup Signatures
127
+ * @returns {boolean} - Whether or not this client can sign a message without a popup.
128
+ */
129
+ CanSign() {
130
+ if(!this.loggedIn) { return false; }
131
+
132
+ return !!this.__authorization.clusterToken ||
133
+ !!(this.UserInfo().walletName.toLowerCase() === "metamask" && window.ethereum && window.ethereum.isMetaMask && window.ethereum.chainId);
134
+ }
135
+
136
+ /**
137
+ * <b><i>Requires login</i></b>
138
+ *
139
+ * Request the current user sign the specified message.
140
+ *
141
+ * If this client is not able to perform the signature (Eluvio custodial OAuth users), a popup will be opened and the user will be prompted to sign.
142
+ *
143
+ * To check if the signature can be done without a popup, use the <a href="#CanSign">CanSign</a> method.
144
+ *
145
+ * @methodGroup Signatures
146
+ * @namedParams
147
+ * @param {string} message - The message to sign
148
+ *
149
+ * @throws - If the user rejects the signature or closes the popup, an error will be thrown.
150
+ *
151
+ * @returns {Promise<string>} - The signature of the message
152
+ */
153
+ async PersonalSign({message}) {
154
+ if(!this.loggedIn) { throw Error("ElvWalletClient: Unable to perform signature - Not logged in"); }
155
+
156
+ // Able to sign locally with either cluster token or metamask
157
+ if(this.CanSign()) {
158
+ if(this.__authorization.clusterToken) {
159
+ // Custodial wallet sign
160
+
161
+ message = typeof message === "object" ? JSON.stringify(message) : message;
162
+ message = Ethers.utils.keccak256(Buffer.from(`\x19Ethereum Signed Message:\n${message.length}${message}`, "utf-8"));
163
+
164
+ return await this.client.authClient.Sign(message);
165
+ } else if(this.UserInfo().walletName.toLowerCase() === "metamask") {
166
+ return this.SignMetamask({message, address: this.UserAddress()});
167
+ } else {
168
+ throw Error("ElvWalletClient: Unable to sign");
169
+ }
170
+ }
171
+
172
+ const parameters = {
173
+ action: "personal-sign",
174
+ message,
175
+ logIn: true
176
+ };
177
+
178
+ let url = new URL(this.appUrl);
179
+ url.hash = UrlJoin("/action", "sign", Utils.B58(JSON.stringify(parameters)));
180
+ url.searchParams.set("origin", window.location.origin);
181
+
182
+ return await new Promise(async (resolve, reject) => {
183
+ await ActionPopup({
184
+ mode: "tab",
185
+ url: url.toString(),
186
+ onCancel: () => reject("User cancelled sign"),
187
+ onMessage: async (event, Close) => {
188
+ if(!event || !event.data || event.data.type !== "FlowResponse") {
189
+ return;
190
+ }
191
+
192
+ try {
193
+ resolve(event.data.response);
194
+ } catch(error) {
195
+ reject(error);
196
+ } finally {
197
+ Close();
198
+ }
199
+ }
200
+ });
201
+ });
202
+ }
203
+
120
204
  /**
121
205
  * Direct the user to the Eluvio Media Wallet login page.
122
206
  *
@@ -246,12 +330,12 @@ class ElvWalletClient {
246
330
  throw Error("ElvWalletClient: Provided authorization token has expired");
247
331
  }
248
332
 
249
- this.client.SetStaticToken({token: decodedToken.fabricToken});
250
-
251
333
  if(decodedToken.clusterToken) {
252
- this.client.SetRemoteSigner({authToken: decodedToken.clusterToken});
334
+ await this.client.SetRemoteSigner({authToken: decodedToken.clusterToken});
253
335
  }
254
336
 
337
+ this.client.SetStaticToken({token: decodedToken.fabricToken});
338
+
255
339
  return this.SetAuthorization(decodedToken);
256
340
  }
257
341
 
@@ -415,11 +499,16 @@ class ElvWalletClient {
415
499
  throw Error("ElvWalletClient: Unable to initialize - Metamask not available");
416
500
  }
417
501
 
418
- await window.ethereum.request({method: "eth_requestAccounts"});
419
- const from = address || window.ethereum.selectedAddress;
502
+ address = address || this.UserAddress();
503
+
504
+ const accounts = await window.ethereum.request({method: "eth_requestAccounts"});
505
+ if(address && !Utils.EqualAddress(accounts[0], address)) {
506
+ throw Error(`ElvWalletClient: Incorrect MetaMask account selected. Expected ${address}, got ${accounts[0]}`);
507
+ }
508
+
420
509
  return await window.ethereum.request({
421
510
  method: "personal_sign",
422
- params: [message, from, ""],
511
+ params: [message, address, ""],
423
512
  });
424
513
  }
425
514
 
@@ -750,6 +839,10 @@ class ElvWalletClient {
750
839
  path = UrlJoin("as", "mkt", "f");
751
840
  break;
752
841
 
842
+ case "transfers":
843
+ path = UrlJoin("as", "mkt", "hst", "f");
844
+ break;
845
+
753
846
  case "sales":
754
847
  path = UrlJoin("as", "mkt", "hst", "f");
755
848
  filters.push("action:eq:SOLD");