UNPKG

@nori-zk/mina-token-bridge

Version:

A Mina zk-program contract allowing users to mint tokens on Nori Bridge.

331 lines 21.1 kB
var _NoriTokenControllerSubmitter_instances, _NoriTokenControllerSubmitter_senderPrivateKey, _NoriTokenControllerSubmitter_network, _NoriTokenControllerSubmitter_txFee, _NoriTokenControllerSubmitter_noriTokenController, _NoriTokenControllerSubmitter_tokenBase, _NoriTokenControllerSubmitter_noriTokenControllerPrivateKey, _NoriTokenControllerSubmitter_tokenBasePrivateKey, _NoriTokenControllerSubmitter_adminPublicKey, _NoriTokenControllerSubmitter_ethProcessorAddress, _NoriTokenControllerSubmitter_mock, _NoriTokenControllerSubmitter_cache, _NoriTokenControllerSubmitter_compilePrerequisites, _NoriTokenControllerSubmitter_isMintProofData; import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib"; import 'dotenv/config'; import { AccountUpdate, Mina, PrivateKey, PublicKey, fetchAccount, UInt8, Bool, Cache, } from 'o1js'; import { FungibleToken } from './TokenBase.js'; import { NoriStorageInterface } from './NoriStorageInterface.js'; /*import { MockNoriTokenController, MockConsenusProof, MockDepositAttesterProof, MockMinaAttestationProof, MockMintProofData, } from './NoriTokenControllerMock.js';*/ import { ContractDepositAttestor } from '@nori-zk/o1js-zk-utils'; import { EthVerifier } from '@nori-zk/o1js-zk-utils'; import { EthDepositProgram } from './e2ePrerequisites.js'; import { NoriTokenController } from './NoriTokenController.js'; import { compileEcdsaEthereum, compileEcdsaSigPresentationVerifier, } from './credentialAttestation.js'; export class NoriTokenControllerSubmitter { constructor(config) { _NoriTokenControllerSubmitter_instances.add(this); _NoriTokenControllerSubmitter_senderPrivateKey.set(this, void 0); _NoriTokenControllerSubmitter_network.set(this, void 0); _NoriTokenControllerSubmitter_txFee.set(this, void 0); // Contract instances _NoriTokenControllerSubmitter_noriTokenController.set(this, void 0); // MockNoriTokenController _NoriTokenControllerSubmitter_tokenBase.set(this, void 0); // Optional private keys for deployment _NoriTokenControllerSubmitter_noriTokenControllerPrivateKey.set(this, void 0); _NoriTokenControllerSubmitter_tokenBasePrivateKey.set(this, void 0); _NoriTokenControllerSubmitter_adminPublicKey.set(this, void 0); _NoriTokenControllerSubmitter_ethProcessorAddress.set(this, void 0); _NoriTokenControllerSubmitter_mock.set(this, void 0); _NoriTokenControllerSubmitter_cache.set(this, Cache.FileSystem('./cache')); console.log(`🛠 NoriTokenControllerSubmitter constructor called!`); const errors = []; // Validate required config if (!config.senderPrivateKey) { errors.push('senderPrivateKey is required'); } if (!config.network) { errors.push('network is required'); } if (!config.networkUrl) { errors.push('networkUrl is required'); } // For deployment, we need additional keys const isDeployment = !config.noriTokenControllerAddress || !config.tokenBaseAddress; if (isDeployment) { if (!config.noriTokenControllerPrivateKey) { errors.push('noriTokenControllerPrivateKey is required for deployment'); } if (!config.tokenBasePrivateKey) { errors.push('tokenBasePrivateKey is required for deployment'); } if (!config.adminPublicKey) { errors.push('adminPublicKey is required for deployment'); } // if (!config.ethProcessorAddress) { //TODO enable when needed // errors.push('ethProcessorAddress is required for deployment'); // } } if (errors.length > 0) { throw new Error(`Configuration errors:\n- ${errors.join('\n- ')}`); } // Set instance variables __classPrivateFieldSet(this, _NoriTokenControllerSubmitter_senderPrivateKey, PrivateKey.fromBase58(config.senderPrivateKey), "f"); __classPrivateFieldSet(this, _NoriTokenControllerSubmitter_network, config.network, "f"); __classPrivateFieldSet(this, _NoriTokenControllerSubmitter_txFee, (config.txFee || 0.1) * 1e9, "f"); this.minaRPCNetworkUrl = config.networkUrl; // Set deployment keys if provided if (config.noriTokenControllerPrivateKey) { __classPrivateFieldSet(this, _NoriTokenControllerSubmitter_noriTokenControllerPrivateKey, PrivateKey.fromBase58(config.noriTokenControllerPrivateKey), "f"); } if (config.tokenBasePrivateKey) { __classPrivateFieldSet(this, _NoriTokenControllerSubmitter_tokenBasePrivateKey, PrivateKey.fromBase58(config.tokenBasePrivateKey), "f"); } if (config.adminPublicKey) { __classPrivateFieldSet(this, _NoriTokenControllerSubmitter_adminPublicKey, PublicKey.fromBase58(config.adminPublicKey), "f"); } if (config.ethProcessorAddress) { __classPrivateFieldSet(this, _NoriTokenControllerSubmitter_ethProcessorAddress, PublicKey.fromBase58(config.ethProcessorAddress), "f"); } // Initialize contract instances const noriAddress = config.noriTokenControllerAddress ? PublicKey.fromBase58(config.noriTokenControllerAddress) : __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenControllerPrivateKey, "f").toPublicKey(); const tokenAddress = config.tokenBaseAddress ? PublicKey.fromBase58(config.tokenBaseAddress) : __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_tokenBasePrivateKey, "f").toPublicKey(); __classPrivateFieldSet(this, _NoriTokenControllerSubmitter_mock, !!config.mock || false, "f"); console.log('this.#mock', __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_mock, "f")); console.log('this.#mock', __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_mock, "f"), __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_mock, "f") ? 'selecting mock' : 'selecting real'); __classPrivateFieldSet(this, _NoriTokenControllerSubmitter_noriTokenController, /*this.#mock ? new MockNoriTokenController(noriAddress) :*/ new NoriTokenController(noriAddress), "f"); __classPrivateFieldSet(this, _NoriTokenControllerSubmitter_tokenBase, new FungibleToken(tokenAddress), "f"); console.log('NoriTokenControllerSubmitter initialized successfully'); } async networkSetUp() { console.log(`Setting up ${__classPrivateFieldGet(this, _NoriTokenControllerSubmitter_network, "f")} network with RPC endpoint: '${this.minaRPCNetworkUrl}'.`); const Network = Mina.Network({ networkId: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_network, "f"), mina: this.minaRPCNetworkUrl, // ...(this.#network.toString().match('localhost') && { // lightnetAccountManager: 'http://localhost:8181', // }), }); Mina.setActiveInstance(Network); console.log('Finished Mina network setup.'); } async compileContracts() { console.log('Compiling prerequisites...'); await __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_instances, "m", _NoriTokenControllerSubmitter_compilePrerequisites).call(this); console.log('Compiling contracts...'); // Compile all required contracts console.log('Compiling NoriStorageInterface...'); const storageResult = await NoriStorageInterface.compile({ cache: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_cache, "f"), }); console.log('Compiling FungibleToken...'); const tokenBaseResult = await FungibleToken.compile({ cache: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_cache, "f"), }); console.log('Compiling NoriTokenController...'); console.log('this.#mock', __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_mock, "f"), __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_mock, "f") ? 'compiling mock' : 'compiling real'); const controllerResult = /*this.#mock ? await MockNoriTokenController.compile({ cache: this.#cache, }) : */ await NoriTokenController.compile({ cache: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_cache, "f"), }); //TODO replace with compileAndVerifyContracts this.storageInterfaceVerificationKey = storageResult.verificationKey; this.tokenBaseVerificationKey = tokenBaseResult.verificationKey; this.noriTokenControllerVerificationKey = controllerResult.verificationKey; console.log('All contracts compiled successfully'); } async deployContracts(options = {}) { if (!__classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenControllerPrivateKey, "f") || !__classPrivateFieldGet(this, _NoriTokenControllerSubmitter_tokenBasePrivateKey, "f") || !__classPrivateFieldGet(this, _NoriTokenControllerSubmitter_adminPublicKey, "f")) { throw new Error('Deployment keys not provided in constructor'); } console.log('Deploying NoriTokenController and TokenBase contracts...'); const symbol = options.symbol || 'nETH'; const decimals = UInt8.from(options.decimals || 18); const allowUpdates = options.allowUpdates ?? true; const startPaused = Bool(options.startPaused ?? false); const senderPublicKey = __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_senderPrivateKey, "f").toPublicKey(); console.log('this.#mock', __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_mock, "f"), __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_mock, "f") ? 'deploying mock' : 'deploying real'); const deployTx = await Mina.transaction({ sender: senderPublicKey, fee: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_txFee, "f") }, async () => { AccountUpdate.fundNewAccount(senderPublicKey, 3); // Deploy NoriTokenController await __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenController, "f").deploy({ adminPublicKey: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_adminPublicKey, "f"), tokenBaseAddress: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_tokenBase, "f").address, storageVKHash: this.storageInterfaceVerificationKey.hash, ethProcessorAddress: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_ethProcessorAddress, "f") || PrivateKey.random().toPublicKey(), }); // Deploy TokenBase await __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_tokenBase, "f").deploy({ symbol, src: 'https://x.com/nori_zk', allowUpdates, }); // Initialize TokenBase await __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_tokenBase, "f").initialize(__classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenController, "f").address, decimals, startPaused); }); console.log('Deploy transaction created. Proving...'); await deployTx.prove(); console.log('Transaction proved. Signing and sending...'); const tx = await deployTx .sign([ __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_senderPrivateKey, "f"), __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenControllerPrivateKey, "f"), __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_tokenBasePrivateKey, "f"), ]) .send(); const result = await tx.wait(); console.log('Contracts deployed successfully'); return { noriTokenControllerAddress: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenController, "f").address.toBase58(), tokenBaseAddress: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_tokenBase, "f").address.toBase58(), txHash: result.hash, }; } async setupStorage(userPublicKey) { console.log(`Setting up storage for user: ${userPublicKey.toBase58()}`); await this.fetchAccounts([ userPublicKey, __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenController, "f").address, ]); console.log('this.#mock', __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_mock, "f"), __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_mock, "f") ? 'setup mock' : 'setup real'); const setupTx = await Mina.transaction({ sender: userPublicKey, fee: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_txFee, "f") }, async () => { AccountUpdate.fundNewAccount(userPublicKey, 1); await __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenController, "f").setUpStorage(userPublicKey, this.storageInterfaceVerificationKey); }); await setupTx.prove(); const tx = await setupTx.sign([__classPrivateFieldGet(this, _NoriTokenControllerSubmitter_senderPrivateKey, "f")]).send(); const result = await tx.wait(); console.log('Storage setup completed successfully'); return { txHash: result.hash }; } //TODO make one that returns unsigned transaction to be passed to the wallet async mint(userPublicKey, proofData, // MockMintProofData | userPrivateKey, fundNewAccount = true) { console.log(`Minting tokens for user: ${userPublicKey.toBase58()}`); await this.fetchAccounts([ userPublicKey, __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenController, "f").address, ]); console.log('this.#mock', __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_mock, "f"), __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_mock, "f") ? 'mint mock' : 'mint real'); const mintTx = await Mina.transaction({ sender: userPublicKey, fee: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_txFee, "f") }, async () => { if (fundNewAccount) { AccountUpdate.fundNewAccount(userPublicKey, 1); } /*if (this.#mock) { const mockNoriTokenController = this .#noriTokenController as MockNoriTokenController; const mockProofData = proofData as MockMintProofData; await mockNoriTokenController.noriMint( mockProofData.ethConsensusProof, mockProofData.depositAttesterProof, mockProofData.minaAttestationProof ); } else {*/ const noriTokenController = __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenController, "f"); const realProofData = proofData; await noriTokenController.noriMint(realProofData.ethDepositProof, realProofData.presentationProof); //} }); await mintTx.prove(); const tx = await mintTx .sign([__classPrivateFieldGet(this, _NoriTokenControllerSubmitter_senderPrivateKey, "f"), userPrivateKey]) .send(); const result = await tx.wait(); // Fetch updated balance await fetchAccount({ publicKey: userPublicKey, tokenId: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_tokenBase, "f").deriveTokenId(), }); const balance = await __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_tokenBase, "f").getBalanceOf(userPublicKey); console.log('Minting completed successfully'); //if (this.#isMintProofData(proofData)) { return { txHash: result.hash, mintedAmount: proofData.ethDepositProof.publicOutput.totalLocked.toString(), userBalance: balance.toString(), }; /*} else { return { txHash: result.hash, mintedAmount: proofData.depositAttesterProof?.lockedSoFar.toString(), userBalance: balance.toString(), }; }*/ } async getUserBalance(userPublicKey) { await fetchAccount({ publicKey: userPublicKey, tokenId: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_tokenBase, "f").deriveTokenId(), }); return __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_tokenBase, "f").getBalanceOf(userPublicKey); } async getUserStorageInfo(userPublicKey) { const storage = new NoriStorageInterface(userPublicKey, __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenController, "f").deriveTokenId()); await fetchAccount({ publicKey: userPublicKey, tokenId: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenController, "f").deriveTokenId(), }); const userKeyHash = await storage.userKeyHash.fetch(); const mintedSoFar = await storage.mintedSoFar.fetch(); return { userKeyHash, mintedSoFar }; } // Getters for contract addresses get noriTokenControllerAddress() { return __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenController, "f").address.toBase58(); } get tokenBaseAddress() { return __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_tokenBase, "f").address.toBase58(); } get contracts() { return { noriTokenController: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_noriTokenController, "f"), tokenBase: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_tokenBase, "f"), }; } async fetchAccounts(accounts) { await Promise.all(accounts.map((addr) => fetchAccount({ publicKey: addr }))); } } _NoriTokenControllerSubmitter_senderPrivateKey = new WeakMap(), _NoriTokenControllerSubmitter_network = new WeakMap(), _NoriTokenControllerSubmitter_txFee = new WeakMap(), _NoriTokenControllerSubmitter_noriTokenController = new WeakMap(), _NoriTokenControllerSubmitter_tokenBase = new WeakMap(), _NoriTokenControllerSubmitter_noriTokenControllerPrivateKey = new WeakMap(), _NoriTokenControllerSubmitter_tokenBasePrivateKey = new WeakMap(), _NoriTokenControllerSubmitter_adminPublicKey = new WeakMap(), _NoriTokenControllerSubmitter_ethProcessorAddress = new WeakMap(), _NoriTokenControllerSubmitter_mock = new WeakMap(), _NoriTokenControllerSubmitter_cache = new WeakMap(), _NoriTokenControllerSubmitter_instances = new WeakSet(), _NoriTokenControllerSubmitter_compilePrerequisites = async function _NoriTokenControllerSubmitter_compilePrerequisites() { if (__classPrivateFieldGet(this, _NoriTokenControllerSubmitter_mock, "f")) return; // Compile programs / contracts console.time('compileEcdsaEthereum'); await compileEcdsaEthereum(__classPrivateFieldGet(this, _NoriTokenControllerSubmitter_cache, "f")); console.timeEnd('compileEcdsaEthereum'); // 1:20.330 (m:ss.mmm) console.time('compilePresentationVerifier'); await compileEcdsaSigPresentationVerifier(__classPrivateFieldGet(this, _NoriTokenControllerSubmitter_cache, "f")); console.timeEnd('compilePresentationVerifier'); // 11.507s console.time('ContractDepositAttestor compile'); const { verificationKey: contractDepositAttestorVerificationKey } = await ContractDepositAttestor.compile({ cache: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_cache, "f"), forceRecompile: true, }); console.timeEnd('ContractDepositAttestor compile'); console.log(`ContractDepositAttestor contract compiled vk: '${contractDepositAttestorVerificationKey.hash}'.`); console.time('EthVerifier compile'); const { verificationKey: ethVerifierVerificationKey } = await EthVerifier.compile({ cache: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_cache, "f"), forceRecompile: true, }); console.timeEnd('EthVerifier compile'); console.log(`EthVerifier compiled vk: '${ethVerifierVerificationKey.hash}'.`); console.time('EthDepositProgram compile'); const { verificationKey: EthDepositProgramVerificationKey } = await EthDepositProgram.compile({ cache: __classPrivateFieldGet(this, _NoriTokenControllerSubmitter_cache, "f"), forceRecompile: true, }); console.timeEnd('EthDepositProgram compile'); console.log(`EthDepositProgram compiled vk: '${EthDepositProgramVerificationKey.hash}'.`); }, _NoriTokenControllerSubmitter_isMintProofData = function _NoriTokenControllerSubmitter_isMintProofData(obj) { return 'ethDepositProof' in obj && 'presentationProof' in obj; }; //# sourceMappingURL=NoriControllerSubmitter.js.map