@nori-zk/mina-token-bridge
Version:
Nori ethereum state settelment and nETH token bridge zkApp
122 lines • 5.26 kB
JavaScript
// Shared utilities for admin bin scripts that follow the
// validate → compile → transact → wait pattern.
import { Mina, PrivateKey, fetchAccount } from 'o1js';
import { NoriTokenBridge } from '../../NoriTokenBridge.js';
import { NoriStorageInterface } from '../../NoriStorageInterface.js';
import { FungibleToken } from '../../TokenBase.js';
import { compileAndVerifyContracts } from '@nori-zk/o1js-zk-utils';
import { noriTokenBridgeVkHash } from '../../integrity/NoriTokenBridge.VkHash.js';
import { noriStorageInterfaceVkHash } from '../../integrity/NoriStorageInterface.VkHash.js';
import { fungibleTokenVkHash } from '../../integrity/FungibleToken.VkHash.js';
/**
* Parse and validate the env vars common to all admin bin scripts.
* `extraValidations` is called to collect script-specific issues.
* Exits the process if any issues are found.
*/
export function parseAdminBinEnv(logger, scriptName, extraValidations) {
const possibleNetworkUrl = process.env.MINA_RPC_NETWORK_URL;
const possibleNetwork = process.env.MINA_NETWORK;
const possibleAdminKeyBase58 = process.env.MINA_SENDER_PRIVATE_KEY;
const possibleTokenBridgeKeyBase58 = process.env.NORI_MINA_TOKEN_BRIDGE_PRIVATE_KEY;
const fee = Number(process.env.MINA_TX_FEE || 0.1) * 1e9;
const issues = [];
if (!possibleNetworkUrl)
issues.push('Missing required env: MINA_RPC_NETWORK_URL');
if (!possibleNetwork)
issues.push('Missing required env: MINA_NETWORK');
if (!possibleAdminKeyBase58)
issues.push('Missing required env: MINA_SENDER_PRIVATE_KEY (must be the contract admin private key)');
if (!possibleTokenBridgeKeyBase58)
issues.push('Missing required env: NORI_MINA_TOKEN_BRIDGE_PRIVATE_KEY');
let possibleAdminKey;
if (possibleAdminKeyBase58) {
try {
possibleAdminKey = PrivateKey.fromBase58(possibleAdminKeyBase58);
}
catch (e) {
issues.push(`MINA_SENDER_PRIVATE_KEY (contract admin) is not a valid private key: ${e.message}`);
}
}
let possibleTokenBridgeKey;
if (possibleTokenBridgeKeyBase58) {
try {
possibleTokenBridgeKey = PrivateKey.fromBase58(possibleTokenBridgeKeyBase58);
}
catch (e) {
issues.push(`NORI_MINA_TOKEN_BRIDGE_PRIVATE_KEY is not a valid private key: ${e.message}`);
}
}
extraValidations?.(issues);
if (issues.length) {
const formatted = [
`${scriptName} encountered issues:`,
...issues.flatMap((issue, idx) => {
const lines = issue.split('\n');
return lines.map((line, lineIdx) => lineIdx === 0 ? `\t${idx + 1}: ${line}` : `\t ${line}`);
}),
].join('\n');
logger.fatal(formatted);
process.exit(1);
}
if (possibleAdminKey === undefined ||
possibleTokenBridgeKey === undefined ||
possibleNetworkUrl === undefined ||
possibleNetwork === undefined) {
logger.fatal('Internal error: required values undefined after validation.');
process.exit(1);
}
return {
adminKey: possibleAdminKey,
tokenBridgePrivateKey: possibleTokenBridgeKey,
networkUrl: possibleNetworkUrl,
networkId: possibleNetwork === 'mainnet' ? 'mainnet' : 'testnet',
fee,
};
}
/**
* Set up the Mina network, compile contracts, and return a NoriTokenBridge
* instance bound to the token bridge address.
*/
export async function setupNetworkAndCompile(logger, config) {
const tokenBridgeAddress = config.tokenBridgePrivateKey.toPublicKey();
const adminAccount = config.adminKey.toPublicKey();
logger.log(`Admin address: '${adminAccount.toBase58()}'.`);
logger.log(`NoriTokenBridge address: '${tokenBridgeAddress.toBase58()}'.`);
const Network = Mina.Network({ networkId: config.networkId, mina: config.networkUrl });
Mina.setActiveInstance(Network);
await compileAndVerifyContracts(logger, [
{
name: 'NoriStorageInterface',
program: NoriStorageInterface,
integrityHash: noriStorageInterfaceVkHash,
},
{
name: 'FungibleToken',
program: FungibleToken,
integrityHash: fungibleTokenVkHash,
},
{
name: 'NoriTokenBridge',
program: NoriTokenBridge,
integrityHash: noriTokenBridgeVkHash,
},
]);
return new NoriTokenBridge(tokenBridgeAddress);
}
/**
* Build, prove, sign, send, and wait for an admin transaction.
*/
export async function submitAdminTx(logger, config, txBody) {
const adminAccount = config.adminKey.toPublicKey();
const tokenBridgeAddress = config.tokenBridgePrivateKey.toPublicKey();
const txn = await Mina.transaction({ fee: config.fee, sender: adminAccount }, txBody);
logger.log('Proving transaction');
await txn.prove();
const signedTx = txn.sign([config.adminKey]);
logger.log('Sending transaction...');
const pendingTx = await signedTx.send();
logger.log('Waiting for transaction to be included in a block...');
await pendingTx.wait();
await fetchAccount({ publicKey: tokenBridgeAddress });
}
//# sourceMappingURL=adminBinUtils.js.map