@sabaaa1/common 0.0.19 → 0.0.20
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/API/admin-calls.cjs +1 -1
- package/API/admin-calls.d.ts +1 -1
- package/API/admin-calls.mjs +8 -5
- package/data-structures/ApprovalDBs/EventsPublicApprovalsDB.cjs +1 -1
- package/data-structures/ApprovalDBs/EventsPublicApprovalsDB.mjs +37 -37
- package/data-structures/TokenDBs/AlchemyPublicTokensDB.cjs +1 -1
- package/data-structures/TokenDBs/AlchemyPublicTokensDB.mjs +36 -36
- package/package.json +1 -1
package/API/admin-calls.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("../constants/server.constants.cjs"),i=require("./getRelayerURL.cjs"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("../constants/server.constants.cjs"),i=require("./getRelayerURL.cjs"),s=require("axios"),c=async(e,t)=>{const{data:a}=await s.post(`${i.getRelayerURL(e)}${r.RELAYER_CONFIG.emitTxPublicData}`,{adminData:t});return a};exports.emitTxPublicData=c;
|
package/API/admin-calls.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { AdminDataType } from '../types/admin.types';
|
|
2
|
-
export declare const emitTxPublicData: (chainId: number, adminData: AdminDataType | undefined) => any
|
|
2
|
+
export declare const emitTxPublicData: (chainId: number, adminData: AdminDataType | undefined) => Promise<any>;
|
package/API/admin-calls.mjs
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { RELAYER_CONFIG as
|
|
2
|
-
import { getRelayerURL as
|
|
3
|
-
import
|
|
4
|
-
const
|
|
1
|
+
import { RELAYER_CONFIG as r } from "../constants/server.constants.mjs";
|
|
2
|
+
import { getRelayerURL as i } from "./getRelayerURL.mjs";
|
|
3
|
+
import m from "axios";
|
|
4
|
+
const s = async (t, a) => {
|
|
5
|
+
const { data: o } = await m.post(`${i(t)}${r.emitTxPublicData}`, { adminData: a });
|
|
6
|
+
return o;
|
|
7
|
+
};
|
|
5
8
|
export {
|
|
6
|
-
|
|
9
|
+
s as emitTxPublicData
|
|
7
10
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("ethers"),w=require("idb-keyval"),T=require("async-mutex"),h=require("../../constants/chains.constants.cjs"),P=require("../../error-handling/logger.cjs"),L=require("../../functions/utils/string.utils.cjs"),I=require("../../types/cache.types.cjs"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("ethers"),w=require("idb-keyval"),T=require("async-mutex"),h=require("../../constants/chains.constants.cjs"),P=require("../../error-handling/logger.cjs"),L=require("../../functions/utils/string.utils.cjs"),I=require("../../types/cache.types.cjs"),x=require("../../API/API.cjs"),f=require("../../types/approvals.types.cjs"),q=require("../../functions/utils/erc20tokenFunctions.cjs"),R=require("../../functions/utils/create-provider.cjs"),M=require("../../constants/events.constants.cjs"),m=require("../../functions/utils/caseInsensitive.utils.cjs"),_=require("../../constants/protocol.constants.cjs"),$=require("axios");class B{updateMutexes={};approvalTopic=S.ethers.utils.id("Approval(address,address,uint256)");approvalForAllTopic=S.ethers.utils.id("ApprovalForAll(address,address,bool)");getApprovedSelector=S.ethers.utils.id("getApproved(uint256)").substring(0,10);isApprovedForAllSelector=S.ethers.utils.id("isApprovedForAll(address,address)").substring(0,10);ALCHEMY_URLS={[h.chainIds.ethMainnet]:"eth-mainnet",[h.chainIds.polygon]:"polygon-mainnet",[h.chainIds.arbMainnet]:"arb-mainnet",[h.chainIds.optimism]:"opt-mainnet",[h.chainIds.base]:"base-mainnet",[h.chainIds.arcTestnet]:"arc-testnet",[h.chainIds.avalanche]:"avax-mainnet"};getMutex(t){return this.updateMutexes[t]||(this.updateMutexes[t]=new T.Mutex),this.updateMutexes[t]}getAlchemyUrl(t){const s=this.ALCHEMY_URLS[t];if(!s)throw new Error(`Unsupported chainId for Alchemy: ${t}`);return`https://${s}.g.alchemy.com/v2/${h.ALCHEMY_API_KEY}`}async getApprovals(t,s){const r=L.getStateKey(s,t);return(await w.get(I.StorageKeys.EVENTS_PUBLIC_APPROVALS))?.[r]||[]}async getLastProcessedBlock(t,s){const r=await w.get(I.StorageKeys.PUBLIC_APPROVALS_LAST_PROCESSED_BLOCKS)||{},d=L.getStateKey(s,t);return r[d]||M.EVENTS_INITIAL_BLOCKS[t]}async updateLastProcessedBlock(t,s,r){await w.update(I.StorageKeys.PUBLIC_APPROVALS_LAST_PROCESSED_BLOCKS,(d={})=>{const p=L.getStateKey(s,t);return{...d,[p]:r}})}async getApprovalEvents(t,s){try{const{fetchRpcUrl:r}=h.networkRegistry[s];if(!r)throw Error("No fetchRpcUrl in EventsPublicApprovalsDB");const d=R.createTorRpcProvider(r),p=await this.getLastProcessedBlock(s,t)+1,l=await d.getBlockNumber();if(p>l)return{approvalEvents:[],latestBlock:l};const E=S.ethers.utils.hexZeroPad(t.toLowerCase(),32),c={topics:[[this.approvalTopic,this.approvalForAllTopic],E],fromBlock:p,toBlock:l};return{approvalEvents:await d.getLogs(c),latestBlock:l}}catch(r){return P.Logger.error("Failed to fetch approval events",r),{approvalEvents:[],latestBlock:void 0}}}async checkCurrentAllowances(t,s,r){const d=this.getAlchemyUrl(t),p=`0x${s.substring(2).padStart(64,"0")}`,l=[...new Set(r.map(e=>e.contractAddress))],E=(await x.API.tokensInfoCall(t,l)).filter(e=>!!e),c=new Map(E.map(e=>[e.erc20TokenAddress.toLowerCase(),e])),i=[],k=[];if(r.forEach((e,o)=>{const a=c.get(e.contractAddress.toLowerCase());if(a)if(!q.isNFTToken(a))i.push({jsonrpc:"2.0",id:i.length,method:"alchemy_getTokenAllowance",params:[{contract:e.contractAddress,owner:s,spender:e.spenderAddress}]}),k.push({pairIndex:o,type:f.RevokeType.ERC20});else{const v=`0x${e.spenderAddress.substring(2).padStart(64,"0")}`,y=`${this.isApprovedForAllSelector}${p.substring(2)}${v.substring(2)}`;i.push({jsonrpc:"2.0",id:i.length,method:"eth_call",params:[{to:e.contractAddress,data:y},"latest"]}),k.push({pairIndex:o,type:f.RevokeType.approvedForAll}),e.tokenIds&&e.tokenIds.size>0&&e.tokenIds.forEach(g=>{const b=S.ethers.BigNumber.from(g).toHexString().substring(2).padStart(64,"0"),C=`${this.getApprovedSelector}${b}`;i.push({jsonrpc:"2.0",id:i.length,method:"eth_call",params:[{to:e.contractAddress,data:C},"latest"]}),k.push({pairIndex:o,type:f.RevokeType.tokenId,tokenId:g})})}}),i.length===0)return[];const{data:n}=await $.post(d,i),u=[],A=new Set;return n.forEach((e,o)=>{const a=k[o];if(!a)return;const v=r[a.pairIndex],y=c.get(v.contractAddress.toLowerCase());if(!(!y||m.caseInsensitiveEqual(v.spenderAddress,_.zeroAddress))&&!e?.error&&e?.result&&e.result!=="0x")try{if(a.type===f.RevokeType.ERC20&&BigInt(e.result)>0n)u.push({token:y,spenderAddress:v.spenderAddress,allowance:BigInt(e.result)});else if(a.type===f.RevokeType.approvedForAll&&BigInt(e.result)===1n)A.add(a.pairIndex),u.push({token:y,spenderAddress:v.spenderAddress,allowance:1n});else if(a.type===f.RevokeType.tokenId&&!A.has(a.pairIndex)){const g=`0x${e.result.substring(26)}`.toLowerCase();!m.caseInsensitiveEqual(g,_.zeroAddress)&&m.caseInsensitiveEqual(g,v.spenderAddress)&&u.push({token:y,spenderAddress:v.spenderAddress,allowance:1n,tokenId:a.tokenId})}}catch(g){P.Logger.error("Error processing approval response",g)}}),u}async fetchAndUpdatePublicApprovals(t,s){const r=L.getStateKey(t,s);await this.getMutex(r).runExclusive(async()=>{try{const{approvalEvents:p,latestBlock:l}=await this.getApprovalEvents(t,s);if(!l)return;const E=await this.getApprovals(s,t),c=new Map;if(E.forEach(n=>{const u=n.token.erc20TokenAddress.toLowerCase(),A=n.spenderAddress.toLowerCase(),e=`${u}_${A}`;let o=c.get(e);o||(o={contractAddress:u,spenderAddress:A,tokenIds:new Set},c.set(e,o)),n.tokenId&&o.tokenIds&&o.tokenIds.add(n.tokenId)}),p.forEach(n=>{if(!n.topics[2])return;const u=n.address.toLowerCase(),A=`0x${n.topics[2].substring(26)}`.toLowerCase();if(m.caseInsensitiveEqual(A,_.zeroAddress))return;const e=`${u}_${A}`;let o=c.get(e);if(o||(o={contractAddress:u,spenderAddress:A,tokenIds:new Set},c.set(e,o)),n.topics.length===4&&o.tokenIds){const a=BigInt(n.topics[3]).toString();o.tokenIds.add(a)}}),c.size===0){await this.updateLastProcessedBlock(s,t,l);return}const i=Array.from(c.values()),k=await this.checkCurrentAllowances(s,t,i);await w.update(I.StorageKeys.EVENTS_PUBLIC_APPROVALS,(n={})=>({...n,[r]:k})),await this.updateLastProcessedBlock(s,t,l)}catch(p){P.Logger.error("Failed to sync approvals",p)}})}}const K=new B;exports.EventsPublicApprovalsDB=B;exports.eventsPublicApprovalsDB=K;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { ethers as k } from "ethers";
|
|
2
|
-
import { get as
|
|
2
|
+
import { get as C, update as I } from "idb-keyval";
|
|
3
3
|
import { Mutex as b } from "async-mutex";
|
|
4
4
|
import { chainIds as f, ALCHEMY_API_KEY as T, networkRegistry as M } from "../../constants/chains.constants.mjs";
|
|
5
5
|
import { Logger as B } from "../../error-handling/logger.mjs";
|
|
6
6
|
import { getStateKey as L } from "../../functions/utils/string.utils.mjs";
|
|
7
7
|
import { StorageKeys as S } from "../../types/cache.types.mjs";
|
|
8
|
-
import {
|
|
9
|
-
import { API as $ } from "../../API/API.mjs";
|
|
8
|
+
import { API as R } from "../../API/API.mjs";
|
|
10
9
|
import { RevokeType as w } from "../../types/approvals.types.mjs";
|
|
11
|
-
import { isNFTToken as
|
|
12
|
-
import { createTorRpcProvider as
|
|
13
|
-
import { EVENTS_INITIAL_BLOCKS as
|
|
10
|
+
import { isNFTToken as $ } from "../../functions/utils/erc20tokenFunctions.mjs";
|
|
11
|
+
import { createTorRpcProvider as U } from "../../functions/utils/create-provider.mjs";
|
|
12
|
+
import { EVENTS_INITIAL_BLOCKS as F } from "../../constants/events.constants.mjs";
|
|
14
13
|
import { caseInsensitiveEqual as y } from "../../functions/utils/caseInsensitive.utils.mjs";
|
|
15
|
-
import { zeroAddress as
|
|
14
|
+
import { zeroAddress as P } from "../../constants/protocol.constants.mjs";
|
|
15
|
+
import O from "axios";
|
|
16
16
|
class N {
|
|
17
17
|
updateMutexes = {};
|
|
18
18
|
approvalTopic = k.utils.id("Approval(address,address,uint256)");
|
|
@@ -39,11 +39,11 @@ class N {
|
|
|
39
39
|
}
|
|
40
40
|
async getApprovals(e, s) {
|
|
41
41
|
const r = L(s, e);
|
|
42
|
-
return (await
|
|
42
|
+
return (await C(S.EVENTS_PUBLIC_APPROVALS))?.[r] || [];
|
|
43
43
|
}
|
|
44
44
|
async getLastProcessedBlock(e, s) {
|
|
45
|
-
const r = await
|
|
46
|
-
return r[d] ||
|
|
45
|
+
const r = await C(S.PUBLIC_APPROVALS_LAST_PROCESSED_BLOCKS) || {}, d = L(s, e);
|
|
46
|
+
return r[d] || F[e];
|
|
47
47
|
}
|
|
48
48
|
async updateLastProcessedBlock(e, s, r) {
|
|
49
49
|
await I(S.PUBLIC_APPROVALS_LAST_PROCESSED_BLOCKS, (d = {}) => {
|
|
@@ -59,57 +59,57 @@ class N {
|
|
|
59
59
|
const { fetchRpcUrl: r } = M[s];
|
|
60
60
|
if (!r)
|
|
61
61
|
throw Error("No fetchRpcUrl in EventsPublicApprovalsDB");
|
|
62
|
-
const d =
|
|
62
|
+
const d = U(r), i = await this.getLastProcessedBlock(s, e) + 1, l = await d.getBlockNumber();
|
|
63
63
|
if (i > l)
|
|
64
64
|
return { approvalEvents: [], latestBlock: l };
|
|
65
|
-
const E = k.utils.hexZeroPad(e.toLowerCase(), 32),
|
|
65
|
+
const E = k.utils.hexZeroPad(e.toLowerCase(), 32), c = {
|
|
66
66
|
topics: [[this.approvalTopic, this.approvalForAllTopic], E],
|
|
67
67
|
fromBlock: i,
|
|
68
68
|
toBlock: l
|
|
69
69
|
};
|
|
70
|
-
return { approvalEvents: await d.getLogs(
|
|
70
|
+
return { approvalEvents: await d.getLogs(c), latestBlock: l };
|
|
71
71
|
} catch (r) {
|
|
72
72
|
return B.error("Failed to fetch approval events", r), { approvalEvents: [], latestBlock: void 0 };
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
async checkCurrentAllowances(e, s, r) {
|
|
76
|
-
const d = this.getAlchemyUrl(e), i = `0x${s.substring(2).padStart(64, "0")}`, l = [...new Set(r.map((t) => t.contractAddress))], E = (await
|
|
76
|
+
const d = this.getAlchemyUrl(e), i = `0x${s.substring(2).padStart(64, "0")}`, l = [...new Set(r.map((t) => t.contractAddress))], E = (await R.tokensInfoCall(e, l)).filter((t) => !!t), c = new Map(E.map((t) => [t.erc20TokenAddress.toLowerCase(), t])), p = [], v = [];
|
|
77
77
|
if (r.forEach((t, o) => {
|
|
78
|
-
const a =
|
|
78
|
+
const a = c.get(t.contractAddress.toLowerCase());
|
|
79
79
|
if (a)
|
|
80
|
-
if (
|
|
81
|
-
|
|
80
|
+
if (!$(a))
|
|
81
|
+
p.push({
|
|
82
82
|
jsonrpc: "2.0",
|
|
83
|
-
id:
|
|
83
|
+
id: p.length,
|
|
84
84
|
method: "alchemy_getTokenAllowance",
|
|
85
85
|
params: [{ contract: t.contractAddress, owner: s, spender: t.spenderAddress }]
|
|
86
86
|
}), v.push({ pairIndex: o, type: w.ERC20 });
|
|
87
87
|
else {
|
|
88
88
|
const m = `0x${t.spenderAddress.substring(2).padStart(64, "0")}`, g = `${this.isApprovedForAllSelector}${i.substring(2)}${m.substring(2)}`;
|
|
89
|
-
|
|
89
|
+
p.push({
|
|
90
90
|
jsonrpc: "2.0",
|
|
91
|
-
id:
|
|
91
|
+
id: p.length,
|
|
92
92
|
method: "eth_call",
|
|
93
93
|
params: [{ to: t.contractAddress, data: g }, "latest"]
|
|
94
94
|
}), v.push({ pairIndex: o, type: w.approvedForAll }), t.tokenIds && t.tokenIds.size > 0 && t.tokenIds.forEach((h) => {
|
|
95
|
-
const
|
|
96
|
-
|
|
95
|
+
const x = k.BigNumber.from(h).toHexString().substring(2).padStart(64, "0"), _ = `${this.getApprovedSelector}${x}`;
|
|
96
|
+
p.push({
|
|
97
97
|
jsonrpc: "2.0",
|
|
98
|
-
id:
|
|
98
|
+
id: p.length,
|
|
99
99
|
method: "eth_call",
|
|
100
|
-
params: [{ to: t.contractAddress, data:
|
|
100
|
+
params: [{ to: t.contractAddress, data: _ }, "latest"]
|
|
101
101
|
}), v.push({ pairIndex: o, type: w.tokenId, tokenId: h });
|
|
102
102
|
});
|
|
103
103
|
}
|
|
104
|
-
}),
|
|
104
|
+
}), p.length === 0)
|
|
105
105
|
return [];
|
|
106
|
-
const n = await
|
|
106
|
+
const { data: n } = await O.post(d, p), u = [], A = /* @__PURE__ */ new Set();
|
|
107
107
|
return n.forEach((t, o) => {
|
|
108
108
|
const a = v[o];
|
|
109
109
|
if (!a)
|
|
110
110
|
return;
|
|
111
|
-
const m = r[a.pairIndex], g =
|
|
112
|
-
if (!(!g || y(m.spenderAddress,
|
|
111
|
+
const m = r[a.pairIndex], g = c.get(m.contractAddress.toLowerCase());
|
|
112
|
+
if (!(!g || y(m.spenderAddress, P)) && !t?.error && t?.result && t.result !== "0x")
|
|
113
113
|
try {
|
|
114
114
|
if (a.type === w.ERC20 && BigInt(t.result) > 0n)
|
|
115
115
|
u.push({ token: g, spenderAddress: m.spenderAddress, allowance: BigInt(t.result) });
|
|
@@ -117,7 +117,7 @@ class N {
|
|
|
117
117
|
A.add(a.pairIndex), u.push({ token: g, spenderAddress: m.spenderAddress, allowance: 1n });
|
|
118
118
|
else if (a.type === w.tokenId && !A.has(a.pairIndex)) {
|
|
119
119
|
const h = `0x${t.result.substring(26)}`.toLowerCase();
|
|
120
|
-
!y(h,
|
|
120
|
+
!y(h, P) && y(h, m.spenderAddress) && u.push({
|
|
121
121
|
token: g,
|
|
122
122
|
spenderAddress: m.spenderAddress,
|
|
123
123
|
allowance: 1n,
|
|
@@ -136,28 +136,28 @@ class N {
|
|
|
136
136
|
const { approvalEvents: i, latestBlock: l } = await this.getApprovalEvents(e, s);
|
|
137
137
|
if (!l)
|
|
138
138
|
return;
|
|
139
|
-
const E = await this.getApprovals(s, e),
|
|
139
|
+
const E = await this.getApprovals(s, e), c = /* @__PURE__ */ new Map();
|
|
140
140
|
if (E.forEach((n) => {
|
|
141
141
|
const u = n.token.erc20TokenAddress.toLowerCase(), A = n.spenderAddress.toLowerCase(), t = `${u}_${A}`;
|
|
142
|
-
let o =
|
|
143
|
-
o || (o = { contractAddress: u, spenderAddress: A, tokenIds: /* @__PURE__ */ new Set() },
|
|
142
|
+
let o = c.get(t);
|
|
143
|
+
o || (o = { contractAddress: u, spenderAddress: A, tokenIds: /* @__PURE__ */ new Set() }, c.set(t, o)), n.tokenId && o.tokenIds && o.tokenIds.add(n.tokenId);
|
|
144
144
|
}), i.forEach((n) => {
|
|
145
145
|
if (!n.topics[2])
|
|
146
146
|
return;
|
|
147
147
|
const u = n.address.toLowerCase(), A = `0x${n.topics[2].substring(26)}`.toLowerCase();
|
|
148
|
-
if (y(A,
|
|
148
|
+
if (y(A, P))
|
|
149
149
|
return;
|
|
150
150
|
const t = `${u}_${A}`;
|
|
151
|
-
let o =
|
|
152
|
-
if (o || (o = { contractAddress: u, spenderAddress: A, tokenIds: /* @__PURE__ */ new Set() },
|
|
151
|
+
let o = c.get(t);
|
|
152
|
+
if (o || (o = { contractAddress: u, spenderAddress: A, tokenIds: /* @__PURE__ */ new Set() }, c.set(t, o)), n.topics.length === 4 && o.tokenIds) {
|
|
153
153
|
const a = BigInt(n.topics[3]).toString();
|
|
154
154
|
o.tokenIds.add(a);
|
|
155
155
|
}
|
|
156
|
-
}),
|
|
156
|
+
}), c.size === 0) {
|
|
157
157
|
await this.updateLastProcessedBlock(s, e, l);
|
|
158
158
|
return;
|
|
159
159
|
}
|
|
160
|
-
const
|
|
160
|
+
const p = Array.from(c.values()), v = await this.checkCurrentAllowances(s, e, p);
|
|
161
161
|
await I(S.EVENTS_PUBLIC_APPROVALS, (n = {}) => ({
|
|
162
162
|
...n,
|
|
163
163
|
[r]: v
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const m=require("idb-keyval"),S=require("../../API/API.cjs"),r=require("../../constants/chains.constants.cjs"),y=require("../../constants/protocol.constants.cjs"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const m=require("idb-keyval"),S=require("../../API/API.cjs"),r=require("../../constants/chains.constants.cjs"),y=require("../../constants/protocol.constants.cjs"),f=require("../../functions/utils/caseInsensitive.utils.cjs"),w=require("../../functions/utils/publicBalance.utils.cjs"),g=require("../../functions/utils/string.utils.cjs"),A=require("../../types/cache.types.cjs"),B=require("./token-visibility-db.cjs"),b=require("axios");class _{fetchedTokens={};ALCHEMY_URLS={[r.chainIds.ethMainnet]:"eth-mainnet",[r.chainIds.polygon]:"polygon-mainnet",[r.chainIds.arbMainnet]:"arb-mainnet",[r.chainIds.optimism]:"opt-mainnet",[r.chainIds.base]:"base-mainnet",[r.chainIds.avalanche]:"avax-mainnet"};KNOWN_GOOD_NFTS={[r.chainIds.base]:["0x20bc8d248fe9c18a947406cea50d716828ab821f"],[r.chainIds.optimism]:["0x3c3e0e73b53a19bcaf4178b8f9c9428fd2a2775e"]};isWhitelistedNFT(t,s){return this.KNOWN_GOOD_NFTS[s]?this.KNOWN_GOOD_NFTS[s].some(n=>f.caseInsensitiveEqual(t,n)):!1}async getPublicTokens(t,s){const n=g.getStateKey(s,t);return(await m.get(A.StorageKeys.ALCHEMY_PUBLIC_TOKENS))?.[n]||[]}getFetchedTokens(t,s){const n=g.getStateKey(s,t);return this.fetchedTokens[n]||[]}async fetchAndUpdatePublicTokens(t,s){const n=g.getStateKey(t,s),l=await this.getERC20TokenAddresses(s,t),a=await this.getNFTTokens(s,t),u=a.map(o=>o.contractAddress),i=[...l,...u];if(!i.length)return;const c=(await S.API.tokensInfoCall(s,i)).map((o,h)=>{if(o)return o;const p=i[h],T=a.find(N=>f.caseInsensitiveEqual(N.contractAddress,p));return T&&T.tokenIds&&T.tokenIds.length>0&&this.isWhitelistedNFT(p,s)?{chainId:s,name:"Unknown NFT",symbol:"NFT",erc20TokenAddress:p,decimals:0,nftTokenType:y.TokenType.ERC721,tokenIds:T.tokenIds}:null}).filter(o=>!!o),d=await B.tokenVisibilityStorage.hideSpamsAndFetchHiddenTokensAddresses(s,c),I=c.filter(o=>!f.lowerCaseIncludes(d,o.erc20TokenAddress)).map(o=>({...o,tokenIds:a.find(h=>f.caseInsensitiveEqual(h.contractAddress,o.erc20TokenAddress))?.tokenIds}));await m.update(A.StorageKeys.ALCHEMY_PUBLIC_TOKENS,(o={})=>{const h={...o,[n]:I};return this.fetchedTokens=h,h})}async getERC20TokenAddresses(t,s){const n=await w.getPublicBalanceByTokenAddress(t,s,y.zeroAddress),l=`https://${this.ALCHEMY_URLS[t]}.g.alchemy.com/v2/${r.ALCHEMY_API_KEY}`,a=[];let u;do{const e=[s,"erc20"];u&&e.push({pageKey:u});const{data:c}=await b.post(l,{jsonrpc:"2.0",id:1,method:"alchemy_getTokenBalances",params:e}),{result:d}=c;a.push(...d?.tokenBalances??[]),u=d?.pageKey}while(u);n&&n>0n&&a.push({contractAddress:y.zeroAddress,tokenBalance:n.toString()});const i={};return a.forEach(e=>{(!i[e.contractAddress]||BigInt(e.tokenBalance)>0n)&&(i[e.contractAddress]=e)}),Object.keys(i)}async getNFTTokens(t,s){const n=`https://${this.ALCHEMY_URLS[t]}.g.alchemy.com/nft/v3/${r.ALCHEMY_API_KEY}/getNFTsForOwner`,l=[];let a;do{const e=new URLSearchParams({owner:s,withMetadata:"false",pageSize:"100"});a&&e.append("pageKey",a);const{data:c}=await b.get(`${n}?${e.toString()}`),{ownedNfts:d=[],pageKey:k}=c;l.push(...d),a=k}while(a);const i=l.filter(({contractAddress:e,tokenId:c})=>e&&c).reduce((e,{contractAddress:c,tokenId:d})=>{const k=c.toLowerCase();return e.has(k)||e.set(k,[]),e.get(k)?.push(d),e},new Map);return Array.from(i.entries()).map(([e,c])=>({contractAddress:e,tokenIds:c}))}}const E=new _;exports.AlchemyPublicTokensDB=_;exports.alchemyPublicTokensDB=E;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { get as B, update as
|
|
2
|
-
import { API as
|
|
1
|
+
import { get as B, update as E } from "idb-keyval";
|
|
2
|
+
import { API as S } from "../../API/API.mjs";
|
|
3
3
|
import { chainIds as d, ALCHEMY_API_KEY as g } from "../../constants/chains.constants.mjs";
|
|
4
|
-
import { TokenType as
|
|
5
|
-
import { caseInsensitiveEqual as h, lowerCaseIncludes as
|
|
4
|
+
import { TokenType as _, zeroAddress as y } from "../../constants/protocol.constants.mjs";
|
|
5
|
+
import { caseInsensitiveEqual as h, lowerCaseIncludes as C } from "../../functions/utils/caseInsensitive.utils.mjs";
|
|
6
6
|
import { getPublicBalanceByTokenAddress as F } from "../../functions/utils/publicBalance.utils.mjs";
|
|
7
7
|
import { getStateKey as u } from "../../functions/utils/string.utils.mjs";
|
|
8
8
|
import { StorageKeys as A } from "../../types/cache.types.mjs";
|
|
9
9
|
import { tokenVisibilityStorage as K } from "./token-visibility-db.mjs";
|
|
10
|
-
import
|
|
10
|
+
import b from "axios";
|
|
11
11
|
class L {
|
|
12
12
|
fetchedTokens = {};
|
|
13
13
|
ALCHEMY_URLS = {
|
|
@@ -41,66 +41,66 @@ class L {
|
|
|
41
41
|
return this.fetchedTokens[s] || [];
|
|
42
42
|
}
|
|
43
43
|
async fetchAndUpdatePublicTokens(n, t) {
|
|
44
|
-
const s = u(n, t), l = await this.getERC20TokenAddresses(t, n),
|
|
44
|
+
const s = u(n, t), l = await this.getERC20TokenAddresses(t, n), a = await this.getNFTTokens(t, n), m = a.map((o) => o.contractAddress), c = [...l, ...m];
|
|
45
45
|
if (!c.length)
|
|
46
46
|
return;
|
|
47
|
-
const
|
|
47
|
+
const r = (await S.tokensInfoCall(t, c)).map((o, k) => {
|
|
48
48
|
if (o)
|
|
49
49
|
return o;
|
|
50
|
-
const T = c[
|
|
51
|
-
return
|
|
50
|
+
const T = c[k], p = a.find((w) => h(w.contractAddress, T));
|
|
51
|
+
return p && p.tokenIds && p.tokenIds.length > 0 && this.isWhitelistedNFT(T, t) ? {
|
|
52
52
|
chainId: t,
|
|
53
53
|
name: "Unknown NFT",
|
|
54
54
|
symbol: "NFT",
|
|
55
55
|
erc20TokenAddress: T,
|
|
56
56
|
decimals: 0,
|
|
57
|
-
nftTokenType:
|
|
58
|
-
tokenIds:
|
|
57
|
+
nftTokenType: _.ERC721,
|
|
58
|
+
tokenIds: p.tokenIds
|
|
59
59
|
} : null;
|
|
60
60
|
}).filter((o) => !!o), i = await K.hideSpamsAndFetchHiddenTokensAddresses(
|
|
61
61
|
t,
|
|
62
|
-
|
|
63
|
-
), N =
|
|
64
|
-
(o) => !
|
|
62
|
+
r
|
|
63
|
+
), N = r.filter(
|
|
64
|
+
(o) => !C(i, o.erc20TokenAddress)
|
|
65
65
|
// filter out hidden tokens
|
|
66
66
|
).map((o) => ({
|
|
67
67
|
...o,
|
|
68
|
-
tokenIds:
|
|
68
|
+
tokenIds: a.find((k) => h(k.contractAddress, o.erc20TokenAddress))?.tokenIds
|
|
69
69
|
}));
|
|
70
|
-
await
|
|
71
|
-
const
|
|
70
|
+
await E(A.ALCHEMY_PUBLIC_TOKENS, (o = {}) => {
|
|
71
|
+
const k = {
|
|
72
72
|
...o,
|
|
73
73
|
[s]: N
|
|
74
74
|
};
|
|
75
|
-
return this.fetchedTokens =
|
|
75
|
+
return this.fetchedTokens = k, k;
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
async getERC20TokenAddresses(n, t) {
|
|
79
|
-
const s = await F(n, t, y), l = `https://${this.ALCHEMY_URLS[n]}.g.alchemy.com/v2/${g}`,
|
|
79
|
+
const s = await F(n, t, y), l = `https://${this.ALCHEMY_URLS[n]}.g.alchemy.com/v2/${g}`, a = [];
|
|
80
80
|
let m;
|
|
81
81
|
do {
|
|
82
82
|
const e = [t, "erc20"];
|
|
83
83
|
m && e.push({ pageKey: m });
|
|
84
|
-
const
|
|
84
|
+
const { data: r } = await b.post(l, {
|
|
85
85
|
jsonrpc: "2.0",
|
|
86
86
|
id: 1,
|
|
87
87
|
method: "alchemy_getTokenBalances",
|
|
88
88
|
params: e
|
|
89
|
-
}), { result: i } =
|
|
90
|
-
|
|
89
|
+
}), { result: i } = r;
|
|
90
|
+
a.push(...i?.tokenBalances ?? []), m = i?.pageKey;
|
|
91
91
|
} while (m);
|
|
92
|
-
s && s > 0n &&
|
|
92
|
+
s && s > 0n && a.push({
|
|
93
93
|
contractAddress: y,
|
|
94
94
|
tokenBalance: s.toString()
|
|
95
95
|
});
|
|
96
96
|
const c = {};
|
|
97
|
-
return
|
|
97
|
+
return a.forEach((e) => {
|
|
98
98
|
(!c[e.contractAddress] || BigInt(e.tokenBalance) > 0n) && (c[e.contractAddress] = e);
|
|
99
99
|
}), Object.keys(c);
|
|
100
100
|
}
|
|
101
101
|
async getNFTTokens(n, t) {
|
|
102
102
|
const s = `https://${this.ALCHEMY_URLS[n]}.g.alchemy.com/nft/v3/${g}/getNFTsForOwner`, l = [];
|
|
103
|
-
let
|
|
103
|
+
let a;
|
|
104
104
|
do {
|
|
105
105
|
const e = new URLSearchParams({
|
|
106
106
|
owner: t,
|
|
@@ -108,22 +108,22 @@ class L {
|
|
|
108
108
|
pageSize: "100"
|
|
109
109
|
// max is 100
|
|
110
110
|
});
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
l.push(...i),
|
|
114
|
-
} while (
|
|
115
|
-
const c = l.filter(({ contractAddress: e, tokenId:
|
|
116
|
-
const
|
|
117
|
-
return e.has(
|
|
111
|
+
a && e.append("pageKey", a);
|
|
112
|
+
const { data: r } = await b.get(`${s}?${e.toString()}`), { ownedNfts: i = [], pageKey: f } = r;
|
|
113
|
+
l.push(...i), a = f;
|
|
114
|
+
} while (a);
|
|
115
|
+
const c = l.filter(({ contractAddress: e, tokenId: r }) => e && r).reduce((e, { contractAddress: r, tokenId: i }) => {
|
|
116
|
+
const f = r.toLowerCase();
|
|
117
|
+
return e.has(f) || e.set(f, []), e.get(f)?.push(i), e;
|
|
118
118
|
}, /* @__PURE__ */ new Map());
|
|
119
|
-
return Array.from(c.entries()).map(([e,
|
|
119
|
+
return Array.from(c.entries()).map(([e, r]) => ({
|
|
120
120
|
contractAddress: e,
|
|
121
|
-
tokenIds:
|
|
121
|
+
tokenIds: r
|
|
122
122
|
}));
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
-
const
|
|
125
|
+
const x = new L();
|
|
126
126
|
export {
|
|
127
127
|
L as AlchemyPublicTokensDB,
|
|
128
|
-
|
|
128
|
+
x as alchemyPublicTokensDB
|
|
129
129
|
};
|