Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(bridge-ui-v2): build errors #14706

Merged
merged 17 commits into from
Sep 18, 2023
Merged
12 changes: 12 additions & 0 deletions .github/workflows/bridge-ui-v2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ jobs:
working-directory: ./packages/bridge-ui-v2
run: cp .env.example .env

- name: Export config to .env
working-directory: ./packages/bridge-ui-v2
run: pnpm export:config

- name: Build Svelte app
env:
SKIP_ENV_VALDIATION: "true"
working-directory: ./packages/bridge-ui-v2
run: pnpm build

- name: Svelte check
working-directory: ./packages/bridge-ui-v2
run: pnpm svelte:check
Expand All @@ -40,6 +50,8 @@ jobs:
run: pnpm lint

- name: Unit tests
env:
SKIP_ENV_VALDIATION: "true"
working-directory: ./packages/bridge-ui-v2
run: pnpm test:unit

Expand Down
2 changes: 1 addition & 1 deletion packages/bridge-ui-v2/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ vite.config.ts.timestamp-*
!/config/sample/
!/config/schemas/

src/generated/*
src/generated/
28 changes: 4 additions & 24 deletions packages/bridge-ui-v2/__mocks__/$env/static/public.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,10 @@
export const PUBLIC_L1_CHAIN_NAME = 'Ethereum';
export const PUBLIC_L2_CHAIN_NAME = 'Taiko';
export const PUBLIC_L3_CHAIN_NAME = 'L3 chain';
export const PUBLIC_L1_CHAIN_ID = '1';
export const PUBLIC_L2_CHAIN_ID = '2';
export const PUBLIC_L3_CHAIN_ID = '3';
export const PUBLIC_L1_RPC_URL = 'https://l1rpc.com';
export const PUBLIC_L2_RPC_URL = 'https://l2rpc.com';
export const PUBLIC_L3_RPC_URL = 'https://l3rpc.com';
export const PUBLIC_L1_EXPLORER_URL = 'https://l1explorer.com';
export const PUBLIC_L2_EXPLORER_URL = 'https://l2explorer.com';
export const PUBLIC_L3_EXPLORER_URL = 'https://l3explorer.com';
export const PUBLIC_RELAYER_URL = 'https://relayer.com';
export const PUBLIC_GUIDE_URL = 'https://guide.com';
export const PUBLIC_L1_CROSS_CHAIN_SYNC_ADDRESS = '0x123';
export const PUBLIC_L2_CROSS_CHAIN_SYNC_ADDRESS = '0x234';
export const PUBLIC_L3_CROSS_CHAIN_SYNC_ADDRESS = '0x345';
export const PUBLIC_L1_TOKEN_VAULT_ADDRESS = '0x456';
export const PUBLIC_L2_TOKEN_VAULT_ADDRESS = '0x567';
export const PUBLIC_L3_TOKEN_VAULT_ADDRESS = '0x678';
export const PUBLIC_L1_BRIDGE_ADDRESS = '0x789';
export const PUBLIC_L2_BRIDGE_ADDRESS = '0x890';
export const PUBLIC_L3_BRIDGE_ADDRESS = '0x901';
export const PUBLIC_L1_SIGNAL_SERVICE_ADDRESS = '0x012';
export const PUBLIC_L2_SIGNAL_SERVICE_ADDRESS = '0x098';
export const PUBLIC_L3_SIGNAL_SERVICE_ADDRESS = '0x987';
export const PUBLIC_TEST_ERC20 =
'[{"address": "0x876", "symbol": "BLL", "name": "Bull Token"}, {"address": "0x765", "symbol": "HORSE", "name": "Horse Token"}]';
export const PUBLIC_WALLETCONNECT_PROJECT_ID = '123';
export const PUBLIC_SENTRY_DSN = 'https://sentry.com';
export const CONFIGURED_BRIDGES = '';
export const CONFIGURED_CHAINS = '';
export const CONFIGURED_CUSTOM_TOKEN = '';
export const CONFIGURED_RELAYER = '';
8 changes: 8 additions & 0 deletions packages/bridge-ui-v2/__mocks__/@wagmi/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,11 @@ export const getPublicClient = vi.fn();
export const getContract = vi.fn();

export const fetchBalance = vi.fn();

export const configureChains = vi.fn(() => {
return { publicClient: 'mockPublicClient' };
});

export const createConfig = vi.fn(() => {
return 'mockWagmiConfig';
});
4 changes: 2 additions & 2 deletions packages/bridge-ui-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"test:unit:debug": "vitest run",
"test:unit:coverage": "vitest run --silent --coverage",
"test:unit:watch": "vitest",
"svelte:check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --ignore ./wagmi.config.ts",
"svelte:check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --ignore ./wagmi.config.ts ./src/generated",
"svelte:check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --ignore ./wagmi.config.ts --watch",
"format": "prettier --write .",
"lint": "prettier --check . && eslint .",
Expand All @@ -27,7 +27,7 @@
"@sveltejs/kit": "^1.22.3",
"@types/debug": "^4.1.7",
"@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/parser": "^5.45.0",
"@typescript-eslint/parser": "^6.7.0",
"@vitest/coverage-v8": "^0.33.0",
"@wagmi/cli": "^1.0.1",
"abitype": "^0.8.7",
Expand Down
2 changes: 1 addition & 1 deletion packages/bridge-ui-v2/scripts/exportJsonToEnv.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import * as fs from 'fs';
import * as path from 'path';

import { Logger as LogUtil } from './utils/Logger.js';
import { PluginLogger as LogUtil } from './utils/PluginLogger.js';

const Logger = new LogUtil('exportJsonToEnv');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const Reset = '\x1b[0m';

const timestamp = () => new Date().toLocaleTimeString();

export class Logger {
export class PluginLogger {
/**
* @param {string} pluginName
*/
Expand Down
4 changes: 2 additions & 2 deletions packages/bridge-ui-v2/scripts/utils/validateJson.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/* eslint-disable no-console */
import Ajv, { type Schema } from 'ajv';

import { Logger } from './Logger';
import { PluginLogger } from './PluginLogger';

const ajv = new Ajv({ strict: false });

type SchmaWithId = Schema & { $id?: string };

const logger = new Logger('json-validator');
const logger = new PluginLogger('json-validator');

export const validateJsonAgainstSchema = (json: JSON, schema: SchmaWithId): boolean => {
logger.info(`Validating ${schema.$id}`);
Expand Down
135 changes: 77 additions & 58 deletions packages/bridge-ui-v2/scripts/vite-plugins/generateBridgeConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import configuredBridgesSchema from '../../config/schemas/configuredBridges.sche
import type { BridgeConfig, ConfiguredBridgesType, RoutingMap } from '../../src/libs/bridge/types';
import { decodeBase64ToJson } from '../utils/decodeBase64ToJson';
import { formatSourceFile } from '../utils/formatSourceFile';
import { Logger } from '../utils/Logger';
import { PluginLogger } from '../utils/PluginLogger';
import { validateJsonAgainstSchema } from '../utils/validateJson';

dotenv.config();
const pluginName = 'generateBridgeConfig';
const logger = new Logger(pluginName);
const logger = new PluginLogger(pluginName);

const skip = process.env.SKIP_ENV_VALDIATION || false;

const currentDir = path.resolve(new URL(import.meta.url).pathname);

Expand All @@ -22,22 +24,27 @@ export function generateBridgeConfig() {
return {
name: pluginName,
async buildStart() {
if (!process.env.CONFIGURED_BRIDGES) {
throw new Error(
'CONFIGURED_BRIDGES is not defined in environment. Make sure to run the export step in the documentation.',
);
}

// Decode base64 encoded JSON string
const configuredBridgesConfigFile = decodeBase64ToJson(process.env.CONFIGURED_BRIDGES || '');

// Valide JSON against schema
const isValid = validateJsonAgainstSchema(configuredBridgesConfigFile, configuredBridgesSchema);

if (!isValid) {
throw new Error('encoded configuredBridges.json is not valid.');
}
logger.info('Plugin initialized.');
let configuredBridgesConfigFile;
if (!skip) {
if (!process.env.CONFIGURED_BRIDGES) {
throw new Error(
'CONFIGURED_BRIDGES is not defined in environment. Make sure to run the export step in the documentation.',
);
}

// Decode base64 encoded JSON string
configuredBridgesConfigFile = decodeBase64ToJson(process.env.CONFIGURED_BRIDGES || '');

// Valide JSON against schema
const isValid = validateJsonAgainstSchema(configuredBridgesConfigFile, configuredBridgesSchema);

if (!isValid) {
throw new Error('encoded configuredBridges.json is not valid.');
}
} else {
configuredBridgesConfigFile = '';
}

const tsFilePath = path.resolve(outputPath);

Expand Down Expand Up @@ -86,58 +93,70 @@ async function buildBridgeConfig(sourceFile: SourceFile, configuredBridgesConfig

const bridges: ConfiguredBridgesType = configuredBridgesConfigFile;

if (!bridges.configuredBridges || !Array.isArray(bridges.configuredBridges)) {
logger.error('configuredBridges is not an array. Please check the content of the configuredBridgesConfigFile.');
throw new Error();
}

bridges.configuredBridges.forEach((item: BridgeConfig) => {
if (!routingContractsMap[item.source]) {
routingContractsMap[item.source] = {};
if (!skip) {
if (!bridges.configuredBridges || !Array.isArray(bridges.configuredBridges)) {
logger.error('configuredBridges is not an array. Please check the content of the configuredBridgesConfigFile.');
throw new Error();
}
routingContractsMap[item.source][item.destination] = item.addresses;
});

// Add routingContractsMap variable
sourceFile.addVariableStatement({
declarationKind: VariableDeclarationKind.Const,
declarations: [
{
name: 'routingContractsMap',
type: 'RoutingMap',
initializer: _formatObjectToTsLiteral(routingContractsMap),
},
],
isExported: true,
});

logger.info(`Configured ${bridges.configuredBridges.length} bridges.`);
bridges.configuredBridges.forEach((item: BridgeConfig) => {
if (!routingContractsMap[item.source]) {
routingContractsMap[item.source] = {};
}
routingContractsMap[item.source][item.destination] = item.addresses;
});
}
if (skip) {
// Add empty routingContractsMap variable
sourceFile.addVariableStatement({
declarationKind: VariableDeclarationKind.Const,
declarations: [
{
name: 'routingContractsMap',
type: 'RoutingMap',
initializer: '{}',
},
],
isExported: true,
});
logger.info(`Skipped bridge.`);
} else {
// Add routingContractsMap variable
sourceFile.addVariableStatement({
declarationKind: VariableDeclarationKind.Const,
declarations: [
{
name: 'routingContractsMap',
type: 'RoutingMap',
initializer: _formatObjectToTsLiteral(routingContractsMap),
},
],
isExported: true,
});
logger.info(`Configured ${bridges.configuredBridges.length} bridges.`);
}
return sourceFile;
}

const _formatObjectToTsLiteral = (obj: RoutingMap): string => {
const formatValue = (value: any): string => {
const formatValue = (value: string | number | boolean | null): string => {
if (typeof value === 'string') {
return `"${value}"`;
}
if (typeof value === 'number' || typeof value === 'boolean' || value === null) {
return String(value);
}
if (Array.isArray(value)) {
return `[${value.map(formatValue).join(', ')}]`;
}
if (typeof value === 'object') {
return _formatObjectToTsLiteral(value);
}
return 'undefined';
return String(value);
};

if (Array.isArray(obj)) {
return `[${obj.map(formatValue).join(', ')}]`;
}

const entries = Object.entries(obj);
const formattedEntries = entries.map(([key, value]) => `${key}: ${formatValue(value)}`);
const formattedEntries = entries.map(([key, value]) => {
const innerEntries = Object.entries(value);
const innerFormattedEntries = innerEntries.map(([innerKey, innerValue]) => {
const innerInnerEntries = Object.entries(innerValue);
const innerInnerFormattedEntries = innerInnerEntries.map(
([innerInnerKey, innerInnerValue]) => `${innerInnerKey}: ${formatValue(innerInnerValue)}`,
);
return `${innerKey}: {${innerInnerFormattedEntries.join(', ')}}`;
});
return `${key}: {${innerFormattedEntries.join(', ')}}`;
});

return `{${formattedEntries.join(', ')}}`;
};