sparrow-controllers
Version:
Collection of platform-agnostic modules for creating secure data models for cryptocurrency wallets
194 lines • 9.23 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CollectibleDetectionController = void 0;
const BaseController_1 = require("../BaseController");
const util_1 = require("../util");
const constants_1 = require("../constants");
const DEFAULT_INTERVAL = 180000;
/**
* Controller that passively polls on a set interval for Collectibles auto detection
*/
class CollectibleDetectionController extends BaseController_1.BaseController {
/**
* Creates a CollectibleDetectionController instance.
*
* @param options - The controller options.
* @param options.onCollectiblesStateChange - Allows subscribing to assets controller state changes.
* @param options.onPreferencesStateChange - Allows subscribing to preferences controller state changes.
* @param options.onNetworkStateChange - Allows subscribing to network controller state changes.
* @param options.getOpenSeaApiKey - Gets the OpenSea API key, if one is set.
* @param options.addCollectible - Add a collectible.
* @param options.getCollectiblesState - Gets the current state of the Assets controller.
* @param config - Initial options used to configure this controller.
* @param state - Initial state to set on this controller.
*/
constructor({ onPreferencesStateChange, onNetworkStateChange, getOpenSeaApiKey, addCollectible, getCollectiblesState, }, config, state) {
super(config, state);
/**
* Name of this controller used during composition
*/
this.name = 'CollectibleDetectionController';
/**
* Checks whether network is mainnet or not.
*
* @returns Whether current network is mainnet.
*/
this.isMainnet = () => this.config.networkType === constants_1.MAINNET;
this.defaultConfig = {
interval: DEFAULT_INTERVAL,
networkType: constants_1.MAINNET,
chainId: '1',
selectedAddress: '',
disabled: true,
};
this.initialize();
this.getCollectiblesState = getCollectiblesState;
onPreferencesStateChange(({ selectedAddress, useCollectibleDetection }) => {
const { selectedAddress: previouslySelectedAddress, disabled } = this.config;
if (selectedAddress !== previouslySelectedAddress ||
!useCollectibleDetection !== disabled) {
this.configure({ selectedAddress, disabled: !useCollectibleDetection });
}
if (useCollectibleDetection !== undefined) {
if (useCollectibleDetection) {
this.start();
}
else {
this.stop();
}
}
});
onNetworkStateChange(({ provider }) => {
this.configure({
networkType: provider.type,
chainId: provider.chainId,
});
});
this.getOpenSeaApiKey = getOpenSeaApiKey;
this.addCollectible = addCollectible;
}
getOwnerCollectiblesApi(address, offset) {
return `https://api.opensea.io/api/v1/assets?owner=${address}&offset=${offset}&limit=50`;
}
getOwnerCollectibles(address) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
let response;
let collectibles = [];
const openSeaApiKey = this.getOpenSeaApiKey();
try {
let offset = 0;
let pagingFinish = false;
/* istanbul ignore if */
do {
const api = this.getOwnerCollectiblesApi(address, offset);
response = yield (0, util_1.timeoutFetch)(api, openSeaApiKey ? { headers: { 'X-API-KEY': openSeaApiKey } } : {}, 15000);
const collectiblesArray = yield response.json();
((_a = collectiblesArray.assets) === null || _a === void 0 ? void 0 : _a.length) !== 0
? (collectibles = [...collectibles, ...collectiblesArray.assets])
: (pagingFinish = true);
offset += 50;
} while (!pagingFinish);
}
catch (e) {
/* istanbul ignore next */
return [];
}
return collectibles;
});
}
/**
* Start polling for the currency rate.
*/
start() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.isMainnet() || this.disabled) {
return;
}
yield this.startPolling();
});
}
/**
* Stop polling for the currency rate.
*/
stop() {
this.stopPolling();
}
stopPolling() {
if (this.intervalId) {
clearInterval(this.intervalId);
}
}
/**
* Starts a new polling interval.
*
* @param interval - An interval on which to poll.
*/
startPolling(interval) {
return __awaiter(this, void 0, void 0, function* () {
interval && this.configure({ interval }, false, false);
this.stopPolling();
yield this.detectCollectibles();
this.intervalId = setInterval(() => __awaiter(this, void 0, void 0, function* () {
yield this.detectCollectibles();
}), this.config.interval);
});
}
/**
* Triggers asset ERC721 token auto detection on mainnet. Any newly detected collectibles are
* added.
*/
detectCollectibles() {
return __awaiter(this, void 0, void 0, function* () {
/* istanbul ignore if */
if (!this.isMainnet() || this.disabled) {
return;
}
const { selectedAddress, chainId } = this.config;
/* istanbul ignore else */
if (!selectedAddress) {
return;
}
yield (0, util_1.safelyExecute)(() => __awaiter(this, void 0, void 0, function* () {
const apiCollectibles = yield this.getOwnerCollectibles(selectedAddress);
const addCollectiblesPromises = apiCollectibles.map((collectible) => __awaiter(this, void 0, void 0, function* () {
const { token_id, num_sales, background_color, image_url, image_preview_url, image_thumbnail_url, image_original_url, animation_url, animation_original_url, name, description, external_link, creator, asset_contract: { address, schema_name }, last_sale, } = collectible;
let ignored;
/* istanbul ignore else */
const { ignoredCollectibles } = this.getCollectiblesState();
if (ignoredCollectibles.length) {
ignored = ignoredCollectibles.find((c) => {
/* istanbul ignore next */
return (c.address === (0, util_1.toChecksumHexAddress)(address) &&
c.tokenId === token_id);
});
}
/* istanbul ignore else */
if (!ignored) {
/* istanbul ignore next */
const collectibleMetadata = Object.assign({}, { name }, creator && { creator }, description && { description }, image_url && { image: image_url }, num_sales && { numberOfSales: num_sales }, background_color && { backgroundColor: background_color }, image_preview_url && { imagePreview: image_preview_url }, image_thumbnail_url && { imageThumbnail: image_thumbnail_url }, image_original_url && { imageOriginal: image_original_url }, animation_url && { animation: animation_url }, animation_original_url && {
animationOriginal: animation_original_url,
}, schema_name && { standard: schema_name }, external_link && { externalLink: external_link }, last_sale && { lastSale: last_sale });
yield this.addCollectible(address, token_id, collectibleMetadata, {
userAddress: selectedAddress,
chainId: chainId,
});
}
}));
yield Promise.all(addCollectiblesPromises);
}));
});
}
}
exports.CollectibleDetectionController = CollectibleDetectionController;
exports.default = CollectibleDetectionController;
//# sourceMappingURL=CollectibleDetectionController.js.map