chore: sync submodule state (parent ref update)

Made-with: Cursor
This commit is contained in:
defiQUG
2026-03-02 12:14:09 -08:00
parent 50ab378da9
commit 5efe36b1e0
1100 changed files with 155024 additions and 8674 deletions

View File

@@ -0,0 +1,94 @@
/**
* Tezos relay: listen TezosBridgeInitiated -> (mock) Tezos mint/transfer -> confirmTransaction.
*/
import { ethers } from 'ethers';
import { config } from './config.js';
import { TezosAdapterABI } from './abis.js';
import * as metrics from './metrics.js';
export class TezosRelayService {
constructor(logger) {
this.logger = logger;
this.provider = null;
this.adapter = null;
this.signer = null;
this.queue = [];
this.inFlight = 0;
}
async start() {
if (!config.tezosAdapterAddress) {
throw new Error('TEZOS_ADAPTER_ADDRESS required');
}
if (!config.oraclePrivateKey) {
throw new Error('TEZOS_RELAY_ORACLE_KEY or PRIVATE_KEY required');
}
this.provider = new ethers.JsonRpcProvider(config.sourceChain.rpcUrl);
this.signer = new ethers.Wallet(config.oraclePrivateKey, this.provider);
this.adapter = new ethers.Contract(config.tezosAdapterAddress, TezosAdapterABI, this.signer);
this.logger.info('Tezos relay started', { adapter: config.tezosAdapterAddress });
this.adapter.on('TezosBridgeInitiated', (requestId, sender, token, amount, destination) => {
this.queue.push({ requestId, sender, token, amount, destination });
metrics.incrementEventsDetected();
metrics.setPendingRequests(this.queue.length + this.inFlight);
this.processQueue();
});
}
async processQueue() {
while (this.queue.length > 0 && this.inFlight < config.maxConcurrent) {
const item = this.queue.shift();
this.inFlight++;
metrics.setPendingRequests(this.queue.length + this.inFlight);
this.handleRequest(item).finally(() => {
this.inFlight--;
metrics.setPendingRequests(this.queue.length + this.inFlight);
});
}
}
async handleRequest({ requestId, sender, token, amount, destination }) {
try {
let tezosTxHash;
if (config.mockTezosRelay) {
tezosTxHash = `mock_${requestId.slice(0, 10)}_${Date.now()}`;
this.logger.info('Mock Tezos tx', { requestId, destination, tezosTxHash });
} else {
tezosTxHash = await this.performTezosMintOrTransfer(requestId, sender, token, amount, destination);
}
await this.adapter.confirmTransaction(requestId, tezosTxHash);
metrics.incrementConfirmationsSubmitted();
} catch (err) {
this.logger.error('confirmTransaction failed', { requestId, error: err.message });
metrics.incrementConfirmationsFailed();
}
}
/**
* Perform actual Tezos mint/transfer via Taquito or Tezos RPC.
* Real mint: set MOCK_TEZOS_RELAY=false, TEZOS_MINTER_ADDRESS, TEZOS_RPC_URL, TEZOS_ORACLE_SECRET_KEY (edsk...).
* When @taquito/taquito is installed and config is set, calls minter contract mintOrTransfer(destination, amount); otherwise returns mock hash.
*/
async performTezosMintOrTransfer(requestId, sender, token, amount, destination) {
const { config } = await import('./config.js');
if (!config.tezosRpcUrl) {
return `mock_${requestId.slice(0, 10)}_${Date.now()}`;
}
try {
const { Tezos } = await import('@taquito/taquito');
const { InMemorySigner } = await import('@taquito/signer');
const tezosSecret = process.env.TEZOS_ORACLE_SECRET_KEY || config.oraclePrivateKey;
if (config.tezosMinterAddress && tezosSecret) {
Tezos.setProvider({ rpc: config.tezosRpcUrl });
Tezos.setSignerProvider(await InMemorySigner.fromSecretKey(tezosSecret));
const contract = await Tezos.wallet.at(config.tezosMinterAddress);
const op = await contract.methods.mintOrTransfer(destination, amount.toString()).send();
await op.confirmation(1);
return op.hash;
}
} catch (e) {
this.logger.warn('Taquito mint/transfer failed, using mock hash', { error: e.message });
}
return `mock_${requestId.slice(0, 10)}_${Date.now()}`;
}
}

View File

@@ -0,0 +1,5 @@
export const TezosAdapterABI = [
'event TezosBridgeInitiated(bytes32 indexed requestId, address indexed sender, address indexed token, uint256 amount, string destination)',
'function confirmTransaction(bytes32 requestId, string calldata txHash) external',
'function getBridgeStatus(bytes32 requestId) view returns (tuple(bytes32 requestId, address sender, address token, uint256 amount, bytes destinationData, uint8 status, uint256 createdAt, uint256 completedAt))',
];

View File

@@ -0,0 +1,22 @@
import dotenv from 'dotenv';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// Load PRIVATE_KEY from dotenv: smom-dbis-138/.env then service .env
dotenv.config({ path: path.resolve(__dirname, '../../.env') });
dotenv.config({ path: path.resolve(__dirname, '../.env') });
const cwd = process.cwd();
dotenv.config({ path: path.resolve(cwd, 'smom-dbis-138/.env') });
dotenv.config({ path: path.resolve(cwd, '.env') });
export const config = {
sourceChain: { chainId: 138, rpcUrl: process.env.RPC_URL_138 || process.env.RPC_URL || 'http://127.0.0.1:8545' },
tezosAdapterAddress: process.env.TEZOS_ADAPTER_ADDRESS || '',
tezosRpcUrl: process.env.TEZOS_RPC_URL || 'https://mainnet.smartpy.io',
tezosMinterAddress: process.env.TEZOS_MINTER_ADDRESS || '',
oraclePrivateKey: process.env.TEZOS_RELAY_ORACLE_KEY || process.env.PRIVATE_KEY,
pollIntervalMs: parseInt(process.env.POLL_INTERVAL_MS || '5000', 10),
maxConcurrent: parseInt(process.env.TEZOS_RELAY_MAX_CONCURRENT || '5', 10),
mockTezosRelay: process.env.MOCK_TEZOS_RELAY === 'true',
};

View File

@@ -0,0 +1,11 @@
export const metrics = {
tezos_relay_events_detected_total: 0,
tezos_relay_confirmations_submitted_total: 0,
tezos_relay_confirmations_failed_total: 0,
tezos_relay_pending_requests: 0,
};
export function incrementEventsDetected() { metrics.tezos_relay_events_detected_total++; }
export function incrementConfirmationsSubmitted() { metrics.tezos_relay_confirmations_submitted_total++; }
export function incrementConfirmationsFailed() { metrics.tezos_relay_confirmations_failed_total++; }
export function setPendingRequests(n) { metrics.tezos_relay_pending_requests = n; }
export function getMetrics() { return { ...metrics }; }