Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions packages/game-bridge/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const esbuild = require('esbuild');
const fs = require('fs');
const path = require('path');

async function build() {
// Clean dist folder
if (fs.existsSync('dist')) {
fs.rmSync('dist', { recursive: true });
}
fs.mkdirSync('dist/unity', { recursive: true });
fs.mkdirSync('dist/unreal', { recursive: true });

// Build Unity target (IIFE with inline HTML)
console.log('Building Unity target...');
await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
platform: 'browser',
target: 'chrome90',
format: 'iife',
globalName: 'ImmutableGameBridge',
outfile: 'dist/unity/bundle.js',
minify: true,
sourcemap: false,
keepNames: true,
define: {
'process.env.NODE_ENV': '"production"'
},
logLevel: 'info'
});

// Create HTML wrapper for Unity with inlined JS
let htmlTemplate = fs.readFileSync('src/index.html', 'utf-8');
const bundleJs = fs.readFileSync('dist/unity/bundle.js', 'utf-8');

// Find and replace the script section - be explicit about what we're replacing
const scriptStart = htmlTemplate.indexOf('<script');
const scriptEnd = htmlTemplate.indexOf('</script>') + '</script>'.length;

if (scriptStart === -1 || scriptEnd === -1) {
throw new Error('Could not find script tags in HTML template');
}

const beforeScript = htmlTemplate.substring(0, scriptStart);
const afterScript = htmlTemplate.substring(scriptEnd);

const inlineHtml = beforeScript + `<script>\n${bundleJs}\n </script>` + afterScript;

fs.writeFileSync('dist/unity/index.html', inlineHtml);
fs.unlinkSync('dist/unity/bundle.js');

console.log(`Unity HTML created with ${(bundleJs.length / 1024 / 1024).toFixed(2)}MB of inlined JS`);

// Build Unreal target (global format JS only)
console.log('Building Unreal target...');
await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
platform: 'browser',
target: 'chrome90',
format: 'iife',
globalName: 'ImmutableGameBridge',
outfile: 'dist/unreal/index.js',
minify: true,
sourcemap: false,
define: {
'process.env.NODE_ENV': '"production"'
}
});

console.log('✨ Build complete!');
}

build().catch((err) => {
console.error('Build failed:', err);
process.exit(1);
});
7 changes: 5 additions & 2 deletions packages/game-bridge/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
"ethers": "^6.13.4"
},
"devDependencies": {
"esbuild": "^0.23.1",
"eslint": "^8.40.0",
"html-inline": "^1.2.0",
"parcel": "^2.8.3"
},
"scripts": {
"build": "parcel build --no-cache --no-scope-hoist",
"build:local": "parcel build --no-cache --no-scope-hoist && pnpm updateSdkVersion",
"build": "node build.js",
"build:parcel": "parcel build --no-cache --no-scope-hoist",
"build:local": "node build.js && pnpm updateSdkVersion",
"lint": "eslint ./src --ext .ts,.jsx,.tsx --max-warnings=0",
"start": "parcel",
"updateSdkVersion": "./scripts/updateSdkVersion.sh"
Expand Down
69 changes: 52 additions & 17 deletions packages/game-bridge/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
/* eslint-disable no-console */

// Catch any errors during module initialization
window.addEventListener('error', (event) => {
console.error('Global error caught:', event.error || event.message);
});

window.addEventListener('unhandledrejection', (event) => {
console.error('Unhandled promise rejection:', event.reason);
});

console.log('game-bridge loading...');

import * as passport from '@imtbl/passport';
import * as config from '@imtbl/config';
import * as provider from '@imtbl/x-provider';
Expand All @@ -14,12 +26,29 @@ import * as ethers from 'ethers';
// eslint-disable-next-line import/no-duplicates
import { BrowserProvider, getAddress } from 'ethers';

console.log('game-bridge imports loaded');

// This patches a bundler issue where @0xsequence/core expects
// `ethers.getAddress` to exist on the `ethers` namespace, but Parcel
// fails to attach it in a global build. This ensures the function is
// `ethers.getAddress` to exist on the `ethers` namespace, but some bundlers
// fail to attach it in a global build. This ensures the function is
// available before any Passport code executes.
if (typeof ethers === 'object' && !ethers.getAddress) {
(ethers as any).getAddress = getAddress;
try {
if (typeof ethers === 'object' && !ethers.getAddress) {
try {
Object.defineProperty(ethers, 'getAddress', {
value: getAddress,
writable: true,
configurable: true
});
console.log('ethers.getAddress patched successfully');
} catch (e) {
// If we can't define the property, create a new object with the patched value
(window as any).ethers = { ...ethers, getAddress };
console.log('ethers.getAddress patched via window.ethers');
}
}
} catch (error) {
console.error('Error during ethers patching:', error);
}

/* eslint-disable no-undef */
Expand Down Expand Up @@ -176,7 +205,7 @@ const getProvider = (): provider.IMXProvider => {
return providerInstance;
};

const setZkEvmProvider = (zkEvmProvider: passport.Provider | null | undefined): boolean => {
const setEvmProvider = (zkEvmProvider: passport.Provider | null | undefined): boolean => {
if (zkEvmProvider !== null && zkEvmProvider !== undefined) {
zkEvmProviderInstance = zkEvmProvider;
console.log('zkEvm provider set');
Expand All @@ -186,7 +215,7 @@ const setZkEvmProvider = (zkEvmProvider: passport.Provider | null | undefined):
return false;
};

const getZkEvmProvider = (): passport.Provider => {
const getEvmProvider = (): passport.Provider => {
if (zkEvmProviderInstance == null) {
throw new Error('No zkEvm provider');
}
Expand Down Expand Up @@ -263,10 +292,13 @@ window.callFunction = async (jsonData: string) => {
},
}),
zkEvmRpcUrl: 'https://rpc.dev.immutable.com',
relayerUrl: 'https://api.dev.immutable.com/relayer-mr',
relayerUrl: 'http://localhost:8073/relayer-mr',
indexerMrBasePath: 'https://api.dev.immutable.com',
orderBookMrBasePath: 'https://api.dev.immutable.com',
passportMrBasePath: 'https://api.dev.immutable.com',
passportMrBasePath: 'http://localhost:8072',
sequenceIdentityInstrumentEndpoint: 'https://next-identity.sequence-dev.app/',
sequenceProjectAccessKey: 'AQAAAAAAAAB5QznGqk9paa4EQjom09ERpJs',
sequenceGuardEndpoint: 'https://guard.sequence.app',
},
};
} else {
Expand Down Expand Up @@ -606,8 +638,11 @@ window.callFunction = async (jsonData: string) => {
break;
}
case PASSPORT_FUNCTIONS.zkEvm.connectEvm: {
const zkEvmProvider = await getPassportClient().connectEvm();
const providerSet = setZkEvmProvider(zkEvmProvider);
const request = JSON.parse(data);
console.log(`Connecting to EVM chain: ${request.chain}`);

const zkEvmProvider = await getPassportClient().connectEvm({chain: request.chain});
const providerSet = setEvmProvider(zkEvmProvider);

if (!providerSet) {
throw new Error('Failed to connect to EVM');
Expand All @@ -626,7 +661,7 @@ window.callFunction = async (jsonData: string) => {
}
case PASSPORT_FUNCTIONS.zkEvm.sendTransaction: {
const transaction = JSON.parse(data);
const transactionHash = await getZkEvmProvider().request({
const transactionHash = await getEvmProvider().request({
method: 'eth_sendTransaction',
params: [transaction],
});
Expand All @@ -652,7 +687,7 @@ window.callFunction = async (jsonData: string) => {
}
case PASSPORT_FUNCTIONS.zkEvm.sendTransactionWithConfirmation: {
const transaction = JSON.parse(data);
const zkEvmProvider = getZkEvmProvider();
const zkEvmProvider = getEvmProvider();
const browserProvider = new BrowserProvider(zkEvmProvider);
const signer = await browserProvider.getSigner();

Expand All @@ -676,10 +711,10 @@ window.callFunction = async (jsonData: string) => {
}
case PASSPORT_FUNCTIONS.zkEvm.signTypedDataV4: {
const payload = JSON.parse(data);
const [address] = await getZkEvmProvider().request({
const [address] = await getEvmProvider().request({
method: 'eth_requestAccounts',
});
const signature = await getZkEvmProvider().request({
const signature = await getEvmProvider().request({
method: 'eth_signTypedData_v4',
params: [address, payload],
});
Expand All @@ -703,7 +738,7 @@ window.callFunction = async (jsonData: string) => {
break;
}
case PASSPORT_FUNCTIONS.zkEvm.requestAccounts: {
const result = await getZkEvmProvider().request({
const result = await getEvmProvider().request({
method: 'eth_requestAccounts',
});
const success = result !== null && result !== undefined;
Expand All @@ -724,7 +759,7 @@ window.callFunction = async (jsonData: string) => {
}
case PASSPORT_FUNCTIONS.zkEvm.getBalance: {
const request = JSON.parse(data);
const result = await getZkEvmProvider().request({
const result = await getEvmProvider().request({
method: 'eth_getBalance',
params: [request.address, request.blockNumberOrTag],
});
Expand All @@ -746,7 +781,7 @@ window.callFunction = async (jsonData: string) => {
}
case PASSPORT_FUNCTIONS.zkEvm.getTransactionReceipt: {
const request = JSON.parse(data);
const response = await getZkEvmProvider().request({
const response = await getEvmProvider().request({
method: 'eth_getTransactionReceipt',
params: [request.txHash],
});
Expand Down
4 changes: 2 additions & 2 deletions packages/internal/generated-clients/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from '../imx';

// eslint-disable-next-line @typescript-eslint/naming-convention
const defaultHeaders = { 'x-sdk-version': 'ts-immutable-sdk-__SDK_VERSION__' };
const defaultHeaders = { 'x-sdk-version': 'ts-immutable-sdk-1.0.0' };

/**
* Configuration for generated clients
Expand Down Expand Up @@ -78,7 +78,7 @@ export const multiRollupConfig = {
basePath: 'https://api.sandbox.immutable.com',
}),
passport: createConfig({
basePath: 'https://api.sandbox.immutable.com',
basePath: 'http://localhost:8072',
}),
}),
};
6 changes: 4 additions & 2 deletions packages/internal/generated-clients/src/mr-api-clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
PassportProfileApi,
GuardianApi,
} from './multi-rollup';
import { MultiRollupAPIConfiguration } from './config';
import { createConfig, MultiRollupAPIConfiguration } from './config';

export class MultiRollupApiClients {
public config: MultiRollupAPIConfiguration;
Expand Down Expand Up @@ -42,6 +42,8 @@ export class MultiRollupApiClients {
this.ordersApi = new OrdersApi(config.orderBook);
this.passportApi = new PassportApi(config.passport);
this.passportProfileApi = new PassportProfileApi(config.passport);
this.guardianApi = new GuardianApi(config.passport);
this.guardianApi = new GuardianApi(createConfig({
basePath: 'http://localhost:8074',
}));
}
}
Loading