Commit fb171a69 authored by Wyatt Barnes's avatar Wyatt Barnes Committed by GitHub

Merge pull request #7576 from ethereum-optimism/wyatt/ufm/mm-prod-envs-refactors

ufm-metamask prod envs and refactors
parents 8c8e4340 e1a857e5
...@@ -5,14 +5,24 @@ CI=false ...@@ -5,14 +5,24 @@ CI=false
GRAFANA_ADMIN_PWD=op GRAFANA_ADMIN_PWD=op
# Used by Test Services to query metrics. http://prometheus will use Docker's built-in DNS # Used by Test Services to query metrics. http://prometheus will use Docker's built-in DNS
PROMETHEUS_SERVER_URL="http://prometheus:9090" METRICS_READ_URL="http://prometheus:9090/api/v1/query"
# The needed credentials to access METRICS_READ_URL. Will be sent as: Authorization: Bearer username:password
METRICS_READ_USERNAME=""
METRICS_READ_PASSWORD=""
# Used by Test Services to push metrics. http://pushgateway will use Docker's built-in DNS # Used by Test Services to push metrics. http://pushgateway will use Docker's built-in DNS
PROMETHEUS_PUSHGATEWAY_URL="http://pushgateway:9091" METRICS_WRITE_URL="http://pushgateway:9091"
# Dictates how the request body is structured when pushing metrics. Should be either "grafana" or "prometheus-pushgateway"
# If true, Metamask Test Service will install Xvfb inside it's container and used that for Playwright tests. METRICS_WRITE_TOOL="prometheus-pushgateway"
# If false, Metamask you will need to specify METAMASK_DISPLAY and METAMASK_DISPLAY_VOLUME so Playwright can connect to a display # This is the source the pushed metric will be labeled as originting from. May not need this value
METAMASK_RUN_HEADLESS=true METRIC_WRITE_SOURCE=""
# The needed credentials to access METRICS_READ_URL. Will be sent as: Authorization: Bearer username:password
METRICS_WRITE_USERNAME=""
METRICS_WRITE_PASSWORD=""
# If true (or anything other than false), Xvfb will be inside the Metamask Test Service container and use it for Playwright tests.
# If false, you will need to specify METAMASK_DISPLAY and METAMASK_DISPLAY_VOLUME so Playwright can connect to a display
METAMASK_PLAYWRIGHT_RUN_HEADLESS=true
# The display used for running Playwright tests # The display used for running Playwright tests
METAMASK_DISPLAY=host.docker.internal:0 METAMASK_DISPLAY=host.docker.internal:0
...@@ -23,8 +33,8 @@ METAMASK_DISPLAY_VOLUME=/tmp/.X11-unix:/tmp/.X11-unix ...@@ -23,8 +33,8 @@ METAMASK_DISPLAY_VOLUME=/tmp/.X11-unix:/tmp/.X11-unix
# Mnemonic used to initialize Metamask, make sure there's enough ETH to run tests # Mnemonic used to initialize Metamask, make sure there's enough ETH to run tests
METAMASK_SECRET_WORDS_OR_PRIVATEKEY="test test test test test test test test test test test junk" METAMASK_SECRET_WORDS_OR_PRIVATEKEY="test test test test test test test test test test test junk"
# The initial network Metamask will be initialized with, Test Service will override with OP Goerli # The initial network Metamask will be initialized with, Test Service will override with OP Sepolia
METAMASK_NETWORK="goerli" METAMASK_NETWORK="sepolia"
# The password to unlock Metamask # The password to unlock Metamask
METAMASK_PASSWORD="T3st_P@ssw0rd!" METAMASK_PASSWORD="T3st_P@ssw0rd!"
...@@ -32,5 +42,5 @@ METAMASK_PASSWORD="T3st_P@ssw0rd!" ...@@ -32,5 +42,5 @@ METAMASK_PASSWORD="T3st_P@ssw0rd!"
# The URL of the Metamask test dApp that will be spun up automatically for testing against # The URL of the Metamask test dApp that will be spun up automatically for testing against
METAMASK_DAPP_URL="http://localhost:9011" METAMASK_DAPP_URL="http://localhost:9011"
# The OP Goerli RPC provider to be used to read/write data # The OP Sepolia RPC provider to be used to read/write data
METAMASK_OP_GOERLI_RPC_URL="" METAMASK_OP_SEPOLIA_RPC_URL=""
# Used by Test Services to perform certain actions if in CI environment # Used by Test Services to perform certain actions if in CI environment
CI=true CI=false
# This is the password used to login into Grafana dashboard as the admin user # This is the password used to login into Grafana dashboard as the admin user
GRAFANA_ADMIN_PWD=op GRAFANA_ADMIN_PWD=op
# Used by Test Services to query metrics. 172.17.0.1 is the default Docker gateway address # Used by Test Services to query metrics. http://prometheus will use Docker's built-in DNS
PROMETHEUS_SERVER_URL="http://172.17.0.1:9090" METRICS_READ_URL="http://prometheus:9090/api/v1/query"
# The needed credentials to access METRICS_READ_URL. Will be sent as: Authorization: Bearer username:password
# Used by Test Services to push metrics. 172.17.0.1 is the default Docker gateway address METRICS_READ_USERNAME=""
PROMETHEUS_PUSHGATEWAY_URL="http://172.17.0.1:9091" METRICS_READ_PASSWORD=""
# If true, Metamask Test Service will install Xvfb inside it's container and used that for Playwright tests. # Used by Test Services to push metrics. http://pushgateway will use Docker's built-in DNS
# If false, Metamask you will need to specify METAMASK_DISPLAY and METAMASK_DISPLAY_VOLUME so Playwright can connect to a display METRICS_WRITE_URL="http://pushgateway:9091"
METAMASK_RUN_HEADLESS=true # Dictates how the request body is structured when pushing metrics. Should be either "grafana" or "prometheus-pushgateway"
METRICS_WRITE_TOOL="prometheus-pushgateway"
# This is the source the pushed metric will be labeled as originting from. May not need this value
METRIC_WRITE_SOURCE=""
# The needed credentials to access METRICS_READ_URL. Will be sent as: Authorization: Bearer username:password
METRICS_WRITE_USERNAME=""
METRICS_WRITE_PASSWORD=""
# If true (or anything other than false), Xvfb will be inside the Metamask Test Service container and use it for Playwright tests.
# If false, you will need to specify METAMASK_DISPLAY and METAMASK_DISPLAY_VOLUME so Playwright can connect to a display
METAMASK_PLAYWRIGHT_RUN_HEADLESS=true
# The display used for running Playwright tests # The display used for running Playwright tests
METAMASK_DISPLAY=host.docker.internal:0 METAMASK_DISPLAY=host.docker.internal:0
...@@ -23,17 +33,14 @@ METAMASK_DISPLAY_VOLUME=/tmp/.X11-unix:/tmp/.X11-unix ...@@ -23,17 +33,14 @@ METAMASK_DISPLAY_VOLUME=/tmp/.X11-unix:/tmp/.X11-unix
# Mnemonic used to initialize Metamask, make sure there's enough ETH to run tests # Mnemonic used to initialize Metamask, make sure there's enough ETH to run tests
METAMASK_SECRET_WORDS_OR_PRIVATEKEY="test test test test test test test test test test test junk" METAMASK_SECRET_WORDS_OR_PRIVATEKEY="test test test test test test test test test test test junk"
# The initial network Metamask will be initialized with, Test Service will override with OP Goerli. # The initial network Metamask will be initialized with, Test Service will override with OP Goerli
# Will be defaulted to goerli in Github workflow file METAMASK_NETWORK="sepolia"
METAMASK_NETWORK="goerli"
# The password to unlock Metamask # The password to unlock Metamask
# Will be defaulted to T3st_P@ssw0rd! in Github workflow file
METAMASK_PASSWORD="T3st_P@ssw0rd!" METAMASK_PASSWORD="T3st_P@ssw0rd!"
# The URL of the Metamask test dApp that will be spun up automatically for testing against # The URL of the Metamask test dApp that will be spun up automatically for testing against
# Will be defaulted to http://localhost:9011 in Github workflow file
METAMASK_DAPP_URL="http://localhost:9011" METAMASK_DAPP_URL="http://localhost:9011"
# The OP Goerli RPC provider to be used to read/write data # The OP Sepolia RPC provider to be used to read/write data
METAMASK_OP_GOERLI_RPC_URL="" METAMASK_OP_SEPOLIA_RPC_URL=""
...@@ -49,14 +49,20 @@ services: ...@@ -49,14 +49,20 @@ services:
CI: ${CI} CI: ${CI}
DISPLAY: ${METAMASK_DISPLAY} DISPLAY: ${METAMASK_DISPLAY}
GRAFANA_ADMIN_PWD: ${GRAFANA_ADMIN_PWD} GRAFANA_ADMIN_PWD: ${GRAFANA_ADMIN_PWD}
PROMETHEUS_SERVER_URL: ${PROMETHEUS_SERVER_URL} METRICS_READ_URL: ${METRICS_READ_URL}
PROMETHEUS_PUSHGATEWAY_URL: ${PROMETHEUS_PUSHGATEWAY_URL} METRICS_READ_USERNAME: ${METRICS_READ_USERNAME}
METAMASK_RUN_HEADLESS: ${METAMASK_RUN_HEADLESS} METRICS_READ_PASSWORD: ${METRICS_READ_PASSWORD}
METRICS_WRITE_URL: ${METRICS_WRITE_URL}
METRICS_WRITE_TOOL: ${METRICS_WRITE_TOOL}
METRIC_WRITE_SOURCE: ${METRIC_WRITE_SOURCE}
METRICS_WRITE_USERNAME: ${METRICS_WRITE_USERNAME}
METRICS_WRITE_PASSWORD: ${METRICS_WRITE_PASSWORD}
METAMASK_PLAYWRIGHT_RUN_HEADLESS: ${METAMASK_PLAYWRIGHT_RUN_HEADLESS}
METAMASK_SECRET_WORDS_OR_PRIVATEKEY: ${METAMASK_SECRET_WORDS_OR_PRIVATEKEY} METAMASK_SECRET_WORDS_OR_PRIVATEKEY: ${METAMASK_SECRET_WORDS_OR_PRIVATEKEY}
METAMASK_NETWORK: ${METAMASK_NETWORK} METAMASK_NETWORK: ${METAMASK_NETWORK}
METAMASK_PASSWORD: ${METAMASK_PASSWORD} METAMASK_PASSWORD: ${METAMASK_PASSWORD}
METAMASK_DAPP_URL: ${METAMASK_DAPP_URL} METAMASK_DAPP_URL: ${METAMASK_DAPP_URL}
METAMASK_OP_GOERLI_RPC_URL: ${METAMASK_OP_GOERLI_RPC_URL} METAMASK_OP_SEPOLIA_RPC_URL: ${METAMASK_OP_SEPOLIA_RPC_URL}
volumes: volumes:
- ${METAMASK_DISPLAY_VOLUME:-/path/in/container/if/no/env/set} - ${METAMASK_DISPLAY_VOLUME:-/path/in/container/if/no/env/set}
restart: "no" restart: "no"
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
"editable": true, "editable": true,
"fiscalYearStartMonth": 0, "fiscalYearStartMonth": 0,
"graphTooltip": 0, "graphTooltip": 0,
"id": 1,
"links": [], "links": [],
"liveNow": false, "liveNow": false,
"panels": [ "panels": [
...@@ -122,7 +123,7 @@ ...@@ -122,7 +123,7 @@
}, },
"disableTextWrap": false, "disableTextWrap": false,
"editorMode": "builder", "editorMode": "builder",
"expr": "metamask_self_send", "expr": "metamask_self_send_metric",
"fullMetaSearch": false, "fullMetaSearch": false,
"includeNullMetadata": true, "includeNullMetadata": true,
"instant": false, "instant": false,
...@@ -194,7 +195,7 @@ ...@@ -194,7 +195,7 @@
{ {
"matcher": { "matcher": {
"id": "byName", "id": "byName",
"options": "metamask_self_send_fee_estimation_low" "options": "metamask_self_send_fee_estimation_low_metric"
}, },
"properties": [ "properties": [
{ {
...@@ -213,7 +214,7 @@ ...@@ -213,7 +214,7 @@
{ {
"matcher": { "matcher": {
"id": "byName", "id": "byName",
"options": "metamask_self_send_fee_estimation_medium" "options": "metamask_self_send_fee_estimation_medium_metric"
}, },
"properties": [ "properties": [
{ {
...@@ -232,7 +233,7 @@ ...@@ -232,7 +233,7 @@
{ {
"matcher": { "matcher": {
"id": "byName", "id": "byName",
"options": "metamask_self_send_fee_estimation_high" "options": "metamask_self_send_fee_estimation_high_metric"
}, },
"properties": [ "properties": [
{ {
...@@ -244,7 +245,7 @@ ...@@ -244,7 +245,7 @@
{ {
"matcher": { "matcher": {
"id": "byName", "id": "byName",
"options": "metamask_self_send_fee_estimation_actual" "options": "metamask_self_send_fee_estimation_actual_metric"
}, },
"properties": [ "properties": [
{ {
...@@ -294,7 +295,7 @@ ...@@ -294,7 +295,7 @@
}, },
"disableTextWrap": false, "disableTextWrap": false,
"editorMode": "builder", "editorMode": "builder",
"expr": "metamask_self_send_fee_estimation_low", "expr": "metamask_self_send_fee_estimation_low_metric",
"fullMetaSearch": false, "fullMetaSearch": false,
"includeNullMetadata": true, "includeNullMetadata": true,
"instant": false, "instant": false,
...@@ -310,7 +311,7 @@ ...@@ -310,7 +311,7 @@
}, },
"disableTextWrap": false, "disableTextWrap": false,
"editorMode": "builder", "editorMode": "builder",
"expr": "metamask_self_send_fee_estimation_medium", "expr": "metamask_self_send_fee_estimation_medium_metric",
"fullMetaSearch": false, "fullMetaSearch": false,
"hide": false, "hide": false,
"includeNullMetadata": true, "includeNullMetadata": true,
...@@ -327,7 +328,7 @@ ...@@ -327,7 +328,7 @@
}, },
"disableTextWrap": false, "disableTextWrap": false,
"editorMode": "builder", "editorMode": "builder",
"expr": "metamask_self_send_fee_estimation_high", "expr": "metamask_self_send_fee_estimation_high_metric",
"fullMetaSearch": false, "fullMetaSearch": false,
"hide": false, "hide": false,
"includeNullMetadata": true, "includeNullMetadata": true,
...@@ -344,7 +345,7 @@ ...@@ -344,7 +345,7 @@
}, },
"disableTextWrap": false, "disableTextWrap": false,
"editorMode": "builder", "editorMode": "builder",
"expr": "metamask_self_send_fee_estimation_actual", "expr": "metamask_self_send_fee_estimation_actual_metric",
"fullMetaSearch": false, "fullMetaSearch": false,
"hide": false, "hide": false,
"includeNullMetadata": true, "includeNullMetadata": true,
...@@ -367,7 +368,7 @@ ...@@ -367,7 +368,7 @@
"list": [] "list": []
}, },
"time": { "time": {
"from": "now-3h", "from": "now-12h",
"to": "now" "to": "now"
}, },
"timepicker": {}, "timepicker": {},
......
...@@ -7,7 +7,7 @@ WORKDIR /app ...@@ -7,7 +7,7 @@ WORKDIR /app
# Update PATH # Update PATH
ENV PATH /app/node_modules/.bin:$PATH ENV PATH /app/node_modules/.bin:$PATH
RUN if [ "$METAMASK_RUN_HEADLESS" = "true" ]; then \ RUN if [ "$METAMASK_RUN_HEADLESS" != "false" ]; then \
apt-get update && \ apt-get update && \
apt-get install -y xvfb && \ apt-get install -y xvfb && \
rm -rf /var/lib/apt/lists/* ; \ rm -rf /var/lib/apt/lists/* ; \
......
...@@ -17,10 +17,16 @@ jobs: ...@@ -17,10 +17,16 @@ jobs:
run: docker-compose run metamask run: docker-compose run metamask
env: env:
CI: ${{ secrets.CI }} CI: ${{ secrets.CI }}
PROMETHEUS_SERVER_URL: ${{ secrets.PROMETHEUS_SERVER_URL }} METRICS_READ_URL: ${{ secrets.METRICS_READ_URL }}
PROMETHEUS_PUSHGATEWAY_URL: ${{ secrets.PROMETHEUS_PUSHGATEWAY_URL }} METRICS_READ_USERNAME: ${{ secrets.METRICS_READ_USERNAME }}
METRICS_READ_PASSWORD: ${{ secrets.METRICS_READ_PASSWORD }}
METRICS_WRITE_URL: ${{ secrets.METRICS_WRITE_URL }}
METRICS_WRITE_TOOL: ${{ secrets.METRICS_WRITE_TOOL }}
METRIC_WRITE_SOURCE: ${{ secrets.METRIC_WRITE_SOURCE }}
METRICS_WRITE_USERNAME: ${{ secrets.METRICS_WRITE_USERNAME }}
METRICS_WRITE_PASSWORD: ${{ secrets.METRICS_WRITE_PASSWORD }}
METAMASK_SECRET_WORDS_OR_PRIVATEKEY: ${{ secrets.METAMASK_SECRET_WORDS_OR_PRIVATEKEY }} METAMASK_SECRET_WORDS_OR_PRIVATEKEY: ${{ secrets.METAMASK_SECRET_WORDS_OR_PRIVATEKEY }}
METAMASK_NETWORK: ${{ secrets.METAMASK_NETWORK || 'goerli' }} METAMASK_NETWORK: ${{ secrets.METAMASK_NETWORK || 'sepolia' }}
METAMASK_PASSWORD: ${{ secrets.METAMASK_PASSWORD || 'T3st_P@ssw0rd!' }} METAMASK_PASSWORD: ${{ secrets.METAMASK_PASSWORD || 'T3st_P@ssw0rd!' }}
METAMASK_DAPP_URL: ${{ secrets.METAMASK_DAPP_URL || 'http://localhost:9011' }} METAMASK_DAPP_URL: ${{ secrets.METAMASK_DAPP_URL || 'http://localhost:9011' }}
METAMASK_OP_GOERLI_RPC_URL: ${{ secrets.METAMASK_OP_GOERLI_RPC_URL }} METAMASK_OP_SEPOLIA_RPC_URL: ${{ secrets.METAMASK_OP_SEPOLIA_RPC_URL }}
...@@ -16,7 +16,7 @@ import { ...@@ -16,7 +16,7 @@ import {
const env = z const env = z
.object({ .object({
METAMASK_SECRET_WORDS_OR_PRIVATEKEY: z.string(), METAMASK_SECRET_WORDS_OR_PRIVATEKEY: z.string(),
METAMASK_OP_GOERLI_RPC_URL: z.string().url(), METAMASK_OP_SEPOLIA_RPC_URL: z.string().url(),
METAMASK_DAPP_URL: z.string().url(), METAMASK_DAPP_URL: z.string().url(),
}) })
.parse(process.env) .parse(process.env)
...@@ -30,6 +30,8 @@ const expectedSender = env.METAMASK_SECRET_WORDS_OR_PRIVATEKEY?.startsWith('0x') ...@@ -30,6 +30,8 @@ const expectedSender = env.METAMASK_SECRET_WORDS_OR_PRIVATEKEY?.startsWith('0x')
).address.toLowerCase() ).address.toLowerCase()
const expectedRecipient = expectedSender const expectedRecipient = expectedSender
const expectedCurrencySymbol = 'OPS'
let sharedPage: Page let sharedPage: Page
let wasSuccessful: boolean let wasSuccessful: boolean
let handledFailure: boolean let handledFailure: boolean
...@@ -55,27 +57,26 @@ testWithSynpress('Setup wallet and dApp', async ({ page }) => { ...@@ -55,27 +57,26 @@ testWithSynpress('Setup wallet and dApp', async ({ page }) => {
console.log('Setting up wallet and dApp...') console.log('Setting up wallet and dApp...')
sharedPage = page sharedPage = page
await sharedPage.goto('http://localhost:9011') await sharedPage.goto('http://localhost:9011')
console.log('Setup wallet and dApp')
}) })
testWithSynpress('Add OP Goerli network', async () => { testWithSynpress('Add OP Sepolia network', async () => {
console.log('Adding OP Goerli network...') console.log('Adding OP Sepolia network...')
const expectedChainId = '0x1a4' const expectedChainId = '0xaa37dc'
await metamask.addNetwork({ await metamask.addNetwork({
name: 'op-goerli', name: 'op-sepolia',
rpcUrls: { rpcUrls: {
default: { default: {
http: [env.METAMASK_OP_GOERLI_RPC_URL], http: [env.METAMASK_OP_SEPOLIA_RPC_URL],
}, },
}, },
id: '420', id: '11155420',
nativeCurrency: { nativeCurrency: {
symbol: 'OPG', symbol: expectedCurrencySymbol,
}, },
blockExplorers: { blockExplorers: {
default: { default: {
url: 'https://goerli-explorer.optimism.io', url: 'https://optimism-sepolia.blockscout.com',
}, },
}, },
}) })
...@@ -87,7 +88,6 @@ testWithSynpress('Add OP Goerli network', async () => { ...@@ -87,7 +88,6 @@ testWithSynpress('Add OP Goerli network', async () => {
handledFailure = true handledFailure = true
throw error throw error
} }
console.log('Added OP Goerli network')
}) })
test(`Connect wallet with ${expectedSender}`, async () => { test(`Connect wallet with ${expectedSender}`, async () => {
...@@ -102,7 +102,6 @@ test(`Connect wallet with ${expectedSender}`, async () => { ...@@ -102,7 +102,6 @@ test(`Connect wallet with ${expectedSender}`, async () => {
handledFailure = true handledFailure = true
throw error throw error
} }
console.log(`Connected wallet with ${expectedSender}`)
}) })
test('Send an EIP-1559 transaction and verify success', async () => { test('Send an EIP-1559 transaction and verify success', async () => {
...@@ -127,6 +126,7 @@ test('Send an EIP-1559 transaction and verify success', async () => { ...@@ -127,6 +126,7 @@ test('Send an EIP-1559 transaction and verify success', async () => {
const notificationPage = const notificationPage =
await synpressPlaywright.switchToMetamaskNotification() await synpressPlaywright.switchToMetamaskNotification()
console.log('Gathering transaction fee estimations...')
const lowFeeEstimate = await getFeeEstimateInGwei( const lowFeeEstimate = await getFeeEstimateInGwei(
confirmPageElements.gasOptionLowButton, confirmPageElements.gasOptionLowButton,
'Low', 'Low',
...@@ -146,6 +146,7 @@ test('Send an EIP-1559 transaction and verify success', async () => { ...@@ -146,6 +146,7 @@ test('Send an EIP-1559 transaction and verify success', async () => {
notificationPage notificationPage
) )
console.log('Sent transaction, waiting for confirmation...')
await metamask.confirmTransactionAndWaitForMining() await metamask.confirmTransactionAndWaitForMining()
const txHash = await txHashPromise const txHash = await txHashPromise
...@@ -164,6 +165,7 @@ test('Send an EIP-1559 transaction and verify success', async () => { ...@@ -164,6 +165,7 @@ test('Send an EIP-1559 transaction and verify success', async () => {
// Metamask test dApp allows us access to the Metamask RPC provider via loading this URL. // Metamask test dApp allows us access to the Metamask RPC provider via loading this URL.
// The RPC response will be populated onto the page that's loaded. // The RPC response will be populated onto the page that's loaded.
// More info here: https://github.com/MetaMask/test-dapp/tree/main#usage // More info here: https://github.com/MetaMask/test-dapp/tree/main#usage
console.log('Retrieving transaction receipt...')
await sharedPage.goto( await sharedPage.goto(
`${env.METAMASK_DAPP_URL}/request.html?method=eth_getTransactionReceipt&params=["${txHash}"]` `${env.METAMASK_DAPP_URL}/request.html?method=eth_getTransactionReceipt&params=["${txHash}"]`
) )
...@@ -179,7 +181,6 @@ test('Send an EIP-1559 transaction and verify success', async () => { ...@@ -179,7 +181,6 @@ test('Send an EIP-1559 transaction and verify success', async () => {
handledFailure = true handledFailure = true
throw error throw error
} }
console.log('Sent an EIP-1559 transaction and verified success')
await setFeeEstimationGauge('low', lowFeeEstimate) await setFeeEstimationGauge('low', lowFeeEstimate)
await setFeeEstimationGauge('medium', mediumFeeEstimate) await setFeeEstimationGauge('medium', mediumFeeEstimate)
...@@ -192,7 +193,6 @@ const getFeeEstimateInGwei = async ( ...@@ -192,7 +193,6 @@ const getFeeEstimateInGwei = async (
waitForText: 'Low' | 'Market' | 'Aggressive', waitForText: 'Low' | 'Market' | 'Aggressive',
notificationPage: Page notificationPage: Page
) => { ) => {
const regexParseEtherValue = /(\d+\.\d+)\sOPG/
await synpressPlaywright.waitAndClick( await synpressPlaywright.waitAndClick(
confirmPageElements.editGasFeeButton, confirmPageElements.editGasFeeButton,
notificationPage notificationPage
...@@ -203,6 +203,7 @@ const getFeeEstimateInGwei = async ( ...@@ -203,6 +203,7 @@ const getFeeEstimateInGwei = async (
waitForText, waitForText,
notificationPage notificationPage
) )
const regexParseEtherValue = /(\d+\.\d+)\s?OPS/
const feeValue = ( const feeValue = (
await synpressPlaywright.waitAndGetValue( await synpressPlaywright.waitAndGetValue(
confirmPageElements.totalLabel, confirmPageElements.totalLabel,
......
...@@ -4,16 +4,63 @@ import { Gauge, Pushgateway, Registry } from 'prom-client' ...@@ -4,16 +4,63 @@ import { Gauge, Pushgateway, Registry } from 'prom-client'
const env = z const env = z
.object({ .object({
PROMETHEUS_SERVER_URL: z.string().url(), METRICS_READ_URL: z.string().url(),
PROMETHEUS_PUSHGATEWAY_URL: z.string().url(), METRICS_READ_USERNAME: z.string().optional(),
METRICS_READ_PASSWORD: z.string().optional(),
METRICS_WRITE_URL: z.string().url(),
METRICS_WRITE_TOOL: z.enum(['grafana', 'prometheus-pushgateway']),
METRIC_WRITE_SOURCE: z.string().optional(),
METRICS_WRITE_USERNAME: z.string().optional(),
METRICS_WRITE_PASSWORD: z.string().optional(),
}) })
.refine(
(data) => {
if (
(data.METRICS_READ_USERNAME && !data.METRICS_READ_PASSWORD) ||
(data.METRICS_READ_PASSWORD && !data.METRICS_READ_USERNAME)
) {
return false
}
if (
(data.METRICS_WRITE_USERNAME && !data.METRICS_WRITE_PASSWORD) ||
(data.METRICS_WRITE_PASSWORD && !data.METRICS_WRITE_USERNAME)
) {
return false
}
return true
},
{
message:
'Both username and password must be provided together for read or write metrics',
}
)
.refine(
(data) => {
if (
data.METRICS_WRITE_TOOL === 'grafana' &&
data.METRIC_WRITE_SOURCE === undefined
)
return false
return true
},
{
message:
'Writing to Grafana requires a source, please specify one using METRIC_WRITE_SOURCE env',
}
)
.parse(process.env) .parse(process.env)
const selfSendTransactionMetricName = 'metamask_self_send' const selfSendTransactionMetricName = 'metamask_self_send_metric'
const feeEstimateLowMetricName = 'metamask_self_send_fee_estimation_low' const feeEstimateLowMetricName = 'metamask_self_send_fee_estimation_low_metric'
const feeEstimateMediumMetricName = 'metamask_self_send_fee_estimation_medium' const feeEstimateMediumMetricName =
const feeEstimateHighMetricName = 'metamask_self_send_fee_estimation_high' 'metamask_self_send_fee_estimation_medium_metric'
const feeEstimateActualMetricName = 'metamask_self_send_fee_estimation_actual' const feeEstimateHighMetricName =
'metamask_self_send_fee_estimation_high_metric'
const feeEstimateActualMetricName =
'metamask_self_send_fee_estimation_actual_metric'
const selfSendRegistry = new Registry() const selfSendRegistry = new Registry()
const feeEstimateLowRegistry = new Registry() const feeEstimateLowRegistry = new Registry()
...@@ -24,38 +71,51 @@ const feeEstimateActualRegistry = new Registry() ...@@ -24,38 +71,51 @@ const feeEstimateActualRegistry = new Registry()
const selfSendGauge = new Gauge({ const selfSendGauge = new Gauge({
name: selfSendTransactionMetricName, name: selfSendTransactionMetricName,
help: 'A gauge signifying the number of transactions sent with Metamask', help: 'A gauge signifying the number of transactions sent with Metamask',
registers: [selfSendRegistry] registers: [selfSendRegistry],
}) })
const feeEstimateLowGauge = new Gauge({ const feeEstimateLowGauge = new Gauge({
name: feeEstimateLowMetricName, name: feeEstimateLowMetricName,
help: 'A gauge signifying the latest fee estimation from Metamask for Low transaction speed', help: 'A gauge signifying the latest fee estimation from Metamask for Low transaction speed',
registers: [feeEstimateLowRegistry] registers: [feeEstimateLowRegistry],
}) })
const feeEstimateMediumGauge = new Gauge({ const feeEstimateMediumGauge = new Gauge({
name: feeEstimateMediumMetricName, name: feeEstimateMediumMetricName,
help: 'A gauge signifying the latest fee estimation from Metamask for Medium transaction speed', help: 'A gauge signifying the latest fee estimation from Metamask for Medium transaction speed',
registers: [feeEstimateMediumRegistry] registers: [feeEstimateMediumRegistry],
}) })
const feeEstimateHighGauge = new Gauge({ const feeEstimateHighGauge = new Gauge({
name: feeEstimateHighMetricName, name: feeEstimateHighMetricName,
help: 'A gauge signifying the latest fee estimation from Metamask for High transaction speed', help: 'A gauge signifying the latest fee estimation from Metamask for High transaction speed',
registers: [feeEstimateHighRegistry] registers: [feeEstimateHighRegistry],
}) })
const feeEstimateActualGauge = new Gauge({ const feeEstimateActualGauge = new Gauge({
name: feeEstimateActualMetricName, name: feeEstimateActualMetricName,
help: 'A gauge signifying the latest actual transaction fee', help: 'A gauge signifying the latest actual transaction fee',
registers: [feeEstimateActualRegistry] registers: [feeEstimateActualRegistry],
}) })
export const getSelfSendGaugeValue = async () => { const queryMetricsReadUrl = async (
const prometheusMetricQuery = `${env.PROMETHEUS_SERVER_URL}/api/v1/query?query=${selfSendTransactionMetricName}` query: string = selfSendTransactionMetricName
) => {
const response = await fetch(prometheusMetricQuery) const metricsReadRequest = `${env.METRICS_READ_URL}?query=${query}`
const response = await fetch(metricsReadRequest, {
headers:
env.METRICS_READ_USERNAME === undefined
? undefined
: {
Authorization: `Bearer ${env.METRICS_READ_USERNAME}:${env.METRICS_READ_PASSWORD}`,
},
})
if (!response.ok) { if (!response.ok) {
console.error(response.status) console.error(response.status)
console.error(response.statusText) console.error(response.statusText)
throw new Error(`Failed to fetch metric from: ${prometheusMetricQuery}`) throw new Error(`Failed to fetch metric from: ${metricsReadRequest}`)
} }
return response
}
export const getSelfSendGaugeValue = async () => {
const response = await queryMetricsReadUrl(selfSendTransactionMetricName)
// The following is an example of the expect response from prometheusMetricQuery // The following is an example of the expect response from prometheusMetricQuery
// for response.json().data.result[0]: // for response.json().data.result[0]:
...@@ -92,7 +152,7 @@ export const getSelfSendGaugeValue = async () => { ...@@ -92,7 +152,7 @@ export const getSelfSendGaugeValue = async () => {
error.message === "Cannot read properties of undefined (reading 'value')" error.message === "Cannot read properties of undefined (reading 'value')"
) { ) {
console.warn( console.warn(
`No data found for metric ${selfSendTransactionMetricName} in Prometheus` `No data found for metric ${selfSendTransactionMetricName} in ${env.METRICS_READ_URL}`
) )
return undefined return undefined
} }
...@@ -101,12 +161,44 @@ export const getSelfSendGaugeValue = async () => { ...@@ -101,12 +161,44 @@ export const getSelfSendGaugeValue = async () => {
} }
} }
const pushMetricsGrafana = (metricName: string, valueToSetTo: number) =>
pushMetricsWriteUrl(
`${metricName},source=${
env.METRIC_WRITE_SOURCE
} metric=${valueToSetTo}`
)
const pushMetricsPrometheusPushgateway = (registry: Registry) => {
const pushGateway = new Pushgateway(env.METRICS_WRITE_URL, undefined, registry)
return pushGateway.pushAdd({ jobName: 'ufm-metamask-metric-push'})
}
const pushMetricsWriteUrl = async (requestBody: string) => {
const response = await fetch(env.METRICS_WRITE_URL, {
method: 'POST',
headers:
env.METRICS_WRITE_USERNAME === undefined
? undefined
: {
Authorization: `Bearer ${env.METRICS_WRITE_USERNAME}:${env.METRICS_WRITE_PASSWORD}`,
},
body: requestBody,
})
if (!response.ok) {
console.error(response.status)
console.error(response.statusText)
throw new Error(`Failed to push metric to: ${env.METRICS_WRITE_URL}`)
}
return response
}
export const setSelfSendTxGauge = async (valueToSetTo: number) => { export const setSelfSendTxGauge = async (valueToSetTo: number) => {
console.log(`Setting ${selfSendTransactionMetricName} to ${valueToSetTo}...`) console.log(`Setting ${selfSendTransactionMetricName} to ${valueToSetTo}...`)
selfSendGauge.set(valueToSetTo) selfSendGauge.set(valueToSetTo)
const pushGateway = new Pushgateway(env.PROMETHEUS_PUSHGATEWAY_URL, undefined, selfSendRegistry) env.METRICS_WRITE_TOOL === 'grafana'
await pushGateway.pushAdd({ jobName: 'metamask_self_send_tx_count' }) ? await pushMetricsGrafana(selfSendTransactionMetricName.replace('_metric', ''), valueToSetTo)
: await pushMetricsPrometheusPushgateway(selfSendRegistry)
} }
export const incrementSelfSendTxGauge = async (isSuccess: boolean) => { export const incrementSelfSendTxGauge = async (isSuccess: boolean) => {
...@@ -125,36 +217,41 @@ export const incrementSelfSendTxGauge = async (isSuccess: boolean) => { ...@@ -125,36 +217,41 @@ export const incrementSelfSendTxGauge = async (isSuccess: boolean) => {
await setSelfSendTxGauge(newMetricValue) await setSelfSendTxGauge(newMetricValue)
} }
export const setFeeEstimationGauge = async (txSpeed: 'low' | 'medium' | 'high' | 'actual', fee: number) => { export const setFeeEstimationGauge = async (
console.log( txSpeed: 'low' | 'medium' | 'high' | 'actual',
txSpeed !== 'actual' fee: number
? `Setting Metamask fee estimation for ${txSpeed} to ${fee}...` ) => {
: `Setting actual transaction fee to ${fee}` let metricNameGrafana: string
)
let prometheusRegistry: Registry let prometheusRegistry: Registry
switch (txSpeed) { switch (txSpeed) {
case 'low': case 'low':
feeEstimateLowGauge.set(fee) feeEstimateLowGauge.set(fee)
metricNameGrafana = feeEstimateLowMetricName
prometheusRegistry = feeEstimateLowRegistry prometheusRegistry = feeEstimateLowRegistry
break; break
case 'medium': case 'medium':
feeEstimateMediumGauge.set(fee) feeEstimateMediumGauge.set(fee)
metricNameGrafana = feeEstimateMediumMetricName
prometheusRegistry = feeEstimateMediumRegistry prometheusRegistry = feeEstimateMediumRegistry
break; break
case 'high': case 'high':
feeEstimateHighGauge.set(fee) feeEstimateHighGauge.set(fee)
metricNameGrafana = feeEstimateHighMetricName
prometheusRegistry = feeEstimateHighRegistry prometheusRegistry = feeEstimateHighRegistry
break; break
case 'actual': case 'actual':
feeEstimateActualGauge.set(fee) feeEstimateActualGauge.set(fee)
metricNameGrafana = feeEstimateActualMetricName
prometheusRegistry = feeEstimateActualRegistry prometheusRegistry = feeEstimateActualRegistry
break; break
default: default:
throw new Error(`unsupported transaction speed given: ${txSpeed}`) throw new Error(`unsupported transaction speed given: ${txSpeed}`)
} }
metricNameGrafana = metricNameGrafana.replace('_metric', '')
console.log(`Setting ${metricNameGrafana} to ${fee}...`)
const pushGateway = new Pushgateway(env.PROMETHEUS_PUSHGATEWAY_URL, undefined, prometheusRegistry) env.METRICS_WRITE_TOOL === 'grafana'
await pushGateway.pushAdd({ jobName: `metamask_self_send_tx_fee_estimation_${txSpeed}` }) ? await pushMetricsGrafana(metricNameGrafana, fee)
: await pushMetricsPrometheusPushgateway(prometheusRegistry)
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment