UNPKG

@nori-zk/mina-token-bridge

Version:

Nori ethereum state settelment and nETH token bridge zkApp

232 lines 13.6 kB
var _NoriTokenBridgeSubmitter_instances, _NoriTokenBridgeSubmitter_zkApp, _NoriTokenBridgeSubmitter_senderPrivateKey, _NoriTokenBridgeSubmitter_possibleTokenBridgePrivateKey, _NoriTokenBridgeSubmitter_network, _NoriTokenBridgeSubmitter_txFee, _NoriTokenBridgeSubmitter_testMode, _NoriTokenBridgeSubmitter_noriTokenBridgeVerificationKey_get; import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib"; import 'dotenv/config'; import { AccountUpdate, Bool, Field, Mina, PrivateKey, PublicKey, UInt8, fetchAccount, } from 'o1js'; import { Logger } from 'esm-iso-logger'; import { NoriTokenBridge } from './NoriTokenBridge.js'; import { NoriStorageInterface } from './NoriStorageInterface.js'; import { FungibleToken } from './TokenBase.js'; import { EthInput, decodeConsensusMptProof, Bytes32FieldPair, NodeProofLeft, compileAndOptionallyVerifyContracts, bridgeHeadNoriSP1HeliosProgramPi0, proofConversionSP1ToPlonkPO2, } from '@nori-zk/o1js-zk-utils'; import { cacheFactory } from '@nori-zk/o1js-zk-utils/node'; import { FrC, } from '@nori-zk/proof-conversion/min'; import { noriTokenBridgeVkHash } from './integrity/NoriTokenBridge.VkHash.js'; import { noriStorageInterfaceVkHash } from './integrity/NoriStorageInterface.VkHash.js'; import { fungibleTokenVkHash } from './integrity/FungibleToken.VkHash.js'; const logger = new Logger('NoriTokenBridgeSubmitter'); export class NoriTokenBridgeSubmitter { constructor(cache = undefined) { _NoriTokenBridgeSubmitter_instances.add(this); this.cache = cache; _NoriTokenBridgeSubmitter_zkApp.set(this, void 0); _NoriTokenBridgeSubmitter_senderPrivateKey.set(this, void 0); _NoriTokenBridgeSubmitter_possibleTokenBridgePrivateKey.set(this, void 0); _NoriTokenBridgeSubmitter_network.set(this, void 0); _NoriTokenBridgeSubmitter_txFee.set(this, void 0); _NoriTokenBridgeSubmitter_testMode.set(this, void 0); void __classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_testMode, "f"); logger.info(`NoriTokenBridgeSubmitter constructor called.`); const errors = []; const possibleSenderPrivateKeyBase58 = process.env .MINA_SENDER_PRIVATE_KEY; const possibleNetwork = process.env.MINA_NETWORK; const possibleNetworkUrl = process.env.MINA_RPC_NETWORK_URL; const possibleArchiveUrl = process.env.MINA_ARCHIVE_RPC_URL; if (!possibleSenderPrivateKeyBase58) errors.push('MINA_SENDER_PRIVATE_KEY is required'); if (!possibleNetwork) { errors.push('MINA_NETWORK is required'); } else if (!['devnet', 'mainnet', 'lightnet'].includes(possibleNetwork)) { errors.push(`MINA_NETWORK must be one of: devnet, mainnet, lightnet (got "${possibleNetwork}")`); } else { __classPrivateFieldSet(this, _NoriTokenBridgeSubmitter_network, possibleNetwork, "f"); } if (!possibleNetworkUrl) errors.push('MINA_RPC_NETWORK_URL is required'); if (!possibleArchiveUrl) errors.push('MINA_ARCHIVE_RPC_URL is required'); const isLightnet = possibleNetwork === 'lightnet'; const possibleTokenBridgePrivateKeyBase58 = process.env .NORI_MINA_TOKEN_BRIDGE_PRIVATE_KEY; const possibleTokenBridgeAddressBase58 = process.env .NORI_MINA_TOKEN_BRIDGE_ADDRESS; if (isLightnet) { if (!possibleTokenBridgePrivateKeyBase58) errors.push('NORI_MINA_TOKEN_BRIDGE_PRIVATE_KEY is required in lightnet mode'); } else { if (!possibleTokenBridgeAddressBase58) errors.push('NORI_MINA_TOKEN_BRIDGE_ADDRESS is required'); } if (errors.length > 0) { throw `Configuration errors:\n- ${errors.join('\n- ')}`; } __classPrivateFieldSet(this, _NoriTokenBridgeSubmitter_senderPrivateKey, PrivateKey.fromBase58(possibleSenderPrivateKeyBase58), "f"); __classPrivateFieldSet(this, _NoriTokenBridgeSubmitter_txFee, Number(process.env.MINA_TX_FEE || 0.1) * 1e9, "f"); __classPrivateFieldSet(this, _NoriTokenBridgeSubmitter_testMode, isLightnet, "f"); this.minaRPCNetworkUrl = possibleNetworkUrl; this.minaArchiveRPCUrl = possibleArchiveUrl; if (isLightnet) { __classPrivateFieldSet(this, _NoriTokenBridgeSubmitter_possibleTokenBridgePrivateKey, PrivateKey.fromBase58(possibleTokenBridgePrivateKeyBase58), "f"); __classPrivateFieldSet(this, _NoriTokenBridgeSubmitter_zkApp, new NoriTokenBridge(__classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_possibleTokenBridgePrivateKey, "f").toPublicKey()), "f"); } else { __classPrivateFieldSet(this, _NoriTokenBridgeSubmitter_possibleTokenBridgePrivateKey, undefined, "f"); __classPrivateFieldSet(this, _NoriTokenBridgeSubmitter_zkApp, new NoriTokenBridge(PublicKey.fromBase58(possibleTokenBridgeAddressBase58)), "f"); } logger.log('Loaded constants from: .env'); } async networkSetUp() { logger.log(`Setting up ${__classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_network, "f")} network with RPC endpoint: '${this.minaRPCNetworkUrl}' and archive endpoint: '${this.minaArchiveRPCUrl}'.`); const networkId = __classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_network, "f") === 'mainnet' ? 'mainnet' : 'testnet'; const Network = Mina.Network({ networkId, mina: this.minaRPCNetworkUrl, archive: this.minaArchiveRPCUrl, }); Mina.setActiveInstance(Network); logger.log('Finished Mina network setup.'); } async compileContracts() { const fileSystemCache = this.cache ? await cacheFactory(this.cache) : undefined; const { NoriStorageInterfaceVerificationKey, FungibleTokenVerificationKey, NoriTokenBridgeVerificationKey, } = await compileAndOptionallyVerifyContracts(logger, [ { name: 'NoriStorageInterface', program: NoriStorageInterface, integrityHash: noriStorageInterfaceVkHash, }, { name: 'FungibleToken', program: FungibleToken, integrityHash: fungibleTokenVkHash, }, { name: 'NoriTokenBridge', program: NoriTokenBridge, integrityHash: noriTokenBridgeVkHash, }, ], fileSystemCache); Object.defineProperty(this, 'noriStorageInterfaceVerificationKey', { value: NoriStorageInterfaceVerificationKey, writable: false, configurable: false, enumerable: true, }); Object.defineProperty(this, 'noriTokenBridgeVerificationKey', { value: NoriTokenBridgeVerificationKey, writable: false, configurable: false, enumerable: true, }); void FungibleTokenVerificationKey; } async deployContract(storeHash, ethTokenBridgeAddress, genesisRoot) { if (__classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_network, "f") !== 'lightnet') { throw new Error([ `Deploy is only supported in test mode, test mode was set to 'false'. Test mode is only possible when the configured network is 'lightnet' and the configured network is '${__classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_network, "f")}'.`, `Please see the README.md within the 'contracts/mina' workspace of the 'nori-bridge-sdk' repository and use the deploy script 'npm run deploy <storeHash>' instead of this method.`, ].join('\n')); } logger.log('Creating deploy transaction.'); const noriHeliosProgramPi0 = FrC.from(bridgeHeadNoriSP1HeliosProgramPi0); const proofConversionPO2 = Field.from(proofConversionSP1ToPlonkPO2); const senderPublicKey = __classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_senderPrivateKey, "f").toPublicKey(); const initialStoreHash = Bytes32FieldPair.fromBytes32(storeHash); const tokenBasePrivateKey = PrivateKey.random(); const tokenBaseAddress = tokenBasePrivateKey.toPublicKey(); const tokenBase = new FungibleToken(tokenBaseAddress); const deployTx = await Mina.transaction({ sender: senderPublicKey, fee: __classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_txFee, "f") }, async () => { AccountUpdate.fundNewAccount(senderPublicKey, 3); logger.log(`Deploying NoriTokenBridge with verification key hash: '${__classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_instances, "a", _NoriTokenBridgeSubmitter_noriTokenBridgeVerificationKey_get).hash}'`); await __classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_zkApp, "f").deploy({ verificationKey: __classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_instances, "a", _NoriTokenBridgeSubmitter_noriTokenBridgeVerificationKey_get), adminPublicKey: senderPublicKey, tokenBaseAddress, storageVKHash: this.noriStorageInterfaceVerificationKey.hash, newStoreHash: initialStoreHash, ethTokenBridgeAddress, noriHeliosProgramPi0, proofConversionPO2, genesisRoot, }); await tokenBase.deploy({ symbol: 'nETH', src: 'https://github.com/2nori/nori-bridge-sdk', allowUpdates: true, }); await tokenBase.initialize(__classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_possibleTokenBridgePrivateKey, "f").toPublicKey(), UInt8.from(6), Bool(false)); }); logger.log('Deploy transaction created successfully. Proving...'); await deployTx.prove(); logger.log('Transaction proved. Signing and sending the transaction...'); await deployTx .sign([ __classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_senderPrivateKey, "f"), __classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_possibleTokenBridgePrivateKey, "f"), tokenBasePrivateKey, ]) .send() .wait(); logger.log('NoriTokenBridge and FungibleToken deployed successfully.'); } async createProof(proofArguments) { try { logger.log('Creating proof.'); const { sp1PlonkProof, conversionOutputProof } = proofArguments; const rawProof = await NodeProofLeft.fromJSON(conversionOutputProof.proofData); logger.log('Decoding converted proof and creating verification inputs.'); const ethInput = new EthInput(decodeConsensusMptProof(sp1PlonkProof)); logger.log('Proof arguments decoded successfully.'); return { ethInput, rawProof }; } catch (err) { logger.error(`Error creating proof: ${String(err)}`); throw err; } } async submit({ ethInput, rawProof }) { logger.log('Submitting a proof.'); try { await fetchAccount({ publicKey: __classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_zkApp, "f").address }); await fetchAccount({ publicKey: __classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_senderPrivateKey, "f").toPublicKey(), }); logger.log('Fetched accounts.'); logger.log('Creating update transaction.'); const updateTx = await Mina.transaction({ sender: __classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_senderPrivateKey, "f").toPublicKey(), fee: __classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_txFee, "f"), memo: `State for slot ${ethInput.outputSlot.toString()} set`, }, async () => { await __classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_zkApp, "f").update(ethInput, rawProof); }); await updateTx.prove(); logger.log('Transaction proven.'); const tx = await updateTx.sign([__classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_senderPrivateKey, "f")]).send(); logger.log(`Transaction sent to '${__classPrivateFieldGet(this, _NoriTokenBridgeSubmitter_network, "f")}'.`); if (!tx.data) { throw new Error('Transaction data is undefined'); } const txId = tx.data.sendZkapp.zkapp.id; const txHash = tx.data.sendZkapp.zkapp.hash; if (!txId) { throw new Error('txId is undefined'); } return { txId, txHash, }; } catch (err) { logger.error(`Error submitting proof: ${String(err)}`); throw err; } } } _NoriTokenBridgeSubmitter_zkApp = new WeakMap(), _NoriTokenBridgeSubmitter_senderPrivateKey = new WeakMap(), _NoriTokenBridgeSubmitter_possibleTokenBridgePrivateKey = new WeakMap(), _NoriTokenBridgeSubmitter_network = new WeakMap(), _NoriTokenBridgeSubmitter_txFee = new WeakMap(), _NoriTokenBridgeSubmitter_testMode = new WeakMap(), _NoriTokenBridgeSubmitter_instances = new WeakSet(), _NoriTokenBridgeSubmitter_noriTokenBridgeVerificationKey_get = function _NoriTokenBridgeSubmitter_noriTokenBridgeVerificationKey_get() { return this.noriTokenBridgeVerificationKey; }; //# sourceMappingURL=proofSubmitter.js.map