Skip to content

Commit

Permalink
URI encode calls to proxy, update usage of Opensea API (floating#749)
Browse files Browse the repository at this point in the history
* URI encode calls to proxy, update usage of Opensea API

* cleanup

* Improve inventory display and linking

* Update valid host check

Co-authored-by: Jordan Muir <[email protected]>
  • Loading branch information
mholtzman and floating authored Feb 24, 2022
1 parent f0e2efa commit 0c24a44
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 46 deletions.
2 changes: 1 addition & 1 deletion app/App/Panel/Main/Account/Balances/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class Balances extends React.Component {
<div className='signerBalanceInner' style={{ opacity: doneScanning || i === 0 || rawBalance > 0 ? 1 : 0, transitionDelay: (0.1 * i) + 's' }}>
<div className='signerBalanceLogo'>
<img
src={`https://proxy.pylon.link?type=icon&target=${balanceInfo.logoURI}`}
src={`https://proxy.pylon.link?type=icon&target=${encodeURIComponent(balanceInfo.logoURI)}`}
value={symbol.toUpperCase()}
alt={symbol.toUpperCase()}
/>
Expand Down
38 changes: 32 additions & 6 deletions app/App/Panel/Main/Account/Inventory/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,36 @@ class Balances extends React.Component {
<div className='moduleHeader'>
{'Inventory'}
{this.props.expanded ? (
<div className='moduleHeaderClose' onMouseDown={() => this.props.expandModule(false)}>
<div className='moduleHeaderClose' onMouseDown={() => {
this.props.expandModule(false)
}}>
{svg.close(12)}
</div>
) : null}
</div>
<div>
{collections.length ? collections.map(k => {
{collections.length ? collections.filter(k => {
if (this.props.expanded) {
const expandedData = this.props.expandedData || {}
const current = expandedData.currentCollection
return current === k
} else {
return true
}
}).sort((a, b) => {
const assetsLengthA = Object.keys(inventory[a].assets).length
const assetsLengthB = Object.keys(inventory[b].assets).length
if (assetsLengthA > assetsLengthB) return -1
if (assetsLengthA < assetsLengthB) return 1
return 0
}).map(k => {
return (
<div className='inventoryCollection' onMouseDown={() => this.props.expandModule(this.props.moduleId)}>
<div
className='inventoryCollection'
onClick={() => {
this.props.expandModule(this.props.moduleId, { currentCollection: k })
}}
>
<div className='inventoryCollectionTop'>
<div className='inventoryCollectionName'>{inventory[k].meta.name}</div>
<div className='inventoryCollectionCount'>{Object.keys(inventory[k].assets).length}</div>
Expand All @@ -55,10 +76,15 @@ class Balances extends React.Component {
b = inventory[k].assets[b].tokenId
return a < b ? -1 : b > a ? 1 : 0
}).map(id => {
const { tokenId, name, img } = inventory[k].assets[id]
const { tokenId, name, img, openSeaLink } = inventory[k].assets[id]
return (
<div className='inventoryCollectionItem'>
{img ? <img src={`https://proxy.pylon.link?type=nft&target=${img}`} /> : null}
<div
className='inventoryCollectionItem'
onClick={() => {
this.store.notify('openExternal', { url: openSeaLink })
}}
>
{img ? <img src={`https://proxy.pylon.link?type=nft&target=${encodeURIComponent(img)}`} /> : null}
</div>
)
})}
Expand Down
3 changes: 3 additions & 0 deletions app/App/Panel/Main/Account/Inventory/style/index.styl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
box-sizing border-box
box-shadow 0px 4px 10px var(--ghostZ)
cursor pointer
*
pointer-events none

img
width 100%
Expand All @@ -47,6 +49,7 @@
right 16px
bottom -1px
border-bottom 1px solid var(--ghostA)
pointer-events none

.inventoryCollectionName
display flex
Expand Down
28 changes: 21 additions & 7 deletions app/App/Panel/Main/Account/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ class _AccountMain extends React.Component {
// slideHeight += modulePositions[i].height
// })
// }
renderModule (id, module, top, index, expandModule, expanded) {
renderModule (id, module, top, index, expandModule, expanded, expandedData) {
// console.log(id, module, top, index)
let hidden = false
let style = {
Expand Down Expand Up @@ -254,6 +254,7 @@ class _AccountMain extends React.Component {
id={this.props.id}
expandModule={expandModule}
expanded={expanded}
expandedData={expandedData}
/> :
id === 'permissions' ? <Permissions
moduleId={id}
Expand Down Expand Up @@ -283,6 +284,9 @@ class _AccountMain extends React.Component {
</div>
)
}
expandModule (id, data) {
this.setState({ expandedModule: id, expandedModuleData: data || {} })
}
render () {
const accountModules = this.store('panel.account.modules')
const accountModuleOrder = this.store('panel.account.moduleOrder')
Expand All @@ -291,9 +295,13 @@ class _AccountMain extends React.Component {
const modules = accountModuleOrder.map((id, i) => {
const module = accountModules[id] || { height: 0 }
slideHeight += module.height + 5
return this.renderModule(id, module, slideHeight - module.height - 5, i, id => {
this.setState({ expandedModule: id })
})
return this.renderModule(
id,
module,
slideHeight - module.height - 5,
i,
this.expandModule.bind(this)
)
})
return (
<div className='accountMain'>
Expand All @@ -306,9 +314,15 @@ class _AccountMain extends React.Component {
<div className='moduleExpanded' onMouseDown={(e) => {
e.stopPropagation()
}}>
{this.renderModule(this.state.expandedModule, { height: '100%' }, 0, 0, id => {
this.setState({ expandedModule: id })
}, true)}
{this.renderModule(
this.state.expandedModule,
{ height: '100%' },
0,
0,
this.expandModule.bind(this),
true,
this.state.expandedModuleData
)}
</div>
</div>
) : null}
Expand Down
2 changes: 1 addition & 1 deletion app/App/Panel/Main/Signer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class _Balances extends React.Component {
return (
<div className='signerBalance' key={k} onMouseDown={() => this.setState({ selected: i })}>
<div className='signerBalanceLogo'>
<img src={`https://proxy.pylon.link?type=icon&target=${token.logoURI}`} />
<img src={`https://proxy.pylon.link?type=icon&target=${encodeURIComponent(token.logoURI)}`} />
</div>
<div className='signerBalanceCurrency'>
{token.symbol}
Expand Down
2 changes: 1 addition & 1 deletion app/App/Panel/Notify/CustomTokens/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class CustomTokens extends React.Component {
<div className='customTokensListItemTitle'>
<div className='customTokensListItemName'>
<img
src={`https://proxy.pylon.link?type=icon&target=${token.logoURI}`}
src={`https://proxy.pylon.link?type=icon&target=${encodeURIComponent(token.logoURI)}`}
value={token.symbol.toUpperCase()}
alt={token.symbol.toUpperCase()}
/>
Expand Down
3 changes: 2 additions & 1 deletion app/App/Panel/Notify/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,8 @@ class Notify extends React.Component {
Open External Link
</div>
<div className='notifyBody'>
<div className='notifyBodyLine'>{`Frame will now open ${url} in your browser`}</div>
<div className='notifyBodyLineUrl'>{url}</div>
<div className='notifyBodyLine'>{'Open Link in Browser?'}</div>
</div>
<div className='notifyInput'>
<div
Expand Down
13 changes: 13 additions & 0 deletions app/App/Panel/Notify/style/index.styl
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,19 @@
box-sizing border-box
padding 20px

.notifyBodyLine
padding 0px 0px
text-transform uppercase
font-size 16px
font-weight 500
font-family 'Exo2'

.notifyBodyLineUrl
padding-bottom 56px
font-family FiraCode, monospace
font-size 16px
font-weight 100

.notifyBodyUpdate
padding 8px
margin-bottom 8px
Expand Down
68 changes: 41 additions & 27 deletions main/externalData/inventory/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ interface AssetContract {
}

interface InventorySet {
next: string | null,
previous: string | null,
assets: AssetSet[]
}

Expand All @@ -38,8 +40,24 @@ interface Collection {
large_image_url: string
}

async function fetchAssets (address: Address, offset: number) {
const url = `https://proxy.pylon.link?type=api&target=https://api.opensea.io/api/v1/assets?owner=${address}&order_direction=desc&offset=${offset}&limit=50`
async function fetchAssets (address: Address, cursor?: string) {
const queryParams = {
owner: address,
order_direction: 'desc',
limit: '50',
cursor
}

const queryStr = Object.entries(queryParams).reduce((params, [key, value]) => {
if (value) {
params.push([key, value].join('='))
}

return params
}, [] as string[]).join('&')

const target = encodeURIComponent(`https://api.opensea.io/api/v1/assets?${queryStr}`)
const url = `https://proxy.pylon.link?type=api&target=${target}`

const options = {
method: 'GET',
Expand All @@ -56,39 +74,33 @@ async function fetchAssets (address: Address, offset: number) {
const errorMsg = contentType.includes('json') ? await res.json() : ''

log.warn('unable to fetch inventory', errorMsg)
return { assets: [] }
return { assets: [], next: null, previous: null }
}

return res.json() as Promise<InventorySet>
} catch (e) {
log.warn(`could not fetch assets ${address}`, e)

return { assets: [] }
return { assets: [], next: null, previous: null }
}
}

async function scan (address: Address) {
const inventory: Record<string, AssetSet> = {}
async function loadAssets (address: Address, cursor?: string): Promise<AssetSet[]> {
const set = await fetchAssets(address, cursor)

async function getSet (address: Address, offset = 0) {
const set = await fetchAssets(address, offset)
set.assets.forEach(a => {
inventory[a.id] = a
})
if (set.assets.length === 50) await getSet(address, offset + 50)
}

await getSet(address)
return inventory
return (set.next && set.next !== cursor)
? [...set.assets, ...(await loadAssets(address, set.next))]
: set.assets
}

export default async function (address: Address) {
let i = await scan(address)
const inventory: Record<string, any> = {}
let a = Object.keys(i).forEach(a => {
const { collection } = i[a]
if (!inventory[collection.slug]) {
inventory[collection.slug] = {
const assets = await loadAssets(address)

const inventory = assets.reduce((collectedInventory, asset) => {
const { name, id, token_id, image_url, description, external_link, permalink, traits, asset_contract, collection } = asset

if (!collectedInventory[collection.slug]) {
collectedInventory[collection.slug] = {
meta: {
name: collection.name,
description: collection.description,
Expand All @@ -98,8 +110,8 @@ export default async function (address: Address) {
assets: {}
}
}
const { name, id, token_id, image_url, description, external_link, permalink, traits, asset_contract } = i[a]
inventory[collection.slug].assets[id] = {

collectedInventory[collection.slug].assets[id] = {
name,
id,
tokenId: token_id,
Expand All @@ -118,9 +130,11 @@ export default async function (address: Address) {
description: asset_contract.description,
img: asset_contract.image_url,
link: asset_contract.external_link
},

}
}
})

return collectedInventory
}, {} as Record<string, any>)

return inventory
}
6 changes: 4 additions & 2 deletions main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ const externalWhitelist = [
'https://discord.gg/UH7NGqY',
'https://frame.canny.io',
'https://feedback.frame.sh',
'https://wiki.trezor.io/Trezor_Bridge'
'https://wiki.trezor.io/Trezor_Bridge',
'https://opensea.io'
]

global.eval = () => { throw new Error(`This app does not support global.eval()`) } // eslint-disable-line
Expand Down Expand Up @@ -137,7 +138,8 @@ ipcMain.on('dash:reloadSigner', (e, id) => {
})

ipcMain.on('tray:openExternal', (e, url) => {
if (externalWhitelist.indexOf(url) > -1) shell.openExternal(url)
const validHost = externalWhitelist.some(entry => url.startsWith(entry))
if (validHost) shell.openExternal(url)
})

ipcMain.on('tray:openExplorer', (e, hash, chain) => {
Expand Down

0 comments on commit 0c24a44

Please sign in to comment.