Skip to content

Commit

Permalink
feat(bridge-ui-v2): dynamic import of NFT data via API (#14928)
Browse files Browse the repository at this point in the history
  • Loading branch information
KorbinianK authored Oct 10, 2023
1 parent 9de8ba5 commit 946c337
Show file tree
Hide file tree
Showing 27 changed files with 1,121 additions and 268 deletions.
4 changes: 3 additions & 1 deletion packages/bridge-ui-v2/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export PUBLIC_WALLETCONNECT_PROJECT_ID=""

# Enable NFT Bridge ("true" or "false")
export PUBLIC_NFT_BRIDGE_ENABLED=""
PUBLIC_NFT_BATCH_TRANSFERS_ENABLED=""

# Sentry
export PUBLIC_SENTRY_DSN=https://
Expand All @@ -20,4 +21,5 @@ export SENTRY_AUTH_TOKEN=
export CONFIGURED_BRIDGES=
export CONFIGURED_CHAINS=
export CONFIGURED_CUSTOM_TOKEN=
export CONFIGURED_RELAYER=
export CONFIGURED_RELAYER=
export CONFIGURED_EVENT_INDEXER=
12 changes: 12 additions & 0 deletions packages/bridge-ui-v2/config/sample/configuredEventIndexer.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"configuredEventIndexer": [
{
"chainIds": [123456, 654321],
"url": "https://some/url.example"
},
{
"chainIds": [1, 11155111],
"url": "https://some/other/url.example"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"$id": "configuredEventIndexer.json",
"type": "object",
"properties": {
"configuredEventIndexer": {
"type": "array",
"items": {
"type": "object",
"properties": {
"chainIds": {
"type": "array",
"items": {
"type": "integer"
}
},
"url": {
"type": "string"
}
},
"required": ["chainIds", "url"]
}
}
},
"required": ["configuredEventIndexer"]
}
3 changes: 2 additions & 1 deletion packages/bridge-ui-v2/scripts/exportJsonToEnv.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ const bridgesPath = 'config/configuredBridges.json';
const chainsPath = 'config/configuredChains.json';
const tokensPath = 'config/configuredCustomToken.json';
const relayerPath = 'config/configuredRelayer.json';
const eventIndexerPath = 'config/configuredEventIndexer.json';

// Create a backup of the existing .env file
fs.copyFileSync(envFile, `${envFile}.bak`);

const jsonFiles = [bridgesPath, chainsPath, tokensPath, relayerPath];
const jsonFiles = [bridgesPath, chainsPath, tokensPath, relayerPath, eventIndexerPath];

jsonFiles.forEach((jsonFile) => {
if (fs.existsSync(jsonFile)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/* eslint-disable no-console */
import dotenv from 'dotenv';
import { promises as fs } from 'fs';
import path from 'path';
import { Project, SourceFile, VariableDeclarationKind } from 'ts-morph';

import configuredEventIndexerSchema from '../../config/schemas/configuredEventIndexer.schema.json';
import type { ConfiguredEventIndexer, EventIndexerConfig } from '../../src/libs/eventIndexer/types';
import { decodeBase64ToJson } from './../utils/decodeBase64ToJson';
import { formatSourceFile } from './../utils/formatSourceFile';
import { PluginLogger } from './../utils/PluginLogger';
import { validateJsonAgainstSchema } from './../utils/validateJson';

dotenv.config();

const pluginName = 'generateEventIndexerConfig';
const logger = new PluginLogger(pluginName);

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

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

const outputPath = path.join(path.dirname(currentDir), '../../src/generated/eventIndexerConfig.ts');

export function generateEventIndexerConfig() {
return {
name: pluginName,
async buildStart() {
logger.info('Plugin initialized.');
let configuredEventIndexerConfigFile;

if (!skip) {
if (!process.env.CONFIGURED_EVENT_INDEXER) {
throw new Error(
'CONFIGURED_EVENT_INDEXER is not defined in environment. Make sure to run the export step in the documentation.',
);
}

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

// Valide JSON against schema
const isValid = validateJsonAgainstSchema(configuredEventIndexerConfigFile, configuredEventIndexerSchema);
if (!isValid) {
throw new Error('encoded configuredBridges.json is not valid.');
}
} else {
configuredEventIndexerConfigFile = '';
}
// Path to where you want to save the generated Typ eScript file
const tsFilePath = path.resolve(outputPath);

const project = new Project();
const notification = `// Generated by ${pluginName} on ${new Date().toLocaleString()}`;
const warning = `// WARNING: Do not change this file manually as it will be overwritten`;

let sourceFile = project.createSourceFile(tsFilePath, `${notification}\n${warning}\n`, { overwrite: true });

// Create the TypeScript content
sourceFile = await storeTypesAndEnums(sourceFile);
sourceFile = await buildEventIndexerConfig(sourceFile, configuredEventIndexerConfigFile);

await sourceFile.save();

const formatted = await formatSourceFile(tsFilePath);
console.log('formatted', tsFilePath);

// Write the formatted code back to the file
await fs.writeFile(tsFilePath, formatted);
logger.info(`Formatted config file saved to ${tsFilePath}`);
},
};
}

async function storeTypesAndEnums(sourceFile: SourceFile) {
logger.info(`Storing types...`);
// RelayerConfig
sourceFile.addImportDeclaration({
namedImports: ['EventIndexerConfig'],
moduleSpecifier: '$libs/eventIndexer',
isTypeOnly: true,
});

logger.info('Types stored.');
return sourceFile;
}

async function buildEventIndexerConfig(
sourceFile: SourceFile,
configuredEventIndexerConfigFile: ConfiguredEventIndexer,
) {
logger.info('Building event indexer config...');

const indexer: ConfiguredEventIndexer = configuredEventIndexerConfigFile;

if (!skip) {
if (!indexer.configuredEventIndexer || !Array.isArray(indexer.configuredEventIndexer)) {
console.error(
'configuredEventIndexer is not an array. Please check the content of the configuredEventIndexerConfigFile.',
);
throw new Error();
}
// Create a constant variable for the configuration
const eventIndexerConfigVariable = {
declarationKind: VariableDeclarationKind.Const,
declarations: [
{
name: 'configuredEventIndexer',
initializer: _formatObjectToTsLiteral(indexer.configuredEventIndexer),
type: 'EventIndexerConfig[]',
},
],
isExported: true,
};
sourceFile.addVariableStatement(eventIndexerConfigVariable);
} else {
const emptyEventIndexerConfigVariable = {
declarationKind: VariableDeclarationKind.Const,
declarations: [
{
name: 'configuredEventIndexer',
initializer: '[]',
type: 'EventIndexerConfig[]',
},
],
isExported: true,
};
sourceFile.addVariableStatement(emptyEventIndexerConfigVariable);
}

logger.info('EventIndexer config built.');
return sourceFile;
}

const _formatEventIndexerConfigToTsLiteral = (config: EventIndexerConfig): string => {
return `{chainIds: [${config.chainIds ? config.chainIds.join(', ') : ''}], url: "${config.url}"}`;
};

const _formatObjectToTsLiteral = (indexer: EventIndexerConfig[]): string => {
return `[${indexer.map(_formatEventIndexerConfigToTsLiteral).join(', ')}]`;
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
};
export const clearAddress = () => {
state = State.Default;
if (input) input.value = '';
validateEthereumAddress('');
};
Expand Down
Loading

1 comment on commit 946c337

@vercel
Copy link

@vercel vercel bot commented on 946c337 Oct 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

bridge-ui-v2-internal – ./packages/bridge-ui-v2

bridge-ui-v2-internal-taikoxyz.vercel.app
bridge-ui-v2-internal.vercel.app
bridge-ui-v2-internal-git-main-taikoxyz.vercel.app

Please sign in to comment.