@@ -9,7 +9,6 @@ conseiljs.registerFetch(fetch)
99const conseilServer = 'https://conseil-prod.cryptonomic-infra.tech'
1010const conseilApiKey = 'aa73fa8a-8626-4f43-a605-ff63130f37b1' // signup at nautilus.cloud
1111const tezosNode = ''
12-
1312const mainnet = require ( './config' ) . networkConfig
1413
1514
@@ -101,6 +100,132 @@ const gethDaoBalanceForAddress = async (address) => {
101100 return balance
102101}
103102
103+ const getTokenBalance = async ( big_map_id , address , fa2 = false , token_id = 0 ) => {
104+ let tokenBalanceQuery = conseiljs . ConseilQueryBuilder . blankQuery ( ) ;
105+ tokenBalanceQuery = conseiljs . ConseilQueryBuilder . addFields ( tokenBalanceQuery , 'value' ) ;
106+ tokenBalanceQuery = conseiljs . ConseilQueryBuilder . addPredicate ( tokenBalanceQuery , 'big_map_id' , conseiljs . ConseilOperator . EQ , [ big_map_id ] )
107+ if ( fa2 ) {
108+ tokenBalanceQuery = conseiljs . ConseilQueryBuilder . addPredicate ( tokenBalanceQuery , 'key' , conseiljs . ConseilOperator . EQ , [
109+ `Pair 0x${ conseiljs . TezosMessageUtils . writeAddress ( address ) } ${ token_id } `
110+ ] )
111+ }
112+ else {
113+ tokenBalanceQuery = conseiljs . ConseilQueryBuilder . addPredicate ( tokenBalanceQuery , 'key' , conseiljs . ConseilOperator . EQ , [
114+ `0x${ conseiljs . TezosMessageUtils . writeAddress ( address ) } `
115+ ] )
116+ }
117+ tokenBalanceQuery = conseiljs . ConseilQueryBuilder . addPredicate ( tokenBalanceQuery , 'value' , conseiljs . ConseilOperator . EQ , [ 0 ] , true )
118+ tokenBalanceQuery = conseiljs . ConseilQueryBuilder . setLimit ( tokenBalanceQuery , 1 )
119+
120+ let balance = 0
121+
122+ try {
123+ const balanceResult = await conseiljs . TezosConseilClient . getTezosEntityData ( { url : conseilServer , apiKey : conseilApiKey , network : 'mainnet' } , 'mainnet' , 'big_map_contents' , tokenBalanceQuery ) ;
124+ balance = balanceResult [ 0 ] [ 'value' ] // TODO: consider bigNumber here, for the moment there is no reason for it
125+ } catch ( error ) {
126+ console . log ( `getTokenBalance failed for ${ JSON . stringify ( tokenBalanceQuery ) } with ${ error } ` )
127+ }
128+
129+ return balance
130+ }
131+
132+
133+ const getTezBalanceForAddress = async ( address ) => {
134+ let accountQuery = conseiljs . ConseilQueryBuilder . blankQuery ( ) ;
135+ accountQuery = conseiljs . ConseilQueryBuilder . addFields ( accountQuery , 'balance' ) ;
136+ accountQuery = conseiljs . ConseilQueryBuilder . addPredicate ( accountQuery , 'account_id' , conseiljs . ConseilOperator . EQ , [ address ] , false ) ;
137+ accountQuery = conseiljs . ConseilQueryBuilder . setLimit ( accountQuery , 1 ) ;
138+
139+ try {
140+ const balanceResult = await conseiljs . TezosConseilClient . getTezosEntityData ( { url : conseilServer , apiKey : conseilApiKey , network : 'mainnet' } , 'mainnet' , 'accounts' , accountQuery ) ;
141+ balance = balanceResult [ 0 ] [ 'balance' ] // TODO: consider bigNumber here, for the moment there is no reason for it
142+ } catch ( error ) {
143+ console . log ( `getTezBalanceForAddress failed for ${ JSON . stringify ( accountQuery ) } with ${ error } ` )
144+ }
145+
146+ return balance
147+ }
148+
149+
150+ const gethDAOPerTez = async ( ) => {
151+ const tezBalance = await ( getTezBalanceForAddress ( mainnet . hDaoSwap ) )
152+ const hdaoBalance = await ( gethDaoBalanceForAddress ( mainnet . hDaoSwap ) )
153+ return hdaoBalance / tezBalance
154+ }
155+
156+ const getKolibriPerTez = async ( ) => {
157+ const tezBalance = await ( getTezBalanceForAddress ( mainnet . kolibriSwap ) )
158+ //console.log("Tez balance", tezBalance)
159+ var kolibriBalance = await ( getTokenBalance ( mainnet . kolibriLedger , mainnet . kolibriSwap ) )
160+ kolibriBalance = parseInt ( kolibriBalance . replace ( "Pair {} " , "" ) ) / ( 10 ** ( ( 18 - 6 ) ) )
161+ //console.log(kolibriBalance)
162+ //console.log(typeof(kolibriBalance))
163+ //console.log("Kol balance", kolibriBalance)
164+ return kolibriBalance / tezBalance
165+ }
166+
167+
168+ const gethDaoBalances = async ( ) => {
169+ let hDaoBalanceQuery = conseiljs . ConseilQueryBuilder . blankQuery ( ) ;
170+ hDaoBalanceQuery = conseiljs . ConseilQueryBuilder . addFields ( hDaoBalanceQuery , 'key' , 'value' ) ;
171+ hDaoBalanceQuery = conseiljs . ConseilQueryBuilder . addPredicate ( hDaoBalanceQuery , 'big_map_id' , conseiljs . ConseilOperator . EQ , [ mainnet . daoLedger ] )
172+ hDaoBalanceQuery = conseiljs . ConseilQueryBuilder . addPredicate ( hDaoBalanceQuery , 'value' , conseiljs . ConseilOperator . EQ , [ 0 ] , true )
173+ hDaoBalanceQuery = conseiljs . ConseilQueryBuilder . setLimit ( hDaoBalanceQuery , 500_000 )
174+
175+ let balance = 0
176+ let hdaoMap = { }
177+
178+ try {
179+ const balanceResult = await conseiljs . TezosConseilClient . getTezosEntityData ( { url : conseilServer , apiKey : conseilApiKey , network : 'mainnet' } , 'mainnet' , 'big_map_contents' , hDaoBalanceQuery ) ;
180+
181+
182+ balanceResult . forEach ( row => {
183+ hdaoMap [ conseiljs . TezosMessageUtils . readAddress ( row [ 'key' ] . toString ( ) . replace ( / ^ P a i r 0 x ( [ 0 - 9 a - z ] { 1 , } ) [ 0 - 9 ] + / , '$1' ) ) ] = row [ 'value' ]
184+ } )
185+ //#balance = balanceResult[0]['value'] // TODO: consider bigNumber here, for the moment there is no reason for it
186+ } catch ( error ) {
187+ console . log ( `gethDaoBalanceForAddress failed for ${ JSON . stringify ( hDaoBalanceQuery ) } with ${ error } ` )
188+ }
189+
190+
191+ return hdaoMap
192+
193+ }
194+
195+ const getObjektMintingsLastWeek = async ( ) => {
196+ var d = new Date ( ) ;
197+ d . setDate ( d . getDate ( ) - 5 ) ;
198+ let mintOperationQuery = conseiljs . ConseilQueryBuilder . blankQuery ( ) ;
199+ mintOperationQuery = conseiljs . ConseilQueryBuilder . addFields ( mintOperationQuery , 'source' ) ;
200+ mintOperationQuery = conseiljs . ConseilQueryBuilder . addPredicate ( mintOperationQuery , 'kind' , conseiljs . ConseilOperator . EQ , [ 'transaction' ] )
201+ mintOperationQuery = conseiljs . ConseilQueryBuilder . addPredicate ( mintOperationQuery , 'timestamp' , conseiljs . ConseilOperator . AFTER , [ d . getTime ( ) ] ) // 2021 Feb 1
202+ mintOperationQuery = conseiljs . ConseilQueryBuilder . addPredicate ( mintOperationQuery , 'status' , conseiljs . ConseilOperator . EQ , [ 'applied' ] )
203+ mintOperationQuery = conseiljs . ConseilQueryBuilder . addPredicate ( mintOperationQuery , 'destination' , conseiljs . ConseilOperator . EQ , [ mainnet . protocol ] )
204+ mintOperationQuery = conseiljs . ConseilQueryBuilder . addPredicate ( mintOperationQuery , 'parameters_entrypoints' , conseiljs . ConseilOperator . EQ , [ 'mint_OBJKT' ] )
205+ mintOperationQuery = conseiljs . ConseilQueryBuilder . addOrdering ( mintOperationQuery , 'block_level' , conseiljs . ConseilSortDirection . DESC )
206+ mintOperationQuery = conseiljs . ConseilQueryBuilder . setLimit ( mintOperationQuery , 900_000 ) // TODO: this is hardwired and will not work for highly productive artists
207+
208+ const mintOperationResult = await conseiljs . TezosConseilClient . getTezosEntityData (
209+ { url : conseilServer , apiKey : conseilApiKey , network : 'mainnet' } ,
210+ 'mainnet' ,
211+ 'operations' ,
212+ mintOperationQuery ) ;
213+
214+ const mints = mintOperationResult . map ( r => r [ 'source' ] )
215+
216+ var initialValue = { }
217+ var reducer = function ( minters , mintOp ) {
218+ if ( ! minters [ mintOp ] ) {
219+ minters [ mintOp ] = 1 ;
220+ } else {
221+ minters [ mintOp ] = minters [ mintOp ] + 1 ;
222+ }
223+ return minters ;
224+ }
225+ return mints . reduce ( reducer , initialValue )
226+ }
227+
228+
104229/**
105230 * Queries Conseil in two steps to get all the objects minted by a specific address. Step 1 is to query for all 'mint_OBJKT' operations performed by the account to get the list of operation group hashes. Then that list is partitioned into chunks and another query (or set of queries) is run to get big_map values. These values are then parsed into an array of 3-tuples containing the hashed big_map key that can be used to query a Tezos node directly, the nft token id and the ipfs item hash.
106231 *
@@ -239,6 +364,46 @@ const getArtisticUniverse = async (max_time) => {
239364 return universe
240365}
241366
367+
368+ const getFeaturedArtisticUniverse = async ( max_time ) => {
369+
370+ hdaoMap = await gethDaoBalances ( )
371+
372+ mintsPerCreator = await getObjektMintingsLastWeek ( )
373+
374+ artisticUniverse = await getArtisticUniverse ( max_time )
375+
376+ hdaoPerTez = await gethDAOPerTez ( )
377+
378+ // Cost to be on feed per objekt last 7 days shouldn't be higher than:
379+ // 0.1tez
380+ // 1 hDAO
381+ // But not lower than:
382+ // 0.01 hDAO
383+ //
384+ // We should probably add more thresholds like $, € and yen
385+ // It should be cheap but not too cheap and it shouldn't be
386+ // affected by tez or hDAO volatility
387+
388+ thresholdHdao = Math . min ( 1_000_000 , Math . max ( 100_000 * hdaoPerTez , 10_000 ) )
389+
390+ return artisticUniverse . filter ( function ( o ) {
391+ return ( ( hdaoMap [ o . minter ] || 0 ) / Math . max ( mintsPerCreator [ o . minter ] || 1 , 1 ) ) > thresholdHdao
392+ } )
393+ }
394+
395+ const getRecommendedCurateDefault = async ( ) => {
396+ hdaoPerTez = await gethDAOPerTez ( )
397+ kolPerTez = await getKolibriPerTez ( )
398+ //console.log("hdaoPerTez", hdaoPerTez)
399+ //console.log("kolPerTez", kolPerTez)
400+ hdaoPerKol = hdaoPerTez / kolPerTez
401+ //console.log("hdaoPerKol", hdaoPerKol)
402+
403+ //Minimum of $0.1, 0.1 hDAO, and 0.1tez, in hDAO
404+ return Math . floor ( Math . min ( hdaoPerKol * 0.1 , 0.1 , 0.1 * hdaoPerTez ) * 1_000_000 )
405+ }
406+
242407/**
243408 * Returns object ipfs hash and swaps if any
244409 *
@@ -304,5 +469,7 @@ module.exports = {
304469 getArtisticOutputForAddress,
305470 getObjectById,
306471 getArtisticUniverse,
307- hDAOFeed
472+ getFeaturedArtisticUniverse,
473+ hDAOFeed,
474+ getRecommendedCurateDefault
308475}
0 commit comments