Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
frontend
Commits
0a992acd
Commit
0a992acd
authored
Aug 11, 2023
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor features config
parent
64981a9e
Changes
59
Hide whitespace changes
Inline
Side-by-side
Showing
59 changed files
with
776 additions
and
325 deletions
+776
-325
account.ts
configs/app/features/account.ts
+25
-6
addressVerification.ts
configs/app/features/addressVerification.ts
+23
-8
adsBanner.ts
configs/app/features/adsBanner.ts
+46
-9
adsText.ts
configs/app/features/adsText.ts
+19
-5
beaconChain.ts
configs/app/features/beaconChain.ts
+25
-7
blockchainInteraction.ts
configs/app/features/blockchainInteraction.ts
+25
-9
csvExport.ts
configs/app/features/csvExport.ts
+21
-9
googleAnalytics.ts
configs/app/features/googleAnalytics.ts
+20
-5
graphqlApiDocs.ts
configs/app/features/graphqlApiDocs.ts
+13
-5
marketplace.ts
configs/app/features/marketplace.ts
+27
-8
mixpanel.ts
configs/app/features/mixpanel.ts
+20
-5
restApiDocs.ts
configs/app/features/restApiDocs.ts
+20
-5
rollup.ts
configs/app/features/rollup.ts
+28
-6
sentry.ts
configs/app/features/sentry.ts
+23
-9
sol2uml.ts
configs/app/features/sol2uml.ts
+23
-8
stats.ts
configs/app/features/stats.ts
+23
-8
types.ts
configs/app/features/types.ts
+10
-0
verifiedTokens.ts
configs/app/features/verifiedTokens.ts
+23
-8
web3Wallet.ts
configs/app/features/web3Wallet.ts
+23
-9
react.ts
configs/sentry/react.ts
+63
-52
resources.ts
lib/api/resources.ts
+19
-18
ad.ts
lib/csp/policies/ad.ts
+1
-1
app.ts
lib/csp/policies/app.ts
+19
-11
useConfigSentry.tsx
lib/hooks/useConfigSentry.tsx
+4
-0
useIsAccountActionAllowed.tsx
lib/hooks/useIsAccountActionAllowed.tsx
+4
-0
useLoginUrl.tsx
lib/hooks/useLoginUrl.tsx
+5
-1
useRedirectForInvalidAuthToken.tsx
lib/hooks/useRedirectForInvalidAuthToken.tsx
+1
-1
useInit.tsx
lib/mixpanel/useInit.tsx
+3
-2
account.ts
lib/next/middlewares/account.ts
+4
-13
useProvider.tsx
lib/web3/useProvider.tsx
+5
-3
buildApiUrl.ts
playwright/utils/buildApiUrl.ts
+1
-1
SwaggerUI.tsx
ui/apiDocs/SwaggerUI.tsx
+7
-1
CsvExportFormReCaptcha.tsx
ui/csvExport/CsvExportFormReCaptcha.tsx
+4
-2
GraphQL.tsx
ui/graphQL/GraphQL.tsx
+7
-1
LatestDepositsItem.tsx
ui/home/LatestDepositsItem.tsx
+8
-2
DepositsListItem.tsx
ui/l2Deposits/DepositsListItem.tsx
+9
-3
DepositsTableItem.tsx
ui/l2Deposits/DepositsTableItem.tsx
+9
-3
OutputRootsListItem.tsx
ui/l2OutputRoots/OutputRootsListItem.tsx
+7
-1
OutputRootsTableItem.tsx
ui/l2OutputRoots/OutputRootsTableItem.tsx
+7
-1
TxnBatchesListItem.tsx
ui/l2TxnBatches/TxnBatchesListItem.tsx
+8
-2
TxnBatchesTableItem.tsx
ui/l2TxnBatches/TxnBatchesTableItem.tsx
+8
-2
WithdrawalsListItem.tsx
ui/l2Withdrawals/WithdrawalsListItem.tsx
+8
-2
WithdrawalsTableItem.tsx
ui/l2Withdrawals/WithdrawalsTableItem.tsx
+8
-2
useMarketplaceApps.tsx
ui/marketplace/useMarketplaceApps.tsx
+5
-1
Marketplace.tsx
ui/pages/Marketplace.tsx
+24
-21
MarketplaceApp.tsx
ui/pages/MarketplaceApp.tsx
+7
-1
Withdrawals.tsx
ui/pages/Withdrawals.tsx
+4
-2
GoogleAnalytics.tsx
ui/shared/GoogleAnalytics.tsx
+4
-2
NetworkAddToWallet.tsx
ui/shared/NetworkAddToWallet.tsx
+4
-8
Web3ModalProvider.tsx
ui/shared/Web3ModalProvider.tsx
+7
-5
AdBanner.tsx
ui/shared/ad/AdBanner.tsx
+5
-3
AdbutlerBanner.tsx
ui/shared/ad/AdbutlerBanner.tsx
+11
-5
adbutlerScript.ts
ui/shared/ad/adbutlerScript.ts
+21
-13
AddressAddToWallet.tsx
ui/shared/address/AddressAddToWallet.tsx
+5
-5
ProfileMenuContent.tsx
ui/snippets/profileMenu/ProfileMenuContent.tsx
+7
-1
ProfileMenuDesktop.tsx
ui/snippets/profileMenu/ProfileMenuDesktop.tsx
+1
-1
ProfileMenuMobile.tsx
ui/snippets/profileMenu/ProfileMenuMobile.tsx
+1
-1
WithdrawalsListItem.tsx
ui/withdrawals/WithdrawalsListItem.tsx
+7
-1
WithdrawalsTable.tsx
ui/withdrawals/WithdrawalsTable.tsx
+7
-1
No files found.
configs/app/features/account.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
stripTrailingSlash
from
'
lib/stripTrailingSlash
'
;
import
stripTrailingSlash
from
'
lib/stripTrailingSlash
'
;
import
app
from
'
../app
'
;
import
app
from
'
../app
'
;
...
@@ -25,9 +27,26 @@ const logoutUrl = (() => {
...
@@ -25,9 +27,26 @@ const logoutUrl = (() => {
}
}
})();
})();
export
default
Object
.
freeze
({
const
title
=
'
My account
'
;
title
:
'
My account
'
,
isEnabled
:
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED
)
===
'
true
'
,
const
config
:
Feature
<
{
authUrl
:
string
;
logoutUrl
:
string
}
>
=
(()
=>
{
authUrl
,
if
(
logoutUrl
,
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED
)
===
'
true
'
&&
});
authUrl
&&
logoutUrl
)
{
return
Object
.
freeze
({
title
,
isEnabled
:
true
,
authUrl
,
logoutUrl
,
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/addressVerification.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
account
from
'
./account
'
;
import
account
from
'
./account
'
;
import
verifiedTokens
from
'
./verifiedTokens
'
;
import
verifiedTokens
from
'
./verifiedTokens
'
;
const
adminServiceApiHost
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST
);
const
adminServiceApiHost
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST
);
export
default
Object
.
freeze
({
const
title
=
'
Address verification in "My account"
'
;
title
:
'
Address verification in "My account"
'
,
isEnabled
:
account
.
isEnabled
&&
verifiedTokens
.
isEnabled
&&
Boolean
(
adminServiceApiHost
),
const
config
:
Feature
<
{
api
:
{
endpoint
:
string
;
basePath
:
string
}
}
>
=
(()
=>
{
api
:
{
if
(
account
.
isEnabled
&&
verifiedTokens
.
isEnabled
&&
adminServiceApiHost
)
{
endpoint
:
adminServiceApiHost
,
return
Object
.
freeze
({
basePath
:
''
,
title
:
'
Address verification in "My account"
'
,
},
isEnabled
:
true
,
});
api
:
{
endpoint
:
adminServiceApiHost
,
basePath
:
''
,
},
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/adsBanner.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
type
{
AdButlerConfig
}
from
'
types/client/adButlerConfig
'
;
import
type
{
AdButlerConfig
}
from
'
types/client/adButlerConfig
'
;
import
type
{
AdBannerProviders
}
from
'
types/client/adProviders
'
;
import
type
{
AdBannerProviders
}
from
'
types/client/adProviders
'
;
...
@@ -10,14 +11,50 @@ const provider: AdBannerProviders = (() => {
...
@@ -10,14 +11,50 @@ const provider: AdBannerProviders = (() => {
return
envValue
&&
SUPPORTED_AD_BANNER_PROVIDERS
.
includes
(
envValue
)
?
envValue
:
'
slise
'
;
return
envValue
&&
SUPPORTED_AD_BANNER_PROVIDERS
.
includes
(
envValue
)
?
envValue
:
'
slise
'
;
})();
})();
export
default
Object
.
freeze
({
const
title
=
'
Banner ads
'
;
title
:
'
Banner ads
'
,
isEnabled
:
provider
!==
'
none
'
,
type
AdsBannerFeaturePayload
=
{
provider
,
provider
:
Exclude
<
AdBannerProviders
,
'
adbutler
'
|
'
none
'
>
;
}
|
{
provider
:
'
adbutler
'
;
adButler
:
{
adButler
:
{
config
:
{
config
:
{
desktop
:
parseEnvJson
<
AdButlerConfig
>
(
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP
))
??
undefined
,
desktop
:
AdButlerConfig
;
mobile
:
parseEnvJson
<
AdButlerConfig
>
(
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE
))
??
undefined
,
mobile
:
AdButlerConfig
;
},
};
},
};
});
}
const
config
:
Feature
<
AdsBannerFeaturePayload
>
=
(()
=>
{
if
(
provider
===
'
adbutler
'
)
{
const
desktopConfig
=
parseEnvJson
<
AdButlerConfig
>
(
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP
));
const
mobileConfig
=
parseEnvJson
<
AdButlerConfig
>
(
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE
));
if
(
desktopConfig
&&
mobileConfig
)
{
return
Object
.
freeze
({
title
,
isEnabled
:
true
,
provider
,
adButler
:
{
config
:
{
desktop
:
desktopConfig
,
mobile
:
mobileConfig
,
},
},
});
}
}
else
if
(
provider
!==
'
none
'
)
{
return
Object
.
freeze
({
title
,
isEnabled
:
true
,
provider
,
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/adsText.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
type
{
AdTextProviders
}
from
'
types/client/adProviders
'
;
import
type
{
AdTextProviders
}
from
'
types/client/adProviders
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
...
@@ -9,8 +10,21 @@ const provider: AdTextProviders = (() => {
...
@@ -9,8 +10,21 @@ const provider: AdTextProviders = (() => {
return
envValue
&&
SUPPORTED_AD_BANNER_PROVIDERS
.
includes
(
envValue
)
?
envValue
as
AdTextProviders
:
'
coinzilla
'
;
return
envValue
&&
SUPPORTED_AD_BANNER_PROVIDERS
.
includes
(
envValue
)
?
envValue
as
AdTextProviders
:
'
coinzilla
'
;
})();
})();
export
default
Object
.
freeze
({
const
title
=
'
Text ads
'
;
title
:
'
Text ads
'
,
isEnabled
:
provider
!==
'
none
'
,
const
config
:
Feature
<
{
provider
:
AdTextProviders
}
>
=
(()
=>
{
provider
,
if
(
provider
!==
'
none
'
)
{
});
return
Object
.
freeze
({
title
,
isEnabled
:
true
,
provider
,
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/beaconChain.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
export
default
Object
.
freeze
({
const
title
=
'
Beacon chain
'
;
title
:
'
Beacon chain
'
,
isEnabled
:
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_HAS_BEACON_CHAIN
)
===
'
true
'
,
const
config
:
Feature
<
{
currency
:
{
symbol
:
string
}
}
>
=
(()
=>
{
currency
:
{
if
(
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_HAS_BEACON_CHAIN
)
===
'
true
'
)
{
symbol
:
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL
)
||
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL
),
return
Object
.
freeze
({
},
title
,
});
isEnabled
:
true
,
currency
:
{
symbol
:
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL
)
||
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL
)
||
''
,
// maybe we need some other default value here
},
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/blockchainInteraction.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
chain
from
'
../chain
'
;
import
chain
from
'
../chain
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
const
walletConnectProjectId
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID
);
const
walletConnectProjectId
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID
);
export
default
Object
.
freeze
({
const
title
=
'
Blockchain interaction (writing to contract, etc.)
'
;
title
:
'
Blockchain interaction (writing to contract, etc.)
'
,
isEnabled
:
Boolean
(
const
config
:
Feature
<
{
walletConnect
:
{
projectId
:
string
}
}
>
=
(()
=>
{
if
(
// all chain parameters are required for wagmi provider
// all chain parameters are required for wagmi provider
// @wagmi/chains/dist/index.d.ts
// @wagmi/chains/dist/index.d.ts
chain
.
id
&&
chain
.
id
&&
...
@@ -14,9 +18,21 @@ export default Object.freeze({
...
@@ -14,9 +18,21 @@ export default Object.freeze({
chain
.
currency
.
symbol
&&
chain
.
currency
.
symbol
&&
chain
.
currency
.
decimals
&&
chain
.
currency
.
decimals
&&
chain
.
rpcUrl
&&
chain
.
rpcUrl
&&
walletConnectProjectId
,
walletConnectProjectId
),
)
{
walletConnect
:
{
return
Object
.
freeze
({
projectId
:
walletConnectProjectId
??
''
,
title
,
},
isEnabled
:
true
,
});
walletConnect
:
{
projectId
:
walletConnectProjectId
,
},
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/csvExport.ts
View file @
0a992acd
import
{
getEnvValue
}
from
'
../util
s
'
;
import
type
{
Feature
}
from
'
./type
s
'
;
const
reCaptchaSiteKey
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY
)
;
import
services
from
'
../services
'
;
export
default
Object
.
freeze
({
const
title
=
'
Export data to CSV file
'
;
title
:
'
Export data to CSV file
'
,
isEnabled
:
Boolean
(
reCaptchaSiteKey
),
const
config
:
Feature
<
{
reCaptcha
:
{
siteKey
:
string
}}
>
=
(()
=>
{
reCaptcha
:
{
if
(
services
.
reCaptcha
.
siteKey
)
{
siteKey
:
reCaptchaSiteKey
??
''
,
return
Object
.
freeze
({
},
title
,
});
isEnabled
:
true
,
reCaptcha
:
{
siteKey
:
services
.
reCaptcha
.
siteKey
,
},
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/googleAnalytics.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
const
propertyId
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID
);
const
propertyId
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID
);
export
default
Object
.
freeze
({
const
title
=
'
Google analytics
'
;
title
:
'
Google analytics
'
,
isEnabled
:
Boolean
(
propertyId
),
const
config
:
Feature
<
{
propertyId
:
string
}
>
=
(()
=>
{
propertyId
,
if
(
propertyId
)
{
});
return
Object
.
freeze
({
title
,
isEnabled
:
true
,
propertyId
,
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/graphqlApiDocs.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
const
defaultTxHash
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_GRAPHIQL_TRANSACTION
);
const
defaultTxHash
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_GRAPHIQL_TRANSACTION
);
export
default
Object
.
freeze
({
const
title
=
'
GraphQL API documentation
'
;
title
:
'
GraphQL API documentation
'
,
isEnabled
:
true
,
const
config
:
Feature
<
{
defaultTxHash
:
string
|
undefined
}
>
=
(()
=>
{
defaultTxHash
,
return
Object
.
freeze
({
});
title
,
isEnabled
:
true
,
defaultTxHash
,
});
})();
export
default
config
;
configs/app/features/marketplace.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
chain
from
'
../chain
'
;
import
chain
from
'
../chain
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
const
configUrl
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL
);
const
configUrl
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL
);
const
submitForm
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM
);
const
submitFormUrl
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM
);
export
default
Object
.
freeze
({
const
title
=
'
Marketplace
'
;
title
:
'
Marketplace
'
,
isEnabled
:
Boolean
(
chain
.
rpcUrl
&&
configUrl
&&
submitForm
),
const
config
:
Feature
<
{
configUrl
:
string
;
submitFormUrl
:
string
}
>
=
(()
=>
{
configUrl
:
configUrl
??
''
,
if
(
submitFormUrl
:
submitForm
??
''
,
chain
.
rpcUrl
&&
});
configUrl
&&
submitFormUrl
)
{
return
Object
.
freeze
({
title
,
isEnabled
:
true
,
configUrl
,
submitFormUrl
,
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/mixpanel.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
const
projectToken
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN
);
const
projectToken
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN
);
export
default
Object
.
freeze
({
const
title
=
'
Mixpanel analytics
'
;
title
:
'
Mixpanel analytics
'
,
isEnabled
:
Boolean
(
projectToken
),
const
config
:
Feature
<
{
projectToken
:
string
}
>
=
(()
=>
{
projectToken
:
projectToken
??
''
,
if
(
projectToken
)
{
});
return
Object
.
freeze
({
title
,
isEnabled
:
true
,
projectToken
,
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/restApiDocs.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
const
specUrl
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_API_SPEC_URL
);
const
specUrl
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_API_SPEC_URL
);
export
default
Object
.
freeze
({
const
title
=
'
REST API documentation
'
;
title
:
'
REST API documentation
'
,
isEnabled
:
Boolean
(
specUrl
),
const
config
:
Feature
<
{
specUrl
:
string
}
>
=
(()
=>
{
specUrl
,
if
(
specUrl
)
{
});
return
Object
.
freeze
({
title
,
isEnabled
:
true
,
specUrl
,
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/rollup.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
export
default
Object
.
freeze
({
const
title
=
'
Rollup (L2) chain
'
;
title
:
'
Rollup (L2) chain
'
,
isEnabled
:
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_IS_L2_NETWORK
)
===
'
true
'
,
const
config
:
Feature
<
{
L1BaseUrl
:
string
;
withdrawalUrl
:
string
}
>
=
(()
=>
{
L1BaseUrl
:
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_L1_BASE_URL
)
??
''
,
const
L1BaseUrl
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_L1_BASE_URL
);
withdrawalUrl
:
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_L2_WITHDRAWAL_URL
)
??
''
,
const
withdrawalUrl
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_L2_WITHDRAWAL_URL
);
});
if
(
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_IS_L2_NETWORK
)
===
'
true
'
&&
L1BaseUrl
&&
withdrawalUrl
)
{
return
Object
.
freeze
({
title
,
isEnabled
:
true
,
L1BaseUrl
,
withdrawalUrl
,
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/sentry.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
const
dsn
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_SENTRY_DSN
);
const
dsn
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_SENTRY_DSN
);
// TODO @tom2drum check sentry setup
const
title
=
'
Sentry error monitoring
'
;
export
default
Object
.
freeze
({
title
:
'
Sentry error monitoring
'
,
const
config
:
Feature
<
{
dsn
:
string
;
environment
:
string
|
undefined
;
cspReportUrl
:
string
|
undefined
;
instance
:
string
|
undefined
}
>
=
(()
=>
{
isEnabled
:
Boolean
(
dsn
),
if
(
dsn
)
{
dsn
,
return
Object
.
freeze
({
environment
:
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_APP_ENV
)
||
getEnvValue
(
process
.
env
.
NODE_ENV
),
title
,
cspReportUrl
:
getEnvValue
(
process
.
env
.
SENTRY_CSP_REPORT_URI
),
isEnabled
:
true
,
instance
:
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_APP_INSTANCE
),
dsn
,
});
environment
:
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_APP_ENV
)
||
getEnvValue
(
process
.
env
.
NODE_ENV
),
cspReportUrl
:
getEnvValue
(
process
.
env
.
SENTRY_CSP_REPORT_URI
),
instance
:
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_APP_INSTANCE
),
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/sol2uml.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
const
apiEndpoint
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_VISUALIZE_API_HOST
);
const
apiEndpoint
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_VISUALIZE_API_HOST
);
export
default
Object
.
freeze
({
const
title
=
'
Solidity to UML diagrams
'
;
title
:
'
Solidity to UML diagrams
'
,
isEnabled
:
Boolean
(
apiEndpoint
),
const
config
:
Feature
<
{
api
:
{
endpoint
:
string
;
basePath
:
string
}
}
>
=
(()
=>
{
api
:
{
if
(
apiEndpoint
)
{
endpoint
:
apiEndpoint
,
return
Object
.
freeze
({
basePath
:
''
,
title
,
},
isEnabled
:
true
,
});
api
:
{
endpoint
:
apiEndpoint
,
basePath
:
''
,
},
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/stats.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
const
apiEndpoint
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_STATS_API_HOST
);
const
apiEndpoint
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_STATS_API_HOST
);
export
default
Object
.
freeze
({
const
title
=
'
Blockchain statistics
'
;
title
:
'
Blockchain statistics
'
,
isEnabled
:
Boolean
(
apiEndpoint
),
const
config
:
Feature
<
{
api
:
{
endpoint
:
string
;
basePath
:
string
}
}
>
=
(()
=>
{
api
:
{
if
(
apiEndpoint
)
{
endpoint
:
apiEndpoint
,
return
Object
.
freeze
({
basePath
:
''
,
title
,
},
isEnabled
:
true
,
});
api
:
{
endpoint
:
apiEndpoint
,
basePath
:
''
,
},
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/types.ts
0 → 100644
View file @
0a992acd
type
FeatureEnabled
<
Payload
extends
Record
<
string
,
unknown
>
=
Record
<
string
,
never
>>
=
{
title
:
string
;
isEnabled
:
true
}
&
Payload
;
type
FeatureDisabled
=
{
title
:
string
;
isEnabled
:
false
};
export
type
Feature
<
Payload
extends
Record
<
string
,
unknown
>
=
Record
<
string
,
never
>>
=
FeatureEnabled
<
Payload
>
|
FeatureDisabled
;
// typescript cannot properly resolve unions in nested objects - https://github.com/microsoft/TypeScript/issues/18758
// so we use this little helper where it is needed
export
const
getFeaturePayload
=
<
Payload
extends
Record
<
string
,
unknown
>>
(
feature
:
Feature
<
Payload
>
):
Payload
|
undefined
=>
{
return
feature
.
isEnabled
?
feature
:
undefined
;
};
configs/app/features/verifiedTokens.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
const
contractInfoApiHost
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_CONTRACT_INFO_API_HOST
);
const
contractInfoApiHost
=
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_CONTRACT_INFO_API_HOST
);
export
default
Object
.
freeze
({
const
title
=
'
Verified tokens info
'
;
title
:
'
Verified tokens info
'
,
isEnabled
:
Boolean
(
contractInfoApiHost
),
const
config
:
Feature
<
{
api
:
{
endpoint
:
string
;
basePath
:
string
}
}
>
=
(()
=>
{
api
:
{
if
(
contractInfoApiHost
)
{
endpoint
:
contractInfoApiHost
,
return
Object
.
freeze
({
basePath
:
''
,
title
,
},
isEnabled
:
true
,
});
api
:
{
endpoint
:
contractInfoApiHost
,
basePath
:
''
,
},
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/app/features/web3Wallet.ts
View file @
0a992acd
import
type
{
Feature
}
from
'
./types
'
;
import
type
{
WalletType
}
from
'
types/client/wallets
'
;
import
type
{
WalletType
}
from
'
types/client/wallets
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
import
{
getEnvValue
}
from
'
../utils
'
;
...
@@ -12,12 +13,25 @@ const defaultWallet = ((): WalletType => {
...
@@ -12,12 +13,25 @@ const defaultWallet = ((): WalletType => {
return
envValue
&&
SUPPORTED_WALLETS
.
includes
(
envValue
)
?
envValue
:
'
metamask
'
;
return
envValue
&&
SUPPORTED_WALLETS
.
includes
(
envValue
)
?
envValue
:
'
metamask
'
;
})();
})();
export
default
Object
.
freeze
({
const
title
=
'
Web3 wallet integration (add token or network to the wallet)
'
;
title
:
'
Web3 wallet integration (add token or network to the wallet)
'
,
isEnabled
:
defaultWallet
!==
'
none
'
,
const
config
:
Feature
<
{
defaultWallet
:
Exclude
<
WalletType
,
'
none
'
>
;
addToken
:
{
isDisabled
:
boolean
}}
>
=
(()
=>
{
defaultWallet
,
if
(
defaultWallet
!==
'
none
'
)
{
addToken
:
{
return
Object
.
freeze
({
isDisabled
:
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET
)
===
'
true
'
,
title
,
},
isEnabled
:
true
,
addNetwork
:
{},
defaultWallet
,
});
addToken
:
{
isDisabled
:
getEnvValue
(
process
.
env
.
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET
)
===
'
true
'
,
},
addNetwork
:
{},
});
}
return
Object
.
freeze
({
title
,
isEnabled
:
false
,
});
})();
export
default
config
;
configs/sentry/react.ts
View file @
0a992acd
...
@@ -3,59 +3,70 @@ import { BrowserTracing } from '@sentry/tracing';
...
@@ -3,59 +3,70 @@ import { BrowserTracing } from '@sentry/tracing';
import
appConfig
from
'
configs/app
'
;
import
appConfig
from
'
configs/app
'
;
export
const
config
:
Sentry
.
BrowserOptions
=
{
const
feature
=
appConfig
.
features
.
sentry
;
environment
:
appConfig
.
features
.
sentry
.
environment
,
dsn
:
appConfig
.
features
.
sentry
.
dsn
,
release
:
process
.
env
.
NEXT_PUBLIC_GIT_TAG
||
process
.
env
.
NEXT_PUBLIC_GIT_COMMIT_SHA
,
integrations
:
[
new
BrowserTracing
()
],
// We recommend adjusting this value in production, or using tracesSampler
// for finer control
tracesSampleRate
:
1.0
,
// error filtering settings
export
const
config
:
Sentry
.
BrowserOptions
|
undefined
=
(()
=>
{
// were taken from here - https://docs.sentry.io/platforms/node/guides/azure-functions/configuration/filtering/#decluttering-sentry
if
(
!
feature
.
isEnabled
)
{
ignoreErrors
:
[
return
;
// Random plugins/extensions
}
'
top.GLOBALS
'
,
// See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error.html
return
{
'
originalCreateNotification
'
,
environment
:
feature
.
environment
,
'
canvas.contentDocument
'
,
dsn
:
feature
.
dsn
,
'
MyApp_RemoveAllHighlights
'
,
release
:
process
.
env
.
NEXT_PUBLIC_GIT_TAG
||
process
.
env
.
NEXT_PUBLIC_GIT_COMMIT_SHA
,
'
http://tt.epicplay.com
'
,
integrations
:
[
new
BrowserTracing
()
],
'
Can
\'
t find variable: ZiteReader
'
,
// We recommend adjusting this value in production, or using tracesSampler
'
jigsaw is not defined
'
,
// for finer control
'
ComboSearch is not defined
'
,
tracesSampleRate
:
1.0
,
'
http://loading.retry.widdit.com/
'
,
'
atomicFindClose
'
,
// error filtering settings
// Facebook borked
// were taken from here - https://docs.sentry.io/platforms/node/guides/azure-functions/configuration/filtering/#decluttering-sentry
'
fb_xd_fragment
'
,
ignoreErrors
:
[
// ISP "optimizing" proxy - `Cache-Control: no-transform` seems to reduce this. (thanks @acdha)
// Random plugins/extensions
// See http://stackoverflow.com/questions/4113268/how-to-stop-javascript-injection-from-vodafone-proxy
'
top.GLOBALS
'
,
'
bmi_SafeAddOnload
'
,
// See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error.html
'
EBCallBackMessageReceived
'
,
'
originalCreateNotification
'
,
// See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx
'
canvas.contentDocument
'
,
'
conduitPage
'
,
'
MyApp_RemoveAllHighlights
'
,
// Generic error code from errors outside the security sandbox
'
http://tt.epicplay.com
'
,
'
Script error.
'
,
'
Can
\'
t find variable: ZiteReader
'
,
],
'
jigsaw is not defined
'
,
denyUrls
:
[
'
ComboSearch is not defined
'
,
// Facebook flakiness
'
http://loading.retry.widdit.com/
'
,
/graph
\.
facebook
\.
com/i
,
'
atomicFindClose
'
,
// Facebook blocked
// Facebook borked
/connect
\.
facebook
\.
net
\/
en_US
\/
all
\.
js/i
,
'
fb_xd_fragment
'
,
// Woopra flakiness
// ISP "optimizing" proxy - `Cache-Control: no-transform` seems to reduce this. (thanks @acdha)
/eatdifferent
\.
com
\.
woopra-ns
\.
com/i
,
// See http://stackoverflow.com/questions/4113268/how-to-stop-javascript-injection-from-vodafone-proxy
/static
\.
woopra
\.
com
\/
js
\/
woopra
\.
js/i
,
'
bmi_SafeAddOnload
'
,
// Chrome extensions
'
EBCallBackMessageReceived
'
,
/extensions
\/
/i
,
// See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx
/^chrome:
\/\/
/i
,
'
conduitPage
'
,
// Other plugins
// Generic error code from errors outside the security sandbox
/127
\.
0
\.
0
\.
1:4001
\/
isrunning/i
,
// Cacaoweb
'
Script error.
'
,
/webappstoolbarba
\.
texthelp
\.
com
\/
/i
,
],
/metrics
\.
itunes
\.
apple
\.
com
\.
edgesuite
\.
net
\/
/i
,
denyUrls
:
[
],
// Facebook flakiness
};
/graph
\.
facebook
\.
com/i
,
// Facebook blocked
/connect
\.
facebook
\.
net
\/
en_US
\/
all
\.
js/i
,
// Woopra flakiness
/eatdifferent
\.
com
\.
woopra-ns
\.
com/i
,
/static
\.
woopra
\.
com
\/
js
\/
woopra
\.
js/i
,
// Chrome extensions
/extensions
\/
/i
,
/^chrome:
\/\/
/i
,
// Other plugins
/127
\.
0
\.
0
\.
1:4001
\/
isrunning/i
,
// Cacaoweb
/webappstoolbarba
\.
texthelp
\.
com
\/
/i
,
/metrics
\.
itunes
\.
apple
\.
com
\.
edgesuite
\.
net
\/
/i
,
],
};
})();
export
function
configureScope
(
scope
:
Sentry
.
Scope
)
{
export
function
configureScope
(
scope
:
Sentry
.
Scope
)
{
scope
.
setTag
(
'
app_instance
'
,
appConfig
.
features
.
sentry
.
instance
);
if
(
!
feature
.
isEnabled
)
{
return
;
}
scope
.
setTag
(
'
app_instance
'
,
feature
.
instance
);
}
}
lib/api/resources.ts
View file @
0a992acd
import
{
getFeaturePayload
}
from
'
configs/app/features/types
'
;
import
type
{
import
type
{
UserInfo
,
UserInfo
,
CustomAbis
,
CustomAbis
,
...
@@ -111,58 +112,58 @@ export const RESOURCES = {
...
@@ -111,58 +112,58 @@ export const RESOURCES = {
address_verification
:
{
address_verification
:
{
path
:
'
/api/v1/chains/:chainId/verified-addresses:type
'
,
path
:
'
/api/v1/chains/:chainId/verified-addresses:type
'
,
pathParams
:
[
'
chainId
'
as
const
,
'
type
'
as
const
],
pathParams
:
[
'
chainId
'
as
const
,
'
type
'
as
const
],
endpoint
:
config
.
features
.
verifiedTokens
.
api
.
endpoint
,
endpoint
:
getFeaturePayload
(
config
.
features
.
verifiedTokens
)?
.
api
.
endpoint
,
basePath
:
config
.
features
.
verifiedTokens
.
api
.
basePath
,
basePath
:
getFeaturePayload
(
config
.
features
.
verifiedTokens
)?
.
api
.
basePath
,
needAuth
:
true
,
needAuth
:
true
,
},
},
verified_addresses
:
{
verified_addresses
:
{
path
:
'
/api/v1/chains/:chainId/verified-addresses
'
,
path
:
'
/api/v1/chains/:chainId/verified-addresses
'
,
pathParams
:
[
'
chainId
'
as
const
],
pathParams
:
[
'
chainId
'
as
const
],
endpoint
:
config
.
features
.
verifiedTokens
.
api
.
endpoint
,
endpoint
:
getFeaturePayload
(
config
.
features
.
verifiedTokens
)?
.
api
.
endpoint
,
basePath
:
config
.
features
.
verifiedTokens
.
api
.
basePath
,
basePath
:
getFeaturePayload
(
config
.
features
.
verifiedTokens
)?
.
api
.
basePath
,
needAuth
:
true
,
needAuth
:
true
,
},
},
token_info_applications_config
:
{
token_info_applications_config
:
{
path
:
'
/api/v1/chains/:chainId/token-info-submissions/selectors
'
,
path
:
'
/api/v1/chains/:chainId/token-info-submissions/selectors
'
,
pathParams
:
[
'
chainId
'
as
const
],
pathParams
:
[
'
chainId
'
as
const
],
endpoint
:
config
.
features
.
addressVerification
.
api
.
endpoint
,
endpoint
:
getFeaturePayload
(
config
.
features
.
addressVerification
)?
.
api
.
endpoint
,
basePath
:
config
.
features
.
addressVerification
.
api
.
basePath
,
basePath
:
getFeaturePayload
(
config
.
features
.
addressVerification
)?
.
api
.
basePath
,
needAuth
:
true
,
needAuth
:
true
,
},
},
token_info_applications
:
{
token_info_applications
:
{
path
:
'
/api/v1/chains/:chainId/token-info-submissions/:id?
'
,
path
:
'
/api/v1/chains/:chainId/token-info-submissions/:id?
'
,
pathParams
:
[
'
chainId
'
as
const
,
'
id
'
as
const
],
pathParams
:
[
'
chainId
'
as
const
,
'
id
'
as
const
],
endpoint
:
config
.
features
.
addressVerification
.
api
.
endpoint
,
endpoint
:
getFeaturePayload
(
config
.
features
.
addressVerification
)?
.
api
.
endpoint
,
basePath
:
config
.
features
.
addressVerification
.
api
.
basePath
,
basePath
:
getFeaturePayload
(
config
.
features
.
addressVerification
)?
.
api
.
basePath
,
needAuth
:
true
,
needAuth
:
true
,
},
},
// STATS
// STATS
stats_counters
:
{
stats_counters
:
{
path
:
'
/api/v1/counters
'
,
path
:
'
/api/v1/counters
'
,
endpoint
:
config
.
features
.
stats
.
api
.
endpoint
,
endpoint
:
getFeaturePayload
(
config
.
features
.
stats
)?
.
api
.
endpoint
,
basePath
:
config
.
features
.
stats
.
api
.
basePath
,
basePath
:
getFeaturePayload
(
config
.
features
.
stats
)?
.
api
.
basePath
,
},
},
stats_lines
:
{
stats_lines
:
{
path
:
'
/api/v1/lines
'
,
path
:
'
/api/v1/lines
'
,
endpoint
:
config
.
features
.
stats
.
api
.
endpoint
,
endpoint
:
getFeaturePayload
(
config
.
features
.
stats
)?
.
api
.
endpoint
,
basePath
:
config
.
features
.
stats
.
api
.
basePath
,
basePath
:
getFeaturePayload
(
config
.
features
.
stats
)?
.
api
.
basePath
,
},
},
stats_line
:
{
stats_line
:
{
path
:
'
/api/v1/lines/:id
'
,
path
:
'
/api/v1/lines/:id
'
,
pathParams
:
[
'
id
'
as
const
],
pathParams
:
[
'
id
'
as
const
],
endpoint
:
config
.
features
.
stats
.
api
.
endpoint
,
endpoint
:
getFeaturePayload
(
config
.
features
.
stats
)?
.
api
.
endpoint
,
basePath
:
config
.
features
.
stats
.
api
.
basePath
,
basePath
:
getFeaturePayload
(
config
.
features
.
stats
)?
.
api
.
basePath
,
},
},
// VISUALIZATION
// VISUALIZATION
visualize_sol2uml
:
{
visualize_sol2uml
:
{
path
:
'
/api/v1/solidity
\\
:visualize-contracts
'
,
path
:
'
/api/v1/solidity
\\
:visualize-contracts
'
,
endpoint
:
config
.
features
.
sol2uml
.
api
.
endpoint
,
endpoint
:
getFeaturePayload
(
config
.
features
.
sol2uml
)?
.
api
.
endpoint
,
basePath
:
config
.
features
.
sol2uml
.
api
.
basePath
,
basePath
:
getFeaturePayload
(
config
.
features
.
sol2uml
)?
.
api
.
basePath
,
},
},
// BLOCKS, TXS
// BLOCKS, TXS
...
@@ -345,8 +346,8 @@ export const RESOURCES = {
...
@@ -345,8 +346,8 @@ export const RESOURCES = {
token_verified_info
:
{
token_verified_info
:
{
path
:
'
/api/v1/chains/:chainId/token-infos/:hash
'
,
path
:
'
/api/v1/chains/:chainId/token-infos/:hash
'
,
pathParams
:
[
'
chainId
'
as
const
,
'
hash
'
as
const
],
pathParams
:
[
'
chainId
'
as
const
,
'
hash
'
as
const
],
endpoint
:
config
.
features
.
verifiedTokens
.
api
.
endpoint
,
endpoint
:
getFeaturePayload
(
config
.
features
.
verifiedTokens
)?
.
api
.
endpoint
,
basePath
:
config
.
features
.
verifiedTokens
.
api
.
basePath
,
basePath
:
getFeaturePayload
(
config
.
features
.
verifiedTokens
)?
.
api
.
basePath
,
},
},
token_counters
:
{
token_counters
:
{
path
:
'
/api/v2/tokens/:hash/counters
'
,
path
:
'
/api/v2/tokens/:hash/counters
'
,
...
...
lib/csp/policies/ad.ts
View file @
0a992acd
...
@@ -19,7 +19,7 @@ export function ad(): CspDev.DirectiveDescriptor {
...
@@ -19,7 +19,7 @@ export function ad(): CspDev.DirectiveDescriptor {
'
coinzillatag.com
'
,
'
coinzillatag.com
'
,
'
servedbyadbutler.com
'
,
'
servedbyadbutler.com
'
,
`'sha256-
${
Base64
.
stringify
(
sha256
(
connectAdbutler
))
}
'`
,
`'sha256-
${
Base64
.
stringify
(
sha256
(
connectAdbutler
))
}
'`
,
`'sha256-
${
Base64
.
stringify
(
sha256
(
placeAd
))
}
'`
,
`'sha256-
${
Base64
.
stringify
(
sha256
(
placeAd
??
''
))
}
'
`,
'
*
.
slise
.
xyz
'
,
'
*
.
slise
.
xyz
'
,
],
],
'
img
-
src
'
: [
'
img
-
src
'
: [
...
...
lib/csp/policies/app.ts
View file @
0a992acd
import
type
CspDev
from
'
csp-dev
'
;
import
type
CspDev
from
'
csp-dev
'
;
import
{
getFeaturePayload
}
from
'
configs/app/features/types
'
;
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
import
{
KEY_WORDS
}
from
'
../utils
'
;
import
{
KEY_WORDS
}
from
'
../utils
'
;
...
@@ -7,9 +9,8 @@ import { KEY_WORDS } from '../utils';
...
@@ -7,9 +9,8 @@ import { KEY_WORDS } from '../utils';
const
MAIN_DOMAINS
=
[
const
MAIN_DOMAINS
=
[
`*.
${
config
.
app
.
host
}
`
,
`*.
${
config
.
app
.
host
}
`
,
config
.
app
.
host
,
config
.
app
.
host
,
config
.
features
.
sol2uml
.
api
.
endpoint
,
getFeaturePayload
(
config
.
features
.
sol2uml
)?
.
api
.
endpoint
,
].
filter
(
Boolean
);
].
filter
(
Boolean
);
// eslint-disable-next-line no-restricted-properties
export
function
app
():
CspDev
.
DirectiveDescriptor
{
export
function
app
():
CspDev
.
DirectiveDescriptor
{
return
{
return
{
...
@@ -30,10 +31,10 @@ export function app(): CspDev.DirectiveDescriptor {
...
@@ -30,10 +31,10 @@ export function app(): CspDev.DirectiveDescriptor {
// APIs
// APIs
config
.
api
.
endpoint
,
config
.
api
.
endpoint
,
config
.
api
.
socket
,
config
.
api
.
socket
,
config
.
features
.
stats
.
api
.
endpoint
,
getFeaturePayload
(
config
.
features
.
stats
)?
.
api
.
endpoint
,
config
.
features
.
sol2uml
.
api
.
endpoint
,
getFeaturePayload
(
config
.
features
.
sol2uml
)?
.
api
.
endpoint
,
config
.
features
.
verifiedTokens
.
api
.
endpoint
,
getFeaturePayload
(
config
.
features
.
verifiedTokens
)?
.
api
.
endpoint
,
config
.
features
.
addressVerification
.
api
.
endpoint
,
getFeaturePayload
(
config
.
features
.
addressVerification
)?
.
api
.
endpoint
,
// chain RPC server
// chain RPC server
config
.
chain
.
rpcUrl
,
config
.
chain
.
rpcUrl
,
...
@@ -108,10 +109,17 @@ export function app(): CspDev.DirectiveDescriptor {
...
@@ -108,10 +109,17 @@ export function app(): CspDev.DirectiveDescriptor {
'
*
'
,
'
*
'
,
],
],
...(
config
.
features
.
sentry
.
isEnabled
&&
config
.
features
.
sentry
.
cspReportUrl
&&
!
config
.
app
.
isDev
?
{
...((()
=>
{
'
report-uri
'
:
[
const
sentryFeature
=
config
.
features
.
sentry
;
config
.
features
.
sentry
.
cspReportUrl
,
if
(
!
sentryFeature
.
isEnabled
||
!
sentryFeature
.
cspReportUrl
||
config
.
app
.
isDev
)
{
],
return
{};
}
:
{}),
}
return
{
'
report-uri
'
:
[
sentryFeature
.
cspReportUrl
,
],
};
})()),
};
};
}
}
lib/hooks/useConfigSentry.tsx
View file @
0a992acd
...
@@ -5,6 +5,10 @@ import { config, configureScope } from 'configs/sentry/react';
...
@@ -5,6 +5,10 @@ import { config, configureScope } from 'configs/sentry/react';
export
default
function
useConfigSentry
()
{
export
default
function
useConfigSentry
()
{
React
.
useEffect
(()
=>
{
React
.
useEffect
(()
=>
{
if
(
!
config
)
{
return
;
}
// gotta init sentry in browser
// gotta init sentry in browser
Sentry
.
init
(
config
);
Sentry
.
init
(
config
);
Sentry
.
configureScope
(
configureScope
);
Sentry
.
configureScope
(
configureScope
);
...
...
lib/hooks/useIsAccountActionAllowed.tsx
View file @
0a992acd
...
@@ -14,6 +14,10 @@ export default function useIsAccountActionAllowed() {
...
@@ -14,6 +14,10 @@ export default function useIsAccountActionAllowed() {
const
loginUrl
=
useLoginUrl
();
const
loginUrl
=
useLoginUrl
();
return
React
.
useCallback
(()
=>
{
return
React
.
useCallback
(()
=>
{
if
(
!
loginUrl
)
{
return
false
;
}
if
(
!
isAuth
)
{
if
(
!
isAuth
)
{
window
.
location
.
assign
(
loginUrl
);
window
.
location
.
assign
(
loginUrl
);
return
false
;
return
false
;
...
...
lib/hooks/useLoginUrl.tsx
View file @
0a992acd
...
@@ -3,7 +3,11 @@ import { route } from 'nextjs-routes';
...
@@ -3,7 +3,11 @@ import { route } from 'nextjs-routes';
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
const
feature
=
config
.
features
.
account
;
export
default
function
useLoginUrl
()
{
export
default
function
useLoginUrl
()
{
const
router
=
useRouter
();
const
router
=
useRouter
();
return
config
.
features
.
account
.
authUrl
+
route
({
pathname
:
'
/auth/auth0
'
,
query
:
{
path
:
router
.
asPath
}
});
return
feature
.
isEnabled
?
feature
.
authUrl
+
route
({
pathname
:
'
/auth/auth0
'
,
query
:
{
path
:
router
.
asPath
}
})
:
undefined
;
}
}
lib/hooks/useRedirectForInvalidAuthToken.tsx
View file @
0a992acd
...
@@ -18,7 +18,7 @@ export default function useRedirectForInvalidAuthToken() {
...
@@ -18,7 +18,7 @@ export default function useRedirectForInvalidAuthToken() {
if
(
errorStatus
===
401
)
{
if
(
errorStatus
===
401
)
{
const
apiToken
=
cookies
.
get
(
cookies
.
NAMES
.
API_TOKEN
);
const
apiToken
=
cookies
.
get
(
cookies
.
NAMES
.
API_TOKEN
);
if
(
apiToken
)
{
if
(
apiToken
&&
loginUrl
)
{
Sentry
.
captureException
(
new
Error
(
'
Invalid api token
'
),
{
tags
:
{
source
:
'
invalid_api_token
'
}
});
Sentry
.
captureException
(
new
Error
(
'
Invalid api token
'
),
{
tags
:
{
source
:
'
invalid_api_token
'
}
});
window
.
location
.
assign
(
loginUrl
);
window
.
location
.
assign
(
loginUrl
);
}
}
...
...
lib/mixpanel/useInit.tsx
View file @
0a992acd
...
@@ -19,7 +19,8 @@ export default function useMixpanelInit() {
...
@@ -19,7 +19,8 @@ export default function useMixpanelInit() {
React
.
useEffect
(()
=>
{
React
.
useEffect
(()
=>
{
isGoogleAnalyticsLoaded
().
then
((
isGALoaded
)
=>
{
isGoogleAnalyticsLoaded
().
then
((
isGALoaded
)
=>
{
if
(
!
config
.
features
.
mixpanel
.
isEnabled
)
{
const
feature
=
config
.
features
.
mixpanel
;
if
(
!
feature
.
isEnabled
)
{
return
;
return
;
}
}
...
@@ -30,7 +31,7 @@ export default function useMixpanelInit() {
...
@@ -30,7 +31,7 @@ export default function useMixpanelInit() {
};
};
const
isAuth
=
Boolean
(
cookies
.
get
(
cookies
.
NAMES
.
API_TOKEN
));
const
isAuth
=
Boolean
(
cookies
.
get
(
cookies
.
NAMES
.
API_TOKEN
));
mixpanel
.
init
(
config
.
features
.
mixpanel
.
projectToken
,
mixpanelConfig
);
mixpanel
.
init
(
feature
.
projectToken
,
mixpanelConfig
);
mixpanel
.
register
({
mixpanel
.
register
({
'
Chain id
'
:
config
.
chain
.
id
,
'
Chain id
'
:
config
.
chain
.
id
,
Environment
:
config
.
app
.
isDev
?
'
Dev
'
:
'
Prod
'
,
Environment
:
config
.
app
.
isDev
?
'
Dev
'
:
'
Prod
'
,
...
...
lib/next/middlewares/account.ts
View file @
0a992acd
...
@@ -3,12 +3,12 @@ import { NextResponse } from 'next/server';
...
@@ -3,12 +3,12 @@ import { NextResponse } from 'next/server';
import
{
route
}
from
'
nextjs-routes
'
;
import
{
route
}
from
'
nextjs-routes
'
;
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
import
{
httpLogger
}
from
'
lib/api/logger
'
;
import
{
DAY
}
from
'
lib/consts
'
;
import
{
DAY
}
from
'
lib/consts
'
;
import
*
as
cookies
from
'
lib/cookies
'
;
import
*
as
cookies
from
'
lib/cookies
'
;
export
function
account
(
req
:
NextRequest
)
{
export
function
account
(
req
:
NextRequest
)
{
if
(
!
config
.
features
.
account
.
isEnabled
)
{
const
feature
=
config
.
features
.
account
;
if
(
!
feature
.
isEnabled
)
{
return
;
return
;
}
}
...
@@ -24,7 +24,7 @@ export function account(req: NextRequest) {
...
@@ -24,7 +24,7 @@ export function account(req: NextRequest) {
const
isProfileRoute
=
req
.
nextUrl
.
pathname
.
includes
(
'
/auth/profile
'
);
const
isProfileRoute
=
req
.
nextUrl
.
pathname
.
includes
(
'
/auth/profile
'
);
if
((
isAccountRoute
||
isProfileRoute
))
{
if
((
isAccountRoute
||
isProfileRoute
))
{
const
authUrl
=
config
.
features
.
account
.
authUrl
+
route
({
pathname
:
'
/auth/auth0
'
,
query
:
{
path
:
req
.
nextUrl
.
pathname
}
});
const
authUrl
=
feature
.
authUrl
+
route
({
pathname
:
'
/auth/auth0
'
,
query
:
{
path
:
req
.
nextUrl
.
pathname
}
});
return
NextResponse
.
redirect
(
authUrl
);
return
NextResponse
.
redirect
(
authUrl
);
}
}
}
}
...
@@ -33,20 +33,11 @@ export function account(req: NextRequest) {
...
@@ -33,20 +33,11 @@ export function account(req: NextRequest) {
if
(
req
.
cookies
.
get
(
cookies
.
NAMES
.
INVALID_SESSION
))
{
if
(
req
.
cookies
.
get
(
cookies
.
NAMES
.
INVALID_SESSION
))
{
// if user has both cookies, make redirect to logout
// if user has both cookies, make redirect to logout
if
(
apiTokenCookie
)
{
if
(
apiTokenCookie
)
{
// temporary solution
// TODO check app for integrity https://github.com/blockscout/frontend/issues/1028 and make typescript happy here
if
(
!
config
.
features
.
account
.
logoutUrl
)
{
httpLogger
.
logger
.
error
({
message
:
'
Logout URL is not configured
'
,
});
return
;
}
// yes, we could have checked that the current URL is not the logout URL, but we hadn't
// yes, we could have checked that the current URL is not the logout URL, but we hadn't
// logout URL is always external URL in auth0.com sub-domain
// logout URL is always external URL in auth0.com sub-domain
// at least we hope so
// at least we hope so
const
res
=
NextResponse
.
redirect
(
config
.
features
.
account
.
logoutUrl
);
const
res
=
NextResponse
.
redirect
(
feature
.
logoutUrl
);
res
.
cookies
.
delete
(
cookies
.
NAMES
.
CONFIRM_EMAIL_PAGE_VIEWED
);
// reset cookie to show email verification page again
res
.
cookies
.
delete
(
cookies
.
NAMES
.
CONFIRM_EMAIL_PAGE_VIEWED
);
// reset cookie to show email verification page again
return
res
;
return
res
;
...
...
lib/web3/useProvider.tsx
View file @
0a992acd
...
@@ -5,11 +5,13 @@ import 'wagmi/window';
...
@@ -5,11 +5,13 @@ import 'wagmi/window';
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
const
feature
=
config
.
features
.
web3Wallet
;
export
default
function
useProvider
()
{
export
default
function
useProvider
()
{
const
[
provider
,
setProvider
]
=
React
.
useState
<
WindowProvider
>
();
const
[
provider
,
setProvider
]
=
React
.
useState
<
WindowProvider
>
();
React
.
useEffect
(()
=>
{
React
.
useEffect
(()
=>
{
if
(
!
(
'
ethereum
'
in
window
&&
window
.
ethereum
)
||
!
config
.
features
.
web3Wallet
.
isEnabled
)
{
if
(
!
(
'
ethereum
'
in
window
&&
window
.
ethereum
)
||
!
feature
.
isEnabled
)
{
return
;
return
;
}
}
...
@@ -18,11 +20,11 @@ export default function useProvider() {
...
@@ -18,11 +20,11 @@ export default function useProvider() {
const
providers
=
Array
.
isArray
(
window
.
ethereum
.
providers
)
?
window
.
ethereum
.
providers
:
[
window
.
ethereum
];
const
providers
=
Array
.
isArray
(
window
.
ethereum
.
providers
)
?
window
.
ethereum
.
providers
:
[
window
.
ethereum
];
providers
.
forEach
(
async
(
provider
)
=>
{
providers
.
forEach
(
async
(
provider
)
=>
{
if
(
config
.
features
.
web3Wallet
.
defaultWallet
===
'
coinbase
'
&&
provider
.
isCoinbaseWallet
)
{
if
(
feature
.
defaultWallet
===
'
coinbase
'
&&
provider
.
isCoinbaseWallet
)
{
return
setProvider
(
provider
);
return
setProvider
(
provider
);
}
}
if
(
config
.
features
.
web3Wallet
.
defaultWallet
===
'
metamask
'
&&
provider
.
isMetaMask
)
{
if
(
feature
.
defaultWallet
===
'
metamask
'
&&
provider
.
isMetaMask
)
{
return
setProvider
(
provider
);
return
setProvider
(
provider
);
}
}
});
});
...
...
playwright/utils/buildApiUrl.ts
View file @
0a992acd
...
@@ -6,6 +6,6 @@ import { RESOURCES } from 'lib/api/resources';
...
@@ -6,6 +6,6 @@ import { RESOURCES } from 'lib/api/resources';
export
default
function
buildApiUrl
<
R
extends
ResourceName
>
(
resourceName
:
R
,
pathParams
?:
ResourcePathParams
<
R
>
)
{
export
default
function
buildApiUrl
<
R
extends
ResourceName
>
(
resourceName
:
R
,
pathParams
?:
ResourcePathParams
<
R
>
)
{
const
resource
=
RESOURCES
[
resourceName
];
const
resource
=
RESOURCES
[
resourceName
];
const
defaultApi
=
'
https://
'
+
process
.
env
.
NEXT_PUBLIC_API_HOST
+
'
:
'
+
process
.
env
.
NEXT_PUBLIC_API_PORT
;
const
defaultApi
=
'
https://
'
+
process
.
env
.
NEXT_PUBLIC_API_HOST
+
'
:
'
+
process
.
env
.
NEXT_PUBLIC_API_PORT
;
const
origin
=
'
endpoint
'
in
resource
?
resource
.
endpoint
+
resource
.
basePath
:
defaultApi
;
const
origin
=
'
endpoint
'
in
resource
&&
resource
.
endpoint
?
resource
.
endpoint
+
(
resource
.
basePath
??
''
)
:
defaultApi
;
return
origin
+
compile
(
resource
.
path
)(
pathParams
);
return
origin
+
compile
(
resource
.
path
)(
pathParams
);
}
}
ui/apiDocs/SwaggerUI.tsx
View file @
0a992acd
...
@@ -13,6 +13,8 @@ import ContentLoader from 'ui/shared/ContentLoader';
...
@@ -13,6 +13,8 @@ import ContentLoader from 'ui/shared/ContentLoader';
import
'
swagger-ui-react/swagger-ui.css
'
;
import
'
swagger-ui-react/swagger-ui.css
'
;
const
feature
=
config
.
features
.
restApiDocs
;
const
DEFAULT_SERVER
=
'
blockscout.com/poa/core
'
;
const
DEFAULT_SERVER
=
'
blockscout.com/poa/core
'
;
const
NeverShowInfoPlugin
=
()
=>
{
const
NeverShowInfoPlugin
=
()
=>
{
...
@@ -65,10 +67,14 @@ const SwaggerUI = () => {
...
@@ -65,10 +67,14 @@ const SwaggerUI = () => {
return
req
;
return
req
;
},
[]);
},
[]);
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
return
(
return
(
<
Box
sx=
{
swaggerStyle
}
>
<
Box
sx=
{
swaggerStyle
}
>
<
SwaggerUIReact
<
SwaggerUIReact
url=
{
config
.
features
.
restApiDocs
.
specUrl
}
url=
{
feature
.
specUrl
}
plugins=
{
[
NeverShowInfoPlugin
]
}
plugins=
{
[
NeverShowInfoPlugin
]
}
requestInterceptor=
{
reqInterceptor
}
requestInterceptor=
{
reqInterceptor
}
/>
/>
...
...
ui/csvExport/CsvExportFormReCaptcha.tsx
View file @
0a992acd
...
@@ -42,7 +42,9 @@ const CsvExportFormReCaptcha = ({ formApi }: Props) => {
...
@@ -42,7 +42,9 @@ const CsvExportFormReCaptcha = ({ formApi }: Props) => {
formApi
.
setError
(
'
reCaptcha
'
,
{
type
:
'
required
'
});
formApi
.
setError
(
'
reCaptcha
'
,
{
type
:
'
required
'
});
},
[
formApi
]);
},
[
formApi
]);
if
(
!
config
.
features
.
csvExport
.
isEnabled
)
{
const
feature
=
config
.
features
.
csvExport
;
if
(
!
feature
.
isEnabled
)
{
return
(
return
(
<
Alert
status=
"error"
>
<
Alert
status=
"error"
>
CSV export is not available at the moment since reCaptcha is not configured for this application.
CSV export is not available at the moment since reCaptcha is not configured for this application.
...
@@ -55,7 +57,7 @@ const CsvExportFormReCaptcha = ({ formApi }: Props) => {
...
@@ -55,7 +57,7 @@ const CsvExportFormReCaptcha = ({ formApi }: Props) => {
<
ReCaptcha
<
ReCaptcha
className=
"recaptcha"
className=
"recaptcha"
ref=
{
ref
}
ref=
{
ref
}
sitekey=
{
config
.
features
.
csvExport
.
reCaptcha
.
siteKey
}
sitekey=
{
feature
.
reCaptcha
.
siteKey
}
onChange=
{
handleReCaptchaChange
}
onChange=
{
handleReCaptchaChange
}
onExpired=
{
handleReCaptchaExpire
}
onExpired=
{
handleReCaptchaExpire
}
/>
/>
...
...
ui/graphQL/GraphQL.tsx
View file @
0a992acd
...
@@ -8,6 +8,8 @@ import buildUrl from 'lib/api/buildUrl';
...
@@ -8,6 +8,8 @@ import buildUrl from 'lib/api/buildUrl';
import
'
graphiql/graphiql.css
'
;
import
'
graphiql/graphiql.css
'
;
import
isBrowser
from
'
lib/isBrowser
'
;
import
isBrowser
from
'
lib/isBrowser
'
;
const
feature
=
config
.
features
.
graphqlApiDocs
;
const
graphQLStyle
=
{
const
graphQLStyle
=
{
'
.graphiql-container
'
:
{
'
.graphiql-container
'
:
{
backgroundColor
:
'
unset
'
,
backgroundColor
:
'
unset
'
,
...
@@ -31,9 +33,13 @@ const GraphQL = () => {
...
@@ -31,9 +33,13 @@ const GraphQL = () => {
}
}
},
[
colorMode
]);
},
[
colorMode
]);
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
const
initialQuery
=
`{
const
initialQuery
=
`{
transaction(
transaction(
hash: "
${
config
.
features
.
graphqlApiDocs
.
defaultTxHash
}
"
hash: "
${
feature
.
defaultTxHash
}
"
) {
) {
hash
hash
blockNumber
blockNumber
...
...
ui/home/LatestDepositsItem.tsx
View file @
0a992acd
...
@@ -19,6 +19,8 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
...
@@ -19,6 +19,8 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
const
feature
=
config
.
features
.
rollup
;
type
Props
=
{
type
Props
=
{
item
:
L2DepositsItem
;
item
:
L2DepositsItem
;
isLoading
?:
boolean
;
isLoading
?:
boolean
;
...
@@ -28,9 +30,13 @@ const LatestTxsItem = ({ item, isLoading }: Props) => {
...
@@ -28,9 +30,13 @@ const LatestTxsItem = ({ item, isLoading }: Props) => {
const
timeAgo
=
dayjs
(
item
.
l1_block_timestamp
).
fromNow
();
const
timeAgo
=
dayjs
(
item
.
l1_block_timestamp
).
fromNow
();
const
isMobile
=
useIsMobile
();
const
isMobile
=
useIsMobile
();
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
const
l1BlockLink
=
(
const
l1BlockLink
=
(
<
LinkExternal
<
LinkExternal
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/block/[height_or_hash]
'
,
query
:
{
height_or_hash
:
item
.
l1_block_number
.
toString
()
}
})
route
({
pathname
:
'
/block/[height_or_hash]
'
,
query
:
{
height_or_hash
:
item
.
l1_block_number
.
toString
()
}
})
}
}
fontWeight=
{
700
}
fontWeight=
{
700
}
...
@@ -45,7 +51,7 @@ const LatestTxsItem = ({ item, isLoading }: Props) => {
...
@@ -45,7 +51,7 @@ const LatestTxsItem = ({ item, isLoading }: Props) => {
const
l1TxLink
=
(
const
l1TxLink
=
(
<
LinkExternal
<
LinkExternal
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
maxW=
"100%"
maxW=
"100%"
display=
"inline-flex"
display=
"inline-flex"
alignItems=
"center"
alignItems=
"center"
...
...
ui/l2Deposits/DepositsListItem.tsx
View file @
0a992acd
...
@@ -16,18 +16,24 @@ import LinkExternal from 'ui/shared/LinkExternal';
...
@@ -16,18 +16,24 @@ import LinkExternal from 'ui/shared/LinkExternal';
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
ListItemMobileGrid
from
'
ui/shared/ListItemMobile/ListItemMobileGrid
'
;
import
ListItemMobileGrid
from
'
ui/shared/ListItemMobile/ListItemMobileGrid
'
;
const
feature
=
config
.
features
.
rollup
;
type
Props
=
{
item
:
L2DepositsItem
;
isLoading
?:
boolean
};
type
Props
=
{
item
:
L2DepositsItem
;
isLoading
?:
boolean
};
const
DepositsListItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
DepositsListItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
timeAgo
=
dayjs
(
item
.
l1_block_timestamp
).
fromNow
();
const
timeAgo
=
dayjs
(
item
.
l1_block_timestamp
).
fromNow
();
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
return
(
return
(
<
ListItemMobileGrid
.
Container
>
<
ListItemMobileGrid
.
Container
>
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
L1 block No
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
L1 block No
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Value
py=
"3px"
>
<
ListItemMobileGrid
.
Value
py=
"3px"
>
<
LinkExternal
<
LinkExternal
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/block/[height_or_hash]
'
,
query
:
{
height_or_hash
:
item
.
l1_block_number
.
toString
()
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/block/[height_or_hash]
'
,
query
:
{
height_or_hash
:
item
.
l1_block_number
.
toString
()
}
})
}
fontWeight=
{
600
}
fontWeight=
{
600
}
display=
"flex"
display=
"flex"
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
...
@@ -63,7 +69,7 @@ const DepositsListItem = ({ item, isLoading }: Props) => {
...
@@ -63,7 +69,7 @@ const DepositsListItem = ({ item, isLoading }: Props) => {
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
L1 txn hash
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
L1 txn hash
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Value
py=
"3px"
>
<
ListItemMobileGrid
.
Value
py=
"3px"
>
<
LinkExternal
<
LinkExternal
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
maxW=
"100%"
maxW=
"100%"
display=
"flex"
display=
"flex"
overflow=
"hidden"
overflow=
"hidden"
...
@@ -79,7 +85,7 @@ const DepositsListItem = ({ item, isLoading }: Props) => {
...
@@ -79,7 +85,7 @@ const DepositsListItem = ({ item, isLoading }: Props) => {
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
L1 txn origin
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
L1 txn origin
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Value
py=
"3px"
>
<
ListItemMobileGrid
.
Value
py=
"3px"
>
<
LinkExternal
<
LinkExternal
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/address/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_origin
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/address/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_origin
}
})
}
maxW=
"100%"
maxW=
"100%"
display=
"flex"
display=
"flex"
overflow=
"hidden"
overflow=
"hidden"
...
...
ui/l2Deposits/DepositsTableItem.tsx
View file @
0a992acd
...
@@ -15,16 +15,22 @@ import HashStringShorten from 'ui/shared/HashStringShorten';
...
@@ -15,16 +15,22 @@ import HashStringShorten from 'ui/shared/HashStringShorten';
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
const
feature
=
config
.
features
.
rollup
;
type
Props
=
{
item
:
L2DepositsItem
;
isLoading
?:
boolean
};
type
Props
=
{
item
:
L2DepositsItem
;
isLoading
?:
boolean
};
const
WithdrawalsTableItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
WithdrawalsTableItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
timeAgo
=
dayjs
(
item
.
l1_block_timestamp
).
fromNow
();
const
timeAgo
=
dayjs
(
item
.
l1_block_timestamp
).
fromNow
();
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
return
(
return
(
<
Tr
>
<
Tr
>
<
Td
verticalAlign=
"middle"
fontWeight=
{
600
}
>
<
Td
verticalAlign=
"middle"
fontWeight=
{
600
}
>
<
LinkExternal
<
LinkExternal
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/block/[height_or_hash]
'
,
query
:
{
height_or_hash
:
item
.
l1_block_number
.
toString
()
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/block/[height_or_hash]
'
,
query
:
{
height_or_hash
:
item
.
l1_block_number
.
toString
()
}
})
}
fontWeight=
{
600
}
fontWeight=
{
600
}
display=
"inline-flex"
display=
"inline-flex"
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
...
@@ -56,7 +62,7 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
...
@@ -56,7 +62,7 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
</
Td
>
</
Td
>
<
Td
verticalAlign=
"middle"
>
<
Td
verticalAlign=
"middle"
>
<
LinkExternal
<
LinkExternal
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
maxW=
"100%"
maxW=
"100%"
display=
"inline-flex"
display=
"inline-flex"
overflow=
"hidden"
overflow=
"hidden"
...
@@ -70,7 +76,7 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
...
@@ -70,7 +76,7 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
</
Td
>
</
Td
>
<
Td
verticalAlign=
"middle"
>
<
Td
verticalAlign=
"middle"
>
<
LinkExternal
<
LinkExternal
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/address/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_origin
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/address/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_origin
}
})
}
maxW=
"100%"
maxW=
"100%"
display=
"inline-flex"
display=
"inline-flex"
overflow=
"hidden"
overflow=
"hidden"
...
...
ui/l2OutputRoots/OutputRootsListItem.tsx
View file @
0a992acd
...
@@ -14,11 +14,17 @@ import LinkExternal from 'ui/shared/LinkExternal';
...
@@ -14,11 +14,17 @@ import LinkExternal from 'ui/shared/LinkExternal';
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
ListItemMobileGrid
from
'
ui/shared/ListItemMobile/ListItemMobileGrid
'
;
import
ListItemMobileGrid
from
'
ui/shared/ListItemMobile/ListItemMobileGrid
'
;
const
feature
=
config
.
features
.
rollup
;
type
Props
=
{
item
:
L2OutputRootsItem
;
isLoading
?:
boolean
};
type
Props
=
{
item
:
L2OutputRootsItem
;
isLoading
?:
boolean
};
const
OutputRootsListItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
OutputRootsListItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
timeAgo
=
dayjs
(
item
.
l1_timestamp
).
fromNow
();
const
timeAgo
=
dayjs
(
item
.
l1_timestamp
).
fromNow
();
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
return
(
return
(
<
ListItemMobileGrid
.
Container
>
<
ListItemMobileGrid
.
Container
>
...
@@ -53,7 +59,7 @@ const OutputRootsListItem = ({ item, isLoading }: Props) => {
...
@@ -53,7 +59,7 @@ const OutputRootsListItem = ({ item, isLoading }: Props) => {
maxW=
"100%"
maxW=
"100%"
display=
"flex"
display=
"flex"
overflow=
"hidden"
overflow=
"hidden"
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
>
>
<
Icon
as=
{
txIcon
}
boxSize=
{
6
}
isLoading=
{
isLoading
}
/>
<
Icon
as=
{
txIcon
}
boxSize=
{
6
}
isLoading=
{
isLoading
}
/>
...
...
ui/l2OutputRoots/OutputRootsTableItem.tsx
View file @
0a992acd
...
@@ -14,11 +14,17 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
...
@@ -14,11 +14,17 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
const
feature
=
config
.
features
.
rollup
;
type
Props
=
{
item
:
L2OutputRootsItem
;
isLoading
?:
boolean
};
type
Props
=
{
item
:
L2OutputRootsItem
;
isLoading
?:
boolean
};
const
OutputRootsTableItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
OutputRootsTableItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
timeAgo
=
dayjs
(
item
.
l1_timestamp
).
fromNow
();
const
timeAgo
=
dayjs
(
item
.
l1_timestamp
).
fromNow
();
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
return
(
return
(
<
Tr
>
<
Tr
>
<
Td
verticalAlign=
"middle"
>
<
Td
verticalAlign=
"middle"
>
...
@@ -47,7 +53,7 @@ const OutputRootsTableItem = ({ item, isLoading }: Props) => {
...
@@ -47,7 +53,7 @@ const OutputRootsTableItem = ({ item, isLoading }: Props) => {
<
LinkExternal
<
LinkExternal
maxW=
"100%"
maxW=
"100%"
display=
"inline-flex"
display=
"inline-flex"
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
>
>
<
Icon
as=
{
txIcon
}
boxSize=
{
6
}
isLoading=
{
isLoading
}
/>
<
Icon
as=
{
txIcon
}
boxSize=
{
6
}
isLoading=
{
isLoading
}
/>
...
...
ui/l2TxnBatches/TxnBatchesListItem.tsx
View file @
0a992acd
...
@@ -14,11 +14,17 @@ import LinkExternal from 'ui/shared/LinkExternal';
...
@@ -14,11 +14,17 @@ import LinkExternal from 'ui/shared/LinkExternal';
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
ListItemMobileGrid
from
'
ui/shared/ListItemMobile/ListItemMobileGrid
'
;
import
ListItemMobileGrid
from
'
ui/shared/ListItemMobile/ListItemMobileGrid
'
;
const
feature
=
config
.
features
.
rollup
;
type
Props
=
{
item
:
L2TxnBatchesItem
;
isLoading
?:
boolean
};
type
Props
=
{
item
:
L2TxnBatchesItem
;
isLoading
?:
boolean
};
const
TxnBatchesListItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
TxnBatchesListItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
timeAgo
=
dayjs
(
item
.
l1_timestamp
).
fromNow
();
const
timeAgo
=
dayjs
(
item
.
l1_timestamp
).
fromNow
();
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
return
(
return
(
<
ListItemMobileGrid
.
Container
gridTemplateColumns=
"100px auto"
>
<
ListItemMobileGrid
.
Container
gridTemplateColumns=
"100px auto"
>
...
@@ -56,7 +62,7 @@ const TxnBatchesListItem = ({ item, isLoading }: Props) => {
...
@@ -56,7 +62,7 @@ const TxnBatchesListItem = ({ item, isLoading }: Props) => {
<
LinkExternal
<
LinkExternal
fontWeight=
{
600
}
fontWeight=
{
600
}
display=
"inline-flex"
display=
"inline-flex"
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/block/[height_or_hash]
'
,
query
:
{
height_or_hash
:
item
.
epoch_number
.
toString
()
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/block/[height_or_hash]
'
,
query
:
{
height_or_hash
:
item
.
epoch_number
.
toString
()
}
})
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
>
>
<
Skeleton
isLoaded=
{
!
isLoading
}
>
<
Skeleton
isLoaded=
{
!
isLoading
}
>
...
@@ -72,7 +78,7 @@ const TxnBatchesListItem = ({ item, isLoading }: Props) => {
...
@@ -72,7 +78,7 @@ const TxnBatchesListItem = ({ item, isLoading }: Props) => {
<
LinkExternal
<
LinkExternal
maxW=
"100%"
maxW=
"100%"
display=
"inline-flex"
display=
"inline-flex"
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
hash
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
hash
}
})
}
key=
{
hash
}
key=
{
hash
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
>
>
...
...
ui/l2TxnBatches/TxnBatchesTableItem.tsx
View file @
0a992acd
...
@@ -13,11 +13,17 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
...
@@ -13,11 +13,17 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
const
feature
=
config
.
features
.
rollup
;
type
Props
=
{
item
:
L2TxnBatchesItem
;
isLoading
?:
boolean
};
type
Props
=
{
item
:
L2TxnBatchesItem
;
isLoading
?:
boolean
};
const
TxnBatchesTableItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
TxnBatchesTableItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
timeAgo
=
dayjs
(
item
.
l1_timestamp
).
fromNow
();
const
timeAgo
=
dayjs
(
item
.
l1_timestamp
).
fromNow
();
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
return
(
return
(
<
Tr
>
<
Tr
>
<
Td
>
<
Td
>
...
@@ -47,7 +53,7 @@ const TxnBatchesTableItem = ({ item, isLoading }: Props) => {
...
@@ -47,7 +53,7 @@ const TxnBatchesTableItem = ({ item, isLoading }: Props) => {
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
LinkExternal
<
LinkExternal
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/block/[height_or_hash]
'
,
query
:
{
height_or_hash
:
item
.
epoch_number
.
toString
()
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/block/[height_or_hash]
'
,
query
:
{
height_or_hash
:
item
.
epoch_number
.
toString
()
}
})
}
fontWeight=
{
600
}
fontWeight=
{
600
}
display=
"inline-flex"
display=
"inline-flex"
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
...
@@ -65,7 +71,7 @@ const TxnBatchesTableItem = ({ item, isLoading }: Props) => {
...
@@ -65,7 +71,7 @@ const TxnBatchesTableItem = ({ item, isLoading }: Props) => {
maxW=
"100%"
maxW=
"100%"
display=
"inline-flex"
display=
"inline-flex"
key=
{
hash
}
key=
{
hash
}
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
hash
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
hash
}
})
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
>
>
<
Icon
as=
{
txIcon
}
boxSize=
{
6
}
isLoading=
{
isLoading
}
/>
<
Icon
as=
{
txIcon
}
boxSize=
{
6
}
isLoading=
{
isLoading
}
/>
...
...
ui/l2Withdrawals/WithdrawalsListItem.tsx
View file @
0a992acd
...
@@ -16,12 +16,18 @@ import LinkExternal from 'ui/shared/LinkExternal';
...
@@ -16,12 +16,18 @@ import LinkExternal from 'ui/shared/LinkExternal';
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
ListItemMobileGrid
from
'
ui/shared/ListItemMobile/ListItemMobileGrid
'
;
import
ListItemMobileGrid
from
'
ui/shared/ListItemMobile/ListItemMobileGrid
'
;
const
feature
=
config
.
features
.
rollup
;
type
Props
=
{
item
:
L2WithdrawalsItem
;
isLoading
?:
boolean
};
type
Props
=
{
item
:
L2WithdrawalsItem
;
isLoading
?:
boolean
};
const
WithdrawalsListItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
WithdrawalsListItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
timeAgo
=
item
.
l2_timestamp
?
dayjs
(
item
.
l2_timestamp
).
fromNow
()
:
null
;
const
timeAgo
=
item
.
l2_timestamp
?
dayjs
(
item
.
l2_timestamp
).
fromNow
()
:
null
;
const
timeToEnd
=
item
.
challenge_period_end
?
dayjs
(
item
.
challenge_period_end
).
fromNow
(
true
)
+
'
left
'
:
null
;
const
timeToEnd
=
item
.
challenge_period_end
?
dayjs
(
item
.
challenge_period_end
).
fromNow
(
true
)
+
'
left
'
:
null
;
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
return
(
return
(
<
ListItemMobileGrid
.
Container
>
<
ListItemMobileGrid
.
Container
>
...
@@ -75,7 +81,7 @@ const WithdrawalsListItem = ({ item, isLoading }: Props) => {
...
@@ -75,7 +81,7 @@ const WithdrawalsListItem = ({ item, isLoading }: Props) => {
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
Status
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
Status
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Value
>
<
ListItemMobileGrid
.
Value
>
{
item
.
status
===
'
Ready for relay
'
?
{
item
.
status
===
'
Ready for relay
'
?
<
LinkExternal
href=
{
config
.
features
.
rollup
.
withdrawalUrl
}
>
{
item
.
status
}
</
LinkExternal
>
:
<
LinkExternal
href=
{
feature
.
withdrawalUrl
}
>
{
item
.
status
}
</
LinkExternal
>
:
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-block"
>
{
item
.
status
}
</
Skeleton
>
}
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-block"
>
{
item
.
status
}
</
Skeleton
>
}
</
ListItemMobileGrid
.
Value
>
</
ListItemMobileGrid
.
Value
>
...
@@ -84,7 +90,7 @@ const WithdrawalsListItem = ({ item, isLoading }: Props) => {
...
@@ -84,7 +90,7 @@ const WithdrawalsListItem = ({ item, isLoading }: Props) => {
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
L1 txn hash
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
L1 txn hash
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Value
py=
"3px"
>
<
ListItemMobileGrid
.
Value
py=
"3px"
>
<
LinkExternal
<
LinkExternal
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
maxW=
"100%"
maxW=
"100%"
display=
"inline-flex"
display=
"inline-flex"
overflow=
"hidden"
overflow=
"hidden"
...
...
ui/l2Withdrawals/WithdrawalsTableItem.tsx
View file @
0a992acd
...
@@ -15,12 +15,18 @@ import HashStringShorten from 'ui/shared/HashStringShorten';
...
@@ -15,12 +15,18 @@ import HashStringShorten from 'ui/shared/HashStringShorten';
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
const
feature
=
config
.
features
.
rollup
;
type
Props
=
{
item
:
L2WithdrawalsItem
;
isLoading
?:
boolean
};
type
Props
=
{
item
:
L2WithdrawalsItem
;
isLoading
?:
boolean
};
const
WithdrawalsTableItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
WithdrawalsTableItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
timeAgo
=
item
.
l2_timestamp
?
dayjs
(
item
.
l2_timestamp
).
fromNow
()
:
'
N/A
'
;
const
timeAgo
=
item
.
l2_timestamp
?
dayjs
(
item
.
l2_timestamp
).
fromNow
()
:
'
N/A
'
;
const
timeToEnd
=
item
.
challenge_period_end
?
dayjs
(
item
.
challenge_period_end
).
fromNow
(
true
)
+
'
left
'
:
''
;
const
timeToEnd
=
item
.
challenge_period_end
?
dayjs
(
item
.
challenge_period_end
).
fromNow
(
true
)
+
'
left
'
:
''
;
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
return
(
return
(
<
Tr
>
<
Tr
>
<
Td
verticalAlign=
"middle"
fontWeight=
{
600
}
>
<
Td
verticalAlign=
"middle"
fontWeight=
{
600
}
>
...
@@ -55,14 +61,14 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
...
@@ -55,14 +61,14 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
</
Td
>
</
Td
>
<
Td
verticalAlign=
"middle"
>
<
Td
verticalAlign=
"middle"
>
{
item
.
status
===
'
Ready for relay
'
?
{
item
.
status
===
'
Ready for relay
'
?
<
LinkExternal
href=
{
config
.
features
.
rollup
.
withdrawalUrl
}
>
{
item
.
status
}
</
LinkExternal
>
:
<
LinkExternal
href=
{
feature
.
withdrawalUrl
}
>
{
item
.
status
}
</
LinkExternal
>
:
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-block"
>
{
item
.
status
}
</
Skeleton
>
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-block"
>
{
item
.
status
}
</
Skeleton
>
}
}
</
Td
>
</
Td
>
<
Td
verticalAlign=
"middle"
>
<
Td
verticalAlign=
"middle"
>
{
item
.
l1_tx_hash
?
(
{
item
.
l1_tx_hash
?
(
<
LinkExternal
<
LinkExternal
href=
{
config
.
features
.
rollup
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
href=
{
feature
.
L1BaseUrl
+
route
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
item
.
l1_tx_hash
}
})
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
display=
"inline-flex"
display=
"inline-flex"
>
>
...
...
ui/marketplace/useMarketplaceApps.tsx
View file @
0a992acd
...
@@ -9,6 +9,9 @@ import type { ResourceError } from 'lib/api/resources';
...
@@ -9,6 +9,9 @@ import type { ResourceError } from 'lib/api/resources';
import
useApiFetch
from
'
lib/hooks/useFetch
'
;
import
useApiFetch
from
'
lib/hooks/useFetch
'
;
import
{
MARKETPLACE_APP
}
from
'
stubs/marketplace
'
;
import
{
MARKETPLACE_APP
}
from
'
stubs/marketplace
'
;
const
feature
=
config
.
features
.
marketplace
;
const
configUrl
=
feature
.
isEnabled
?
feature
.
configUrl
:
''
;
function
isAppNameMatches
(
q
:
string
,
app
:
MarketplaceAppOverview
)
{
function
isAppNameMatches
(
q
:
string
,
app
:
MarketplaceAppOverview
)
{
return
app
.
title
.
toLowerCase
().
includes
(
q
.
toLowerCase
());
return
app
.
title
.
toLowerCase
().
includes
(
q
.
toLowerCase
());
}
}
...
@@ -23,11 +26,12 @@ export default function useMarketplaceApps(filter: string, selectedCategoryId: s
...
@@ -23,11 +26,12 @@ export default function useMarketplaceApps(filter: string, selectedCategoryId: s
const
apiFetch
=
useApiFetch
();
const
apiFetch
=
useApiFetch
();
const
{
isPlaceholderData
,
isError
,
error
,
data
}
=
useQuery
<
unknown
,
ResourceError
<
unknown
>
,
Array
<
MarketplaceAppOverview
>>
(
const
{
isPlaceholderData
,
isError
,
error
,
data
}
=
useQuery
<
unknown
,
ResourceError
<
unknown
>
,
Array
<
MarketplaceAppOverview
>>
(
[
'
marketplace-apps
'
],
[
'
marketplace-apps
'
],
async
()
=>
apiFetch
(
config
.
features
.
marketplace
.
configUrl
||
''
),
async
()
=>
apiFetch
(
config
Url
),
{
{
select
:
(
data
)
=>
(
data
as
Array
<
MarketplaceAppOverview
>
).
sort
((
a
,
b
)
=>
a
.
title
.
localeCompare
(
b
.
title
)),
select
:
(
data
)
=>
(
data
as
Array
<
MarketplaceAppOverview
>
).
sort
((
a
,
b
)
=>
a
.
title
.
localeCompare
(
b
.
title
)),
placeholderData
:
Array
(
9
).
fill
(
MARKETPLACE_APP
),
placeholderData
:
Array
(
9
).
fill
(
MARKETPLACE_APP
),
staleTime
:
Infinity
,
staleTime
:
Infinity
,
enabled
:
feature
.
isEnabled
,
});
});
const
displayedApps
=
React
.
useMemo
(()
=>
{
const
displayedApps
=
React
.
useMemo
(()
=>
{
...
...
ui/pages/Marketplace.tsx
View file @
0a992acd
...
@@ -9,6 +9,7 @@ import MarketplaceList from 'ui/marketplace/MarketplaceList';
...
@@ -9,6 +9,7 @@ import MarketplaceList from 'ui/marketplace/MarketplaceList';
import
FilterInput
from
'
ui/shared/filters/FilterInput
'
;
import
FilterInput
from
'
ui/shared/filters/FilterInput
'
;
import
useMarketplace
from
'
../marketplace/useMarketplace
'
;
import
useMarketplace
from
'
../marketplace/useMarketplace
'
;
const
feature
=
config
.
features
.
marketplace
;
const
Marketplace
=
()
=>
{
const
Marketplace
=
()
=>
{
const
{
const
{
...
@@ -32,6 +33,10 @@ const Marketplace = () => {
...
@@ -32,6 +33,10 @@ const Marketplace = () => {
throw
new
Error
(
'
Unable to get apps list
'
,
{
cause
:
error
});
throw
new
Error
(
'
Unable to get apps list
'
,
{
cause
:
error
});
}
}
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
const
selectedApp
=
displayedApps
.
find
(
app
=>
app
.
id
===
selectedAppId
);
const
selectedApp
=
displayedApps
.
find
(
app
=>
app
.
id
===
selectedAppId
);
return
(
return
(
...
@@ -74,30 +79,28 @@ const Marketplace = () => {
...
@@ -74,30 +79,28 @@ const Marketplace = () => {
/>
/>
)
}
)
}
{
config
.
features
.
marketplace
.
isEnabled
&&
(
<
Skeleton
<
Skeleton
isLoaded=
{
!
isPlaceholderData
}
isLoaded=
{
!
isPlaceholderData
}
marginTop=
{
{
base
:
8
,
sm
:
16
}
}
marginTop=
{
{
base
:
8
,
sm
:
16
}
}
display=
"inline-block"
display=
"inline-block"
>
<
Link
fontWeight=
"bold"
display=
"inline-flex"
alignItems=
"baseline"
href=
{
feature
.
submitFormUrl
}
isExternal
>
>
<
Link
<
Icon
fontWeight=
"bold"
as=
{
PlusIcon
}
display=
"inline-flex"
w=
{
3
}
alignItems=
"baseline"
h=
{
3
}
href=
{
config
.
features
.
marketplace
.
submitFormUrl
}
mr=
{
2
}
isExternal
/>
>
<
Icon
as=
{
PlusIcon
}
w=
{
3
}
h=
{
3
}
mr=
{
2
}
/>
Submit an app
Submit an app
</
Link
>
</
Link
>
</
Skeleton
>
</
Skeleton
>
)
}
</>
</>
);
);
};
};
...
...
ui/pages/MarketplaceApp.tsx
View file @
0a992acd
...
@@ -15,6 +15,9 @@ import getQueryParamString from 'lib/router/getQueryParamString';
...
@@ -15,6 +15,9 @@ import getQueryParamString from 'lib/router/getQueryParamString';
import
ContentLoader
from
'
ui/shared/ContentLoader
'
;
import
ContentLoader
from
'
ui/shared/ContentLoader
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
const
feature
=
config
.
features
.
marketplace
;
const
configUrl
=
feature
.
isEnabled
?
feature
.
configUrl
:
''
;
const
IFRAME_SANDBOX_ATTRIBUTE
=
'
allow-forms allow-orientation-lock
'
+
const
IFRAME_SANDBOX_ATTRIBUTE
=
'
allow-forms allow-orientation-lock
'
+
'
allow-pointer-lock allow-popups-to-escape-sandbox
'
+
'
allow-pointer-lock allow-popups-to-escape-sandbox
'
+
'
allow-same-origin allow-scripts
'
+
'
allow-same-origin allow-scripts
'
+
...
@@ -33,7 +36,7 @@ const MarketplaceApp = () => {
...
@@ -33,7 +36,7 @@ const MarketplaceApp = () => {
const
{
isLoading
,
isError
,
error
,
data
}
=
useQuery
<
unknown
,
ResourceError
<
unknown
>
,
MarketplaceAppOverview
>
(
const
{
isLoading
,
isError
,
error
,
data
}
=
useQuery
<
unknown
,
ResourceError
<
unknown
>
,
MarketplaceAppOverview
>
(
[
'
marketplace-apps
'
,
id
],
[
'
marketplace-apps
'
,
id
],
async
()
=>
{
async
()
=>
{
const
result
=
await
apiFetch
<
Array
<
MarketplaceAppOverview
>
,
unknown
>
(
config
.
features
.
marketplace
.
config
Url
);
const
result
=
await
apiFetch
<
Array
<
MarketplaceAppOverview
>
,
unknown
>
(
configUrl
);
if
(
!
Array
.
isArray
(
result
))
{
if
(
!
Array
.
isArray
(
result
))
{
throw
result
;
throw
result
;
}
}
...
@@ -45,6 +48,9 @@ const MarketplaceApp = () => {
...
@@ -45,6 +48,9 @@ const MarketplaceApp = () => {
return
item
;
return
item
;
},
},
{
enabled
:
feature
.
isEnabled
,
},
);
);
const
[
isFrameLoading
,
setIsFrameLoading
]
=
useState
(
isLoading
);
const
[
isFrameLoading
,
setIsFrameLoading
]
=
useState
(
isLoading
);
...
...
ui/pages/Withdrawals.tsx
View file @
0a992acd
...
@@ -16,6 +16,8 @@ import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
...
@@ -16,6 +16,8 @@ import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import
WithdrawalsListItem
from
'
ui/withdrawals/WithdrawalsListItem
'
;
import
WithdrawalsListItem
from
'
ui/withdrawals/WithdrawalsListItem
'
;
import
WithdrawalsTable
from
'
ui/withdrawals/WithdrawalsTable
'
;
import
WithdrawalsTable
from
'
ui/withdrawals/WithdrawalsTable
'
;
const
feature
=
config
.
features
.
beaconChain
;
const
Withdrawals
=
()
=>
{
const
Withdrawals
=
()
=>
{
const
isMobile
=
useIsMobile
();
const
isMobile
=
useIsMobile
();
...
@@ -61,7 +63,7 @@ const Withdrawals = () => {
...
@@ -61,7 +63,7 @@ const Withdrawals = () => {
);
);
}
}
if
(
countersQuery
.
isError
)
{
if
(
countersQuery
.
isError
||
!
feature
.
isEnabled
)
{
return
null
;
return
null
;
}
}
...
@@ -69,7 +71,7 @@ const Withdrawals = () => {
...
@@ -69,7 +71,7 @@ const Withdrawals = () => {
return
(
return
(
<
Text
mb=
{
{
base
:
6
,
lg
:
pagination
.
isVisible
?
0
:
6
}
}
lineHeight=
{
{
base
:
'
24px
'
,
lg
:
'
32px
'
}
}
>
<
Text
mb=
{
{
base
:
6
,
lg
:
pagination
.
isVisible
?
0
:
6
}
}
lineHeight=
{
{
base
:
'
24px
'
,
lg
:
'
32px
'
}
}
>
{
BigNumber
(
countersQuery
.
data
.
withdrawal_count
).
toFormat
()
}
withdrawals processed
{
BigNumber
(
countersQuery
.
data
.
withdrawal_count
).
toFormat
()
}
withdrawals processed
and
{
valueStr
}
{
config
.
features
.
beaconChain
.
currency
.
symbol
}
withdrawn
and
{
valueStr
}
{
feature
.
currency
.
symbol
}
withdrawn
</
Text
>
</
Text
>
);
);
})();
})();
...
...
ui/shared/GoogleAnalytics.tsx
View file @
0a992acd
...
@@ -3,12 +3,14 @@ import React from 'react';
...
@@ -3,12 +3,14 @@ import React from 'react';
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
const
feature
=
config
.
features
.
googleAnalytics
;
const
GoogleAnalytics
=
()
=>
{
const
GoogleAnalytics
=
()
=>
{
if
(
!
config
.
features
.
googleAnalytics
.
isEnabled
)
{
if
(
!
feature
.
isEnabled
)
{
return
null
;
return
null
;
}
}
const
id
=
config
.
features
.
googleAnalytics
.
propertyId
;
const
id
=
feature
.
propertyId
;
return
(
return
(
<>
<>
...
...
ui/shared/NetworkAddToWallet.tsx
View file @
0a992acd
...
@@ -6,6 +6,8 @@ import useToast from 'lib/hooks/useToast';
...
@@ -6,6 +6,8 @@ import useToast from 'lib/hooks/useToast';
import
useProvider
from
'
lib/web3/useProvider
'
;
import
useProvider
from
'
lib/web3/useProvider
'
;
import
{
WALLETS_INFO
}
from
'
lib/web3/wallets
'
;
import
{
WALLETS_INFO
}
from
'
lib/web3/wallets
'
;
const
feature
=
config
.
features
.
web3Wallet
;
interface
Props
{
interface
Props
{
className
?:
string
;
className
?:
string
;
}
}
...
@@ -54,19 +56,13 @@ const NetworkAddToWallet = ({ className }: Props) => {
...
@@ -54,19 +56,13 @@ const NetworkAddToWallet = ({ className }: Props) => {
}
}
},
[
provider
,
toast
]);
},
[
provider
,
toast
]);
if
(
!
provider
||
!
config
.
chain
.
rpcUrl
)
{
if
(
!
provider
||
!
config
.
chain
.
rpcUrl
||
!
feature
.
isEnabled
)
{
return
null
;
}
const
defaultWallet
=
config
.
features
.
web3Wallet
.
defaultWallet
;
if
(
defaultWallet
===
'
none
'
)
{
return
null
;
return
null
;
}
}
return
(
return
(
<
Button
variant=
"outline"
size=
"sm"
onClick=
{
handleClick
}
className=
{
className
}
>
<
Button
variant=
"outline"
size=
"sm"
onClick=
{
handleClick
}
className=
{
className
}
>
<
Icon
as=
{
WALLETS_INFO
[
defaultWallet
].
icon
}
boxSize=
{
5
}
mr=
{
2
}
/>
<
Icon
as=
{
WALLETS_INFO
[
feature
.
defaultWallet
].
icon
}
boxSize=
{
5
}
mr=
{
2
}
/>
Add
{
config
.
chain
.
name
}
Add
{
config
.
chain
.
name
}
</
Button
>
</
Button
>
);
);
...
...
ui/shared/Web3ModalProvider.tsx
View file @
0a992acd
...
@@ -8,10 +8,12 @@ import { configureChains, createConfig, WagmiConfig } from 'wagmi';
...
@@ -8,10 +8,12 @@ import { configureChains, createConfig, WagmiConfig } from 'wagmi';
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
const
feature
=
config
.
features
.
blockchainInteraction
;
const
getConfig
=
()
=>
{
const
getConfig
=
()
=>
{
try
{
try
{
if
(
!
config
.
features
.
blockchainInteraction
.
walletConnect
.
projectI
d
)
{
if
(
!
feature
.
isEnable
d
)
{
throw
new
Error
(
'
WalletConnect Project ID is not set
'
);
throw
new
Error
();
}
}
const
currentChain
:
Chain
=
{
const
currentChain
:
Chain
=
{
...
@@ -50,7 +52,7 @@ const getConfig = () => {
...
@@ -50,7 +52,7 @@ const getConfig = () => {
]);
]);
const
wagmiConfig
=
createConfig
({
const
wagmiConfig
=
createConfig
({
autoConnect
:
true
,
autoConnect
:
true
,
connectors
:
w3mConnectors
({
projectId
:
config
.
features
.
blockchainInteraction
.
walletConnect
.
projectId
,
chains
}),
connectors
:
w3mConnectors
({
projectId
:
feature
.
walletConnect
.
projectId
,
chains
}),
publicClient
,
publicClient
,
});
});
const
ethereumClient
=
new
EthereumClient
(
wagmiConfig
,
chains
);
const
ethereumClient
=
new
EthereumClient
(
wagmiConfig
,
chains
);
...
@@ -72,7 +74,7 @@ const Web3ModalProvider = ({ children, fallback }: Props) => {
...
@@ -72,7 +74,7 @@ const Web3ModalProvider = ({ children, fallback }: Props) => {
const
modalZIndex
=
useToken
<
string
>
(
'
zIndices
'
,
'
modal
'
);
const
modalZIndex
=
useToken
<
string
>
(
'
zIndices
'
,
'
modal
'
);
const
web3ModalTheme
=
useColorModeValue
(
'
light
'
,
'
dark
'
);
const
web3ModalTheme
=
useColorModeValue
(
'
light
'
,
'
dark
'
);
if
(
!
wagmiConfig
||
!
ethereumClient
||
!
config
.
features
.
blockchainInteraction
.
isEnabled
)
{
if
(
!
wagmiConfig
||
!
ethereumClient
||
!
feature
.
isEnabled
)
{
return
typeof
fallback
===
'
function
'
?
fallback
()
:
(
fallback
||
null
);
return
typeof
fallback
===
'
function
'
?
fallback
()
:
(
fallback
||
null
);
}
}
...
@@ -82,7 +84,7 @@ const Web3ModalProvider = ({ children, fallback }: Props) => {
...
@@ -82,7 +84,7 @@ const Web3ModalProvider = ({ children, fallback }: Props) => {
{
children
}
{
children
}
</
WagmiConfig
>
</
WagmiConfig
>
<
Web3Modal
<
Web3Modal
projectId=
{
config
.
features
.
blockchainInteraction
.
walletConnect
.
projectId
}
projectId=
{
feature
.
walletConnect
.
projectId
}
ethereumClient=
{
ethereumClient
}
ethereumClient=
{
ethereumClient
}
themeMode=
{
web3ModalTheme
}
themeMode=
{
web3ModalTheme
}
themeVariables=
{
{
themeVariables=
{
{
...
...
ui/shared/ad/AdBanner.tsx
View file @
0a992acd
...
@@ -9,15 +9,17 @@ import AdbutlerBanner from './AdbutlerBanner';
...
@@ -9,15 +9,17 @@ import AdbutlerBanner from './AdbutlerBanner';
import
CoinzillaBanner
from
'
./CoinzillaBanner
'
;
import
CoinzillaBanner
from
'
./CoinzillaBanner
'
;
import
SliseBanner
from
'
./SliseBanner
'
;
import
SliseBanner
from
'
./SliseBanner
'
;
const
feature
=
config
.
features
.
adsBanner
;
const
AdBanner
=
({
className
,
isLoading
}:
{
className
?:
string
;
isLoading
?:
boolean
})
=>
{
const
AdBanner
=
({
className
,
isLoading
}:
{
className
?:
string
;
isLoading
?:
boolean
})
=>
{
const
hasAdblockCookie
=
cookies
.
get
(
cookies
.
NAMES
.
ADBLOCK_DETECTED
,
useAppContext
().
cookies
);
const
hasAdblockCookie
=
cookies
.
get
(
cookies
.
NAMES
.
ADBLOCK_DETECTED
,
useAppContext
().
cookies
);
if
(
!
config
.
features
.
adsBanner
.
isEnabled
||
hasAdblockCookie
)
{
if
(
!
feature
.
isEnabled
||
hasAdblockCookie
)
{
return
null
;
return
null
;
}
}
const
content
=
(()
=>
{
const
content
=
(()
=>
{
switch
(
config
.
features
.
adsBanner
.
provider
)
{
switch
(
feature
.
provider
)
{
case
'
adbutler
'
:
case
'
adbutler
'
:
return
<
AdbutlerBanner
/>;
return
<
AdbutlerBanner
/>;
case
'
coinzilla
'
:
case
'
coinzilla
'
:
...
@@ -32,7 +34,7 @@ const AdBanner = ({ className, isLoading }: { className?: string; isLoading?: bo
...
@@ -32,7 +34,7 @@ const AdBanner = ({ className, isLoading }: { className?: string; isLoading?: bo
className=
{
className
}
className=
{
className
}
isLoaded=
{
!
isLoading
}
isLoaded=
{
!
isLoading
}
borderRadius=
"none"
borderRadius=
"none"
maxW=
{
config
.
features
.
adsBanner
.
provider
===
'
adbutler
'
?
config
.
features
.
adsBanner
.
adButler
.
config
.
desktop
?
.
width
:
'
728px
'
}
maxW=
{
feature
.
provider
===
'
adbutler
'
?
feature
.
adButler
.
config
.
desktop
.
width
:
'
728px
'
}
w=
"100%"
w=
"100%"
>
>
{
content
}
{
content
}
...
...
ui/shared/ad/AdbutlerBanner.tsx
View file @
0a992acd
...
@@ -8,10 +8,16 @@ import useIsMobile from 'lib/hooks/useIsMobile';
...
@@ -8,10 +8,16 @@ import useIsMobile from 'lib/hooks/useIsMobile';
import
isBrowser
from
'
lib/isBrowser
'
;
import
isBrowser
from
'
lib/isBrowser
'
;
import
{
connectAdbutler
,
placeAd
,
ADBUTLER_ACCOUNT
}
from
'
ui/shared/ad/adbutlerScript
'
;
import
{
connectAdbutler
,
placeAd
,
ADBUTLER_ACCOUNT
}
from
'
ui/shared/ad/adbutlerScript
'
;
const
feature
=
config
.
features
.
adsBanner
;
const
AdbutlerBanner
=
({
className
}:
{
className
?:
string
})
=>
{
const
AdbutlerBanner
=
({
className
}:
{
className
?:
string
})
=>
{
const
router
=
useRouter
();
const
router
=
useRouter
();
const
isMobile
=
useIsMobile
();
const
isMobile
=
useIsMobile
();
React
.
useEffect
(()
=>
{
React
.
useEffect
(()
=>
{
if
(
!
feature
.
isEnabled
||
feature
.
provider
!==
'
adbutler
'
)
{
return
;
}
if
(
isBrowser
()
&&
window
.
AdButler
)
{
if
(
isBrowser
()
&&
window
.
AdButler
)
{
const
abkw
=
window
.
abkw
||
''
;
const
abkw
=
window
.
abkw
||
''
;
if
(
!
window
.
AdButler
.
ads
)
{
if
(
!
window
.
AdButler
.
ads
)
{
...
@@ -19,8 +25,8 @@ const AdbutlerBanner = ({ className }: { className?: string }) => {
...
@@ -19,8 +25,8 @@ const AdbutlerBanner = ({ className }: { className?: string }) => {
}
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore:
// @ts-ignore:
let
plc
=
window
[
`plc
${
config
.
features
.
adsBanner
.
adButler
.
config
.
mobile
?
.
id
}
`] || 0;
let
plc
=
window
[
`plc
${
feature
.
adButler
.
config
.
mobile
.
id
}
`
]
||
0
;
const adButlerConfig = isMobile ?
config.features.adsBanner.adButler.config.mobile : config.features.adsBanner
.adButler.config.desktop;
const
adButlerConfig
=
isMobile
?
feature
.
adButler
.
config
.
mobile
:
feature
.
adButler
.
config
.
desktop
;
const
banner
=
document
.
getElementById
(
'
ad-banner
'
);
const
banner
=
document
.
getElementById
(
'
ad-banner
'
);
if
(
banner
)
{
if
(
banner
)
{
banner
.
innerHTML
=
'
<
'
+
'
div id="placement_
'
+
adButlerConfig
?.
id
+
'
_
'
+
plc
+
'
"></
'
+
'
div>
'
;
banner
.
innerHTML
=
'
<
'
+
'
div id="placement_
'
+
adButlerConfig
?.
id
+
'
_
'
+
plc
+
'
"></
'
+
'
div>
'
;
...
@@ -30,9 +36,9 @@ const AdbutlerBanner = ({ className }: { className?: string }) => {
...
@@ -30,9 +36,9 @@ const AdbutlerBanner = ({ className }: { className?: string }) => {
window
.
AdButler
.
ads
.
push
({
handler
:
function
(
opt
)
{
window
.
AdButler
.
ads
.
push
({
handler
:
function
(
opt
)
{
window
.
AdButler
.
register
(
window
.
AdButler
.
register
(
ADBUTLER_ACCOUNT
,
ADBUTLER_ACCOUNT
,
adButlerConfig
?
.id,
adButlerConfig
.
id
,
[ adButlerConfig
?.width, adButlerConfig?
.height ],
[
adButlerConfig
.
width
,
adButlerConfig
.
height
],
`
placement_$
{
adButlerConfig
?
.
id
}
_
` + opt.place,
`placement_
${
adButlerConfig
.
id
}
_`
+
opt
.
place
,
opt
,
opt
,
);
);
},
opt
:
{
place
:
plc
++
,
keywords
:
abkw
,
domain
:
'
servedbyadbutler.com
'
,
click
:
'
CLICK_MACRO_PLACEHOLDER
'
}
});
},
opt
:
{
place
:
plc
++
,
keywords
:
abkw
,
domain
:
'
servedbyadbutler.com
'
,
click
:
'
CLICK_MACRO_PLACEHOLDER
'
}
});
...
...
ui/shared/ad/adbutlerScript.ts
View file @
0a992acd
...
@@ -5,17 +5,25 @@ export const ADBUTLER_ACCOUNT = 182226;
...
@@ -5,17 +5,25 @@ export const ADBUTLER_ACCOUNT = 182226;
export
const
connectAdbutler
=
`if (!window.AdButler){(function(){var s = document.createElement("script"); s.async = true; s.type = "text/javascript";s.src = 'https://servedbyadbutler.com/app.js';var n = document.getElementsByTagName("script")[0]; n.parentNode.insertBefore(s, n);}());}`
;
export
const
connectAdbutler
=
`if (!window.AdButler){(function(){var s = document.createElement("script"); s.async = true; s.type = "text/javascript";s.src = 'https://servedbyadbutler.com/app.js';var n = document.getElementsByTagName("script")[0]; n.parentNode.insertBefore(s, n);}());}`
;
export
const
placeAd
=
`
export
const
placeAd
=
(()
=>
{
var AdButler = AdButler || {}; AdButler.ads = AdButler.ads || [];
const
feature
=
config
.
features
.
adsBanner
;
var abkw = window.abkw || '';
const isMobile = window.matchMedia("only screen and (max-width: 1000px)").matches;
if
(
!
feature
.
isEnabled
||
feature
.
provider
!==
'
adbutler
'
)
{
if (isMobile) {
return
;
var plc
${
config
.
features
.
adsBanner
.
adButler
.
config
.
mobile
?.
id
}
=
window
.
plc$
{
config
.
features
.
adsBanner
.
adButler
.
config
.
mobile
?.
id
}
||
0
;
document
.
getElementById
(
'
ad-banner
'
).
innerHTML
=
'
<
'
+
'
div id="placement_${ config.features.adsBanner.adButler.config.mobile?.id }_
'
+
plc$
{
config
.
features
.
adsBanner
.
adButler
.
config
.
mobile
?.
id
}
+
'
"></
'
+
'
div>
'
;
AdButler
.
ads
.
push
({
handler
:
function
(
opt
){
AdButler
.
register
(
$
{
ADBUTLER_ACCOUNT
},
$
{
config
.
features
.
adsBanner
.
adButler
.
config
.
mobile
?.
id
},
[
$
{
config
.
features
.
adsBanner
.
adButler
.
config
.
mobile
?.
width
},
$
{
config
.
features
.
adsBanner
.
adButler
.
config
.
mobile
?.
height
}],
'
placement_${ config.features.adsBanner.adButler.config.mobile?.id }_
'
+
opt
.
place
,
opt
);
},
opt
:
{
place
:
plc$
{
config
.
features
.
adsBanner
.
adButler
.
config
.
mobile
?.
id
}
++
,
keywords
:
abkw
,
domain
:
'
servedbyadbutler.com
'
,
click
:
'
CLICK_MACRO_PLACEHOLDER
'
}});
}
else
{
var
plc$
{
config
.
features
.
adsBanner
.
adButler
.
config
.
desktop
?.
id
}
=
window
.
plc$
{
config
.
features
.
adsBanner
.
adButler
.
config
.
desktop
?.
id
}
||
0
;
document
.
getElementById
(
'
ad-banner
'
).
innerHTML
=
'
<
'
+
'
div id="placement_${ config.features.adsBanner.adButler.config.desktop?.id }_
'
+
plc$
{
config
.
features
.
adsBanner
.
adButler
.
config
.
desktop
?.
id
}
+
'
"></
'
+
'
div>
'
;
AdButler
.
ads
.
push
({
handler
:
function
(
opt
){
AdButler
.
register
(
$
{
ADBUTLER_ACCOUNT
},
$
{
config
.
features
.
adsBanner
.
adButler
.
config
.
desktop
?.
id
},
[
$
{
config
.
features
.
adsBanner
.
adButler
.
config
.
desktop
?.
width
},
$
{
config
.
features
.
adsBanner
.
adButler
.
config
.
desktop
?.
height
}],
'
placement_${ config.features.adsBanner.adButler.config.desktop?.id }_
'
+
opt
.
place
,
opt
);
},
opt
:
{
place
:
plc$
{
config
.
features
.
adsBanner
.
adButler
.
config
.
desktop
?.
id
}
++
,
keywords
:
abkw
,
domain
:
'
servedbyadbutler.com
'
,
click
:
'
CLICK_MACRO_PLACEHOLDER
'
}});
}
}
`;
return
`
var AdButler = AdButler || {}; AdButler.ads = AdButler.ads || [];
var abkw = window.abkw || '';
const isMobile = window.matchMedia("only screen and (max-width: 1000px)").matches;
if (isMobile) {
var plc
${
feature
.
adButler
.
config
.
mobile
.
id
}
= window.plc
${
feature
.
adButler
.
config
.
mobile
.
id
}
|| 0;
document.getElementById('ad-banner').innerHTML = '<'+'div id="placement_
${
feature
.
adButler
.
config
.
mobile
.
id
}
_'+plc
${
feature
.
adButler
.
config
.
mobile
.
id
}
+'"></'+'div>';
AdButler.ads.push({handler: function(opt){ AdButler.register(
${
ADBUTLER_ACCOUNT
}
,
${
feature
.
adButler
.
config
.
mobile
.
id
}
, [
${
feature
.
adButler
.
config
.
mobile
.
width
}
,
${
feature
.
adButler
.
config
.
mobile
.
height
}
], 'placement_
${
feature
.
adButler
.
config
.
mobile
.
id
}
_'+opt.place, opt); }, opt: { place: plc
${
feature
.
adButler
.
config
.
mobile
.
id
}
++, keywords: abkw, domain: 'servedbyadbutler.com', click:'CLICK_MACRO_PLACEHOLDER' }});
} else {
var plc
${
feature
.
adButler
.
config
.
desktop
.
id
}
= window.plc
${
feature
.
adButler
.
config
.
desktop
.
id
}
|| 0;
document.getElementById('ad-banner').innerHTML = '<'+'div id="placement_
${
feature
.
adButler
.
config
.
desktop
.
id
}
_'+plc
${
feature
.
adButler
.
config
.
desktop
.
id
}
+'"></'+'div>';
AdButler.ads.push({handler: function(opt){ AdButler.register(
${
ADBUTLER_ACCOUNT
}
,
${
feature
.
adButler
.
config
.
desktop
.
id
}
, [
${
feature
.
adButler
.
config
.
desktop
.
width
}
,
${
feature
.
adButler
.
config
.
desktop
.
height
}
], 'placement_
${
feature
.
adButler
.
config
.
desktop
.
id
}
_'+opt.place, opt); }, opt: { place: plc
${
feature
.
adButler
.
config
.
desktop
.
id
}
++, keywords: abkw, domain: 'servedbyadbutler.com', click:'CLICK_MACRO_PLACEHOLDER' }});
}
`
;
})();
ui/shared/address/AddressAddToWallet.tsx
View file @
0a992acd
...
@@ -8,6 +8,8 @@ import useToast from 'lib/hooks/useToast';
...
@@ -8,6 +8,8 @@ import useToast from 'lib/hooks/useToast';
import
useProvider
from
'
lib/web3/useProvider
'
;
import
useProvider
from
'
lib/web3/useProvider
'
;
import
{
WALLETS_INFO
}
from
'
lib/web3/wallets
'
;
import
{
WALLETS_INFO
}
from
'
lib/web3/wallets
'
;
const
feature
=
config
.
features
.
web3Wallet
;
interface
Props
{
interface
Props
{
className
?:
string
;
className
?:
string
;
token
:
TokenInfo
;
token
:
TokenInfo
;
...
@@ -64,16 +66,14 @@ const AddressAddToWallet = ({ className, token, isLoading }: Props) => {
...
@@ -64,16 +66,14 @@ const AddressAddToWallet = ({ className, token, isLoading }: Props) => {
return
<
Skeleton
className=
{
className
}
boxSize=
{
6
}
borderRadius=
"base"
/>;
return
<
Skeleton
className=
{
className
}
boxSize=
{
6
}
borderRadius=
"base"
/>;
}
}
const
defaultWallet
=
config
.
features
.
web3Wallet
.
defaultWallet
;
if
(
!
feature
.
isEnabled
)
{
if
(
defaultWallet
===
'
none
'
)
{
return
null
;
return
null
;
}
}
return
(
return
(
<
Tooltip
label=
{
`Add token to ${ WALLETS_INFO[defaultWallet].name }`
}
>
<
Tooltip
label=
{
`Add token to ${ WALLETS_INFO[
feature.
defaultWallet].name }`
}
>
<
Box
className=
{
className
}
display=
"inline-flex"
cursor=
"pointer"
onClick=
{
handleClick
}
>
<
Box
className=
{
className
}
display=
"inline-flex"
cursor=
"pointer"
onClick=
{
handleClick
}
>
<
Icon
as=
{
WALLETS_INFO
[
defaultWallet
].
icon
}
boxSize=
{
6
}
/>
<
Icon
as=
{
WALLETS_INFO
[
feature
.
defaultWallet
].
icon
}
boxSize=
{
6
}
/>
</
Box
>
</
Box
>
</
Tooltip
>
</
Tooltip
>
);
);
...
...
ui/snippets/profileMenu/ProfileMenuContent.tsx
View file @
0a992acd
...
@@ -8,6 +8,8 @@ import useNavItems from 'lib/hooks/useNavItems';
...
@@ -8,6 +8,8 @@ import useNavItems from 'lib/hooks/useNavItems';
import
getDefaultTransitionProps
from
'
theme/utils/getDefaultTransitionProps
'
;
import
getDefaultTransitionProps
from
'
theme/utils/getDefaultTransitionProps
'
;
import
NavLink
from
'
ui/snippets/navigation/NavLink
'
;
import
NavLink
from
'
ui/snippets/navigation/NavLink
'
;
const
feature
=
config
.
features
.
account
;
type
Props
=
{
type
Props
=
{
data
?:
UserInfo
;
data
?:
UserInfo
;
};
};
...
@@ -16,6 +18,10 @@ const ProfileMenuContent = ({ data }: Props) => {
...
@@ -16,6 +18,10 @@ const ProfileMenuContent = ({ data }: Props) => {
const
{
accountNavItems
,
profileItem
}
=
useNavItems
();
const
{
accountNavItems
,
profileItem
}
=
useNavItems
();
const
primaryTextColor
=
useColorModeValue
(
'
blackAlpha.800
'
,
'
whiteAlpha.800
'
);
const
primaryTextColor
=
useColorModeValue
(
'
blackAlpha.800
'
,
'
whiteAlpha.800
'
);
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
return
(
return
(
<
Box
>
<
Box
>
{
(
data
?.
name
||
data
?.
nickname
)
&&
(
{
(
data
?.
name
||
data
?.
nickname
)
&&
(
...
@@ -46,7 +52,7 @@ const ProfileMenuContent = ({ data }: Props) => {
...
@@ -46,7 +52,7 @@ const ProfileMenuContent = ({ data }: Props) => {
</
VStack
>
</
VStack
>
</
Box
>
</
Box
>
<
Box
mt=
{
2
}
pt=
{
3
}
borderTopColor=
"divider"
borderTopWidth=
"1px"
{
...
getDefaultTransitionProps
()
}
>
<
Box
mt=
{
2
}
pt=
{
3
}
borderTopColor=
"divider"
borderTopWidth=
"1px"
{
...
getDefaultTransitionProps
()
}
>
<
Button
size=
"sm"
width=
"full"
variant=
"outline"
as=
"a"
href=
{
config
.
features
.
account
.
logoutUrl
}
>
Sign Out
</
Button
>
<
Button
size=
"sm"
width=
"full"
variant=
"outline"
as=
"a"
href=
{
feature
.
logoutUrl
}
>
Sign Out
</
Button
>
</
Box
>
</
Box
>
</
Box
>
</
Box
>
);
);
...
...
ui/snippets/profileMenu/ProfileMenuDesktop.tsx
View file @
0a992acd
...
@@ -19,7 +19,7 @@ const ProfileMenuDesktop = () => {
...
@@ -19,7 +19,7 @@ const ProfileMenuDesktop = () => {
},
[
data
,
error
?.
status
,
isLoading
]);
},
[
data
,
error
?.
status
,
isLoading
]);
const
buttonProps
:
Partial
<
ButtonProps
>
=
(()
=>
{
const
buttonProps
:
Partial
<
ButtonProps
>
=
(()
=>
{
if
(
hasMenu
)
{
if
(
hasMenu
||
!
loginUrl
)
{
return
{};
return
{};
}
}
...
...
ui/snippets/profileMenu/ProfileMenuMobile.tsx
View file @
0a992acd
...
@@ -21,7 +21,7 @@ const ProfileMenuMobile = () => {
...
@@ -21,7 +21,7 @@ const ProfileMenuMobile = () => {
},
[
data
,
error
?.
status
,
isLoading
]);
},
[
data
,
error
?.
status
,
isLoading
]);
const
buttonProps
:
Partial
<
ButtonProps
>
=
(()
=>
{
const
buttonProps
:
Partial
<
ButtonProps
>
=
(()
=>
{
if
(
hasMenu
)
{
if
(
hasMenu
||
!
loginUrl
)
{
return
{};
return
{};
}
}
...
...
ui/withdrawals/WithdrawalsListItem.tsx
View file @
0a992acd
...
@@ -16,6 +16,8 @@ import CurrencyValue from 'ui/shared/CurrencyValue';
...
@@ -16,6 +16,8 @@ import CurrencyValue from 'ui/shared/CurrencyValue';
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
ListItemMobileGrid
from
'
ui/shared/ListItemMobile/ListItemMobileGrid
'
;
import
ListItemMobileGrid
from
'
ui/shared/ListItemMobile/ListItemMobileGrid
'
;
const
feature
=
config
.
features
.
beaconChain
;
type
Props
=
({
type
Props
=
({
item
:
WithdrawalsItem
;
item
:
WithdrawalsItem
;
view
:
'
list
'
;
view
:
'
list
'
;
...
@@ -28,6 +30,10 @@ type Props = ({
...
@@ -28,6 +30,10 @@ type Props = ({
})
&
{
isLoading
?:
boolean
};
})
&
{
isLoading
?:
boolean
};
const
WithdrawalsListItem
=
({
item
,
isLoading
,
view
}:
Props
)
=>
{
const
WithdrawalsListItem
=
({
item
,
isLoading
,
view
}:
Props
)
=>
{
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
return
(
return
(
<
ListItemMobileGrid
.
Container
gridTemplateColumns=
"100px auto"
>
<
ListItemMobileGrid
.
Container
gridTemplateColumns=
"100px auto"
>
...
@@ -85,7 +91,7 @@ const WithdrawalsListItem = ({ item, isLoading, view }: Props) => {
...
@@ -85,7 +91,7 @@ const WithdrawalsListItem = ({ item, isLoading, view }: Props) => {
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
Value
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
Value
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Value
>
<
ListItemMobileGrid
.
Value
>
<
CurrencyValue
value=
{
item
.
amount
}
currency=
{
config
.
features
.
beaconChain
.
currency
.
symbol
}
isLoading=
{
isLoading
}
/>
<
CurrencyValue
value=
{
item
.
amount
}
currency=
{
feature
.
currency
.
symbol
}
isLoading=
{
isLoading
}
/>
</
ListItemMobileGrid
.
Value
>
</
ListItemMobileGrid
.
Value
>
</>
</>
)
}
)
}
...
...
ui/withdrawals/WithdrawalsTable.tsx
View file @
0a992acd
...
@@ -10,6 +10,8 @@ import { default as Thead } from 'ui/shared/TheadSticky';
...
@@ -10,6 +10,8 @@ import { default as Thead } from 'ui/shared/TheadSticky';
import
WithdrawalsTableItem
from
'
./WithdrawalsTableItem
'
;
import
WithdrawalsTableItem
from
'
./WithdrawalsTableItem
'
;
const
feature
=
config
.
features
.
beaconChain
;
type
Props
=
{
type
Props
=
{
top
:
number
;
top
:
number
;
isLoading
?:
boolean
;
isLoading
?:
boolean
;
...
@@ -25,6 +27,10 @@ import WithdrawalsTableItem from './WithdrawalsTableItem';
...
@@ -25,6 +27,10 @@ import WithdrawalsTableItem from './WithdrawalsTableItem';
});
});
const
WithdrawalsTable
=
({
items
,
isLoading
,
top
,
view
=
'
list
'
}:
Props
)
=>
{
const
WithdrawalsTable
=
({
items
,
isLoading
,
top
,
view
=
'
list
'
}:
Props
)
=>
{
if
(
!
feature
.
isEnabled
)
{
return
null
;
}
return
(
return
(
<
Table
variant=
"simple"
size=
"sm"
style=
{
{
tableLayout
:
'
auto
'
}
}
minW=
"950px"
>
<
Table
variant=
"simple"
size=
"sm"
style=
{
{
tableLayout
:
'
auto
'
}
}
minW=
"950px"
>
<
Thead
top=
{
top
}
>
<
Thead
top=
{
top
}
>
...
@@ -34,7 +40,7 @@ const WithdrawalsTable = ({ items, isLoading, top, view = 'list' }: Props) => {
...
@@ -34,7 +40,7 @@ const WithdrawalsTable = ({ items, isLoading, top, view = 'list' }: Props) => {
{
view
!==
'
block
'
&&
<
Th
w=
"25%"
>
Block
</
Th
>
}
{
view
!==
'
block
'
&&
<
Th
w=
"25%"
>
Block
</
Th
>
}
{
view
!==
'
address
'
&&
<
Th
w=
"25%"
>
To
</
Th
>
}
{
view
!==
'
address
'
&&
<
Th
w=
"25%"
>
To
</
Th
>
}
{
view
!==
'
block
'
&&
<
Th
w=
"25%"
>
Age
</
Th
>
}
{
view
!==
'
block
'
&&
<
Th
w=
"25%"
>
Age
</
Th
>
}
<
Th
w=
"25%"
>
{
`Value ${
config.features.beaconChain
.currency.symbol }`
}
</
Th
>
<
Th
w=
"25%"
>
{
`Value ${
feature
.currency.symbol }`
}
</
Th
>
</
Tr
>
</
Tr
>
</
Thead
>
</
Thead
>
<
Tbody
>
<
Tbody
>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment