UNPKG

@nori-zk/mina-token-bridge

Version:

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

297 lines (210 loc) 8.98 kB
# Mina zkApp: Token Bridge A Mina zk-program contract allowing users to mint tokens on Nori Bridge. ## How to build In the repositories root directory run: ```sh npm run build ``` ## Usage ### Import workers You have several options depending on your environment and bundler setup: --- #### 1. **Use Node.js workers directly** > Only valid in a Node.js environment (e.g., backend services, CLI tools) ```typescript import { getTokenMintWorker } from '@nori-zk/mina-token-bridge/node/workers/tokenMint'; import { getCredentialAttestationWorker } from '@nori-zk/mina-token-bridge/node/workers/credentialAttestation'; ``` --- #### 2. **For the browser, import pure logic worker classes and lift them into workers manually, using a spec** > Use this if you're building your own worker pipeline (custom setup, unsupported bundler, etc.) ```typescript import { CredentialAttestationWorker, TokenMintWorker, } from '@nori-zk/mina-token-bridge/workers/defs'; ``` - You must lift these pure classes into actual workers. - You can use either: - **(a) Provided worker tooling** > Uses `WorkerParent`, `WorkerChild`, and `createParentFromSpec/createWorker` from the mina-token-bridge repo ```typescript //workers/credentialAttestation/browser/parent.ts import { CredentialAttestationWorkerSpec } from '@nori-zk/mina-token-bridge/workers/specs'; import { WorkerParent } from '@nori-zk/mina-token-bridge/browser/worker/parent'; import { createProxyFromSpec } from '@nori-zk/mina-token-bridge/worker'; const worker = new Worker(new URL('./child.ts', import.meta.url), { type: 'module', }); // workerParent has a ready function which returns a promise, that you can await, as // it can take a long time, for the worker to load. const workerParent = new WorkerParent(worker); export const getCredentialAttestationWorker = () => createProxyFromSpec(workerParent, CredentialAttestationWorkerSpec); ``` ```typescript //workers/credentialAttestation/browser/child.ts import { CredentialAttestationWorker } from '@nori-zk/mina-token-bridge/workers/defs'; import { WorkerChild } from '@nori-zk/mina-token-bridge/browser/worker/child'; import { createWorker } from '@nori-zk/mina-token-bridge/worker'; const credentialAttestationWorker = createWorker( new WorkerChild(), CredentialAttestationWorker ); ``` --- - **(b) Your own tooling (e.g., using Comlink)** > This example shows how to wire up a pure worker using [Comlink](https://github.com/GoogleChromeLabs/comlink) ```typescript //workers/credentialAttestation/child.ts import * as Comlink from 'comlink'; import { CredentialAttestationWorker } from '@nori-zk/mina-token-bridge/workers/defs'; Comlink.expose(new CredentialAttestationWorker()); ``` ```typescript //workers/credentialAttestation/parent.ts import * as Comlink from 'comlink'; import type { CredentialAttestationWorker } from '@nori-zk/mina-token-bridge/workers/defs'; const worker = new Worker(new URL('./child.ts', import.meta.url), { type: 'module' }); type CredentialAttestationWorkerInstance = InstanceType<typeof CredentialAttestationWorker>; const workerApi = Comlink.wrap<CredentialAttestationWorkerInstance>(worker); export const getCredentialAttestationWorker = () => workerApi; ``` --- ### Main imports ```typescript import { TransitionNoticeMessageType } from '@nori-zk/pts-types'; import { getReconnectingBridgeSocket$ } from '@nori-zk/mina-token-bridge/rx/socket'; import { getBridgeStateTopic$, getBridgeTimingsTopic$, getEthStateTopic$, } from '@nori-zk/mina-token-bridge/rx/topics'; import { BridgeDepositProcessingStatus, getDepositProcessingStatus$, bridgeStatusesKnownEnoughToLockUnsafe, bridgeStatusesKnownEnoughToLockSafe, getDepositProcessingStatus$, // Promise triggers resolve when key event occurs and reject after opportunity has been missed: canMint, readyToComputeMintProof, // Observable triggers: // CanMint observable: getCanMint$, // cycles through states of 'Waiting', 'ReadyToMint' and 'MissedMintingOpportunity' CanMintStatus, // CanComputeEthProof observable: getCanComputeEthProof$, // cycles through states of 'Waiting', 'CanCompute', or 'MissedMintingOpportunity' CanComputEthProof, } from '@nori-zk/mina-token-bridge/rx/deposit'; import { FungibleToken, NoriStorageInterface, NoriTokenController, signSecretWithEthWallet } from '@nori-zk/mina-token-bridge'; // Import your worker getter function here to support minting, e.g.: // import { getCredentialAttestationWorker } from './workers/credentialAttestation/parent'; // Do other logic such as retrieving user balance etc. ``` ### Example of mint flow See the [E2E test](src/e2e.workers3.spec.ts) for a comprehensive example. ### Example of token contracts usage #### Get user balance ```typescript const tokenBase = new FungibleToken(tokenAddress); await fetchAccount({ publicKey: userPublicKey, tokenId: tokenBase.deriveTokenId(), }); const balance = await tokenBase.getBalanceOf(userPublicKey); ``` #### Get user storage info ```typescript const noriTokenController = new NoriTokenController(noriAddress); const storage = new NoriStorageInterface( userPublicKey, noriTokenController.deriveTokenId() ); await fetchAccount({ publicKey: userPublicKey, tokenId: noriTokenController.deriveTokenId(), }); const userKeyHash = await storage.userKeyHash.fetch(); const mintedSoFar = await storage.mintedSoFar.fetch(); ``` ## Token Contract Deployment In order to deploy the contract, a script has been provided as an npm command: ```sh npm run deploy ``` This command builds the project and runs the deployment script with Node.js using the necessary experimental flags for VM and WASM modules. ### Environment Variables To configure the deployment, set the following environment variables: - `MINA_RPC_NETWORK_URL` The Mina network RPC endpoint URL. Defaults to `http://localhost:8080/graphql` if unset. - `SENDER_PRIVATE_KEY` Private key of the deploying sender account. Required for non-local deployments. Auto-generated for localhost. - `NORI_CONTROLLER_PRIVATE_KEY` Private key for the Nori Token Controller contract. Randomly generated if not provided. - `TOKEN_BASE_PRIVATE_KEY` Private key for the Token Base contract. Randomly generated if not provided. - `ADMIN_PUBLIC_KEY` Public key of the admin. Defaults to the public key derived from `SENDER_PRIVATE_KEY`. - `ETH_PROCESSOR_ADDRESS` Optional Ethereum processor contract address. - `TX_FEE` Transaction fee to use. Defaults to `0.1`. - `MOCK` Optional flag to indicate mock mode ('true' or omit for false [the default]). ### Example `.env` file ``` MINA_RPC_NETWORK_URL=http://localhost:8080/graphql SENDER_PRIVATE_KEY=your_sender_private_key_here NORI_CONTROLLER_PRIVATE_KEY=your_nori_controller_key_here TOKEN_BASE_PRIVATE_KEY=your_token_base_private_key_here ADMIN_PUBLIC_KEY=your_admin_public_key_here ETH_PROCESSOR_ADDRESS=optional_eth_processor_address TX_FEE=0.1 MOCK=true ``` ## How to run the tests ### Install Mina lightnet 1. `npm install -g zkapp-cli` 2. `zk lightnet start` ### Configure the .env file in the contracts/ethereum workspace contracts/ethereum/.env ``` ETH_PRIVATE_KEY=<Your ETH private key> ETH_RPC_URL=<Ethereum execution RPC e.g. 'https://ethereum-holesky.core.chainstack.com/<apiKey>'> ETH_NETWORK=holesky (for example) NORI_TOKEN_BRIDGE_TEST_MODE=true NORI_TOKEN_BRIDGE_ADDRESS=<Extract this from contracts/ethereum/.env.nori-token-bridge, after running npm run deploy (within the contracts/ethereum workspace), or use an already deployed test contract> ``` ### Then run the tests ```sh npm run test # all tests (hangs due to multiple instances of o1js deps) npm run test -- -t 'e2e_complete' # run a specific test (e.g. the litenet e2e test) npm run test -- src/e2e.workers2.spec.ts # run a specific test file (e.g. the litenet e2e test) npm run testw # watch mode ``` ### How to run E2E test on DevNet Firstly configure your `contracts/mina/token-bridge/.env` file: ``` ETH_PRIVATE_KEY=<Holesky ETH private key which will send the Holesky ETH> ETH_RPC_URL=https://ethereum-holesky.core.chainstack.com/<apiKey> NORI_TOKEN_BRIDGE_ADDRESS=<Holesky ETH Nori Token Bridge address> NORI_CONTROLLER_PUBLIC_KEY=<Nori Mina TestNet Token controller base58 address> MINA_RPC_NETWORK_URL=https://devnet.minaprotocol.network/graphql SENDER_PRIVATE_KEY=<Nori Mina TestNet private key which will receive the deposit> NORI_TOKEN_PUBLIC_KEY=<Nori Mina TestNet Token base base58 address> ``` **Note a real Mina TestNet contract must already be deployed.** #### After configuration, run the E2E test procedure: `npm run test -- src/e2e.workers3.spec.ts` ## How to run coverage ```sh npm run coverage ``` ## License [Apache-2.0](LICENSE)