Commit 14bac770 authored by Moody Salem's avatar Moody Salem

fix(arbitrum): explorer links and better anonymization of GA events

parent c9dbe2f0
import { darken } from 'polished'
import React, { HTMLProps } from 'react'
import { ArrowLeft, ExternalLink as LinkIconFeather, Trash, X } from 'react-feather'
import ReactGA from 'react-ga'
import { Link } from 'react-router-dom'
import styled, { keyframes } from 'styled-components'
import { darken } from 'polished'
import { ArrowLeft, X, ExternalLink as LinkIconFeather, Trash } from 'react-feather'
import { anonymizeLink } from '../utils/anonymizeLink'
export const ButtonText = styled.button`
outline: none;
......@@ -197,31 +198,6 @@ export const UniTokenAnimated = styled.img`
filter: drop-shadow(0px 2px 4px rgba(0, 0, 0, 0.15));
`
const ETHERSCAN_HOSTNAMES: { [hostname: string]: true } = {
'etherscan.io': true,
'ropsten.etherscan.io': true,
'rinkeby.etherscan.io': true,
'kovan.etherscan.io': true,
'goerli.etherscan.io': true,
}
/**
* Returns the anonymized version of the given href, i.e. one that does not leak user information
* @param href the anonymized version of the given href
*/
function anonymizeLink(href: string): string {
try {
const url = new URL(href)
if (ETHERSCAN_HOSTNAMES[url.hostname]) {
return `${url.hostname}/${url.pathname.split('/')[1]}/***`
}
return href
} catch (error) {
console.error('Failed to anonymize outbound link', error)
return href
}
}
function handleClickExternalLink(event: React.MouseEvent<HTMLAnchorElement>) {
const { target, href } = event.currentTarget
......
import { anonymizeLink } from './anonymizeLink'
describe('#anonymizeLink', () => {
it('does nothing to non-urls', () => {
expect(anonymizeLink('not a link')).toEqual('not a link')
})
it('anonymizes any addresses in etherscan urls', () => {
expect(anonymizeLink('https://etherscan.io/address/0xabcd')).toEqual('https://etherscan.io/address/***')
})
it('anonymizes any addresses in etherscan urls', () => {
expect(anonymizeLink('https://etherscan.io/address/0xabcd')).toEqual('https://etherscan.io/address/***')
})
it('anonymizes any addresses in testnet etherscan urls', () => {
expect(anonymizeLink('https://rinkeby.etherscan.io/address/0xabcd')).toEqual(
'https://rinkeby.etherscan.io/address/***'
)
})
it('anonymizes any addresses in testnet etherscan urls', () => {
expect(anonymizeLink('https://ropsten.etherscan.io/address/0xabcd')).toEqual(
'https://ropsten.etherscan.io/address/***'
)
})
it('anonymizes hashes in the middle of the url', () => {
expect(anonymizeLink('https://ropsten.etherscan.io/address/0xabcd/test')).toEqual(
'https://ropsten.etherscan.io/address/***/test'
)
})
it('does not anonymize 0x', () => {
expect(anonymizeLink('https://ropsten.etherscan.io/address/0x/test')).toEqual(
'https://ropsten.etherscan.io/address/0x/test'
)
})
it('works for arbitrum urls', () => {
expect(anonymizeLink('https://explorer.arbitrum.io/0x/0xabc')).toEqual('https://explorer.arbitrum.io/0x/***')
})
it('works for arbitrum rinkeby urls', () => {
expect(anonymizeLink('https://rinkeby-explorer.arbitrum.io/0x/0xabc')).toEqual(
'https://rinkeby-explorer.arbitrum.io/0x/***'
)
})
})
const EXPLORER_HOSTNAMES: { [hostname: string]: true } = {
'etherscan.io': true,
'ropsten.etherscan.io': true,
'rinkeby.etherscan.io': true,
'kovan.etherscan.io': true,
'goerli.etherscan.io': true,
'rinkeby-explorer.arbitrum.io': true,
'explorer.arbitrum.io': true,
}
/**
* Returns the anonymized version of the given href, i.e. one that does not leak user information
* @param href the link to anonymize, i.e. remove any personal data from
* @return string anonymized version of the given href
*/
export function anonymizeLink(href: string): string {
try {
const url = new URL(href)
if (EXPLORER_HOSTNAMES[url.hostname]) {
const pathPieces = url.pathname.split('/')
const anonymizedPath = pathPieces.map((pc) => (/0x[a-fA-F0-9]+/.test(pc) ? '***' : pc)).join('/')
return `${url.protocol}//${url.hostname}${anonymizedPath}`
}
return href
} catch (error) {
return href
}
}
......@@ -25,13 +25,26 @@ export function getExplorerLink(chainId: number, data: string, type: ExplorerDat
if (chainId === SupportedChainId.ARBITRUM_ONE) {
switch (type) {
case ExplorerDataType.TRANSACTION:
return `https://mainnet-arb-explorer.netlify.app/tx/${data}`
return `https://explorer.arbitrum.io/tx/${data}`
case ExplorerDataType.ADDRESS:
return `https://mainnet-arb-explorer.netlify.app/address/${data}`
return `https://explorer.arbitrum.io/address/${data}`
case ExplorerDataType.BLOCK:
return `https://mainnet-arb-explorer.netlify.app/block/${data}`
return `https://explorer.arbitrum.io/block/${data}`
default:
return `https://mainnet-arb-explorer.netlify.app`
return `https://explorer.arbitrum.io/`
}
}
if (chainId === SupportedChainId.ARBITRUM_RINKEBY) {
switch (type) {
case ExplorerDataType.TRANSACTION:
return `https://rinkeby-explorer.arbitrum.io/tx/${data}`
case ExplorerDataType.ADDRESS:
return `https://rinkeby-explorer.arbitrum.io/address/${data}`
case ExplorerDataType.BLOCK:
return `https://rinkeby-explorer.arbitrum.io/block/${data}`
default:
return `https://rinkeby-explorer.arbitrum.io/`
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment