diff --git a/frontend/angular.json b/frontend/angular.json index b6f5338908..92c363c98c 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -29,8 +29,11 @@ "prefix": "mina", "architect": { "build": { - "builder": "@angular-devkit/build-angular:browser", + "builder": "@angular-builders/custom-webpack:browser", "options": { + "customWebpackConfig": { + "path": "./webpack.config.js" + }, "outputPath": "dist/frontend", "index": "src/index.html", "main": "src/main.ts", @@ -123,7 +126,7 @@ "defaultConfiguration": "production" }, "serve": { - "builder": "@angular-devkit/build-angular:dev-server", + "builder": "@angular-builders/custom-webpack:dev-server", "configurations": { "production": { "browserTarget": "frontend:build:production" diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 481aeab759..4a01166329 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -25,12 +25,14 @@ "@ngrx/store": "^16.2.0", "@openmina/shared": "^0.102.0", "base-x": "^5.0.0", + "bs58check": "^4.0.0", "buffer": "^6.0.3", "d3": "^7.8.4", "eigen": "^0.2.2", "mathjs": "^12.3.0", "mina-signer": "^3.0.7", "ngx-json-viewer": "^3.2.1", + "o1js": "^1.7.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.13.0" @@ -3556,6 +3558,17 @@ "webpack": "^5.54.0" } }, + "node_modules/@noble/hashes": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", + "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, @@ -5373,6 +5386,23 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs58": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "dependencies": { + "base-x": "^5.0.0" + } + }, + "node_modules/bs58check": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz", + "integrity": "sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==", + "dependencies": { + "@noble/hashes": "^1.2.0", + "bs58": "^6.0.0" + } + }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -5508,7 +5538,6 @@ }, "node_modules/cachedir": { "version": "2.4.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7228,7 +7257,6 @@ }, "node_modules/encoding": { "version": "0.1.13", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -7237,7 +7265,6 @@ }, "node_modules/encoding/node_modules/iconv-lite": { "version": "0.6.3", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -9114,6 +9141,15 @@ "node": ">=0.10.0" } }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, "node_modules/isstream": { "version": "0.1.2", "dev": true, @@ -10734,6 +10770,44 @@ "license": "MIT", "optional": true }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -11046,6 +11120,25 @@ "dev": true, "license": "MIT" }, + "node_modules/o1js": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/o1js/-/o1js-1.7.0.tgz", + "integrity": "sha512-/gQKJLRuqDrArdU/QkaU0F1lQl/K6/170U01JeU2xIpryN6vBwENfEHWpHt1FXOmGwyTsQHmrJLWfyFLjQOkeA==", + "dependencies": { + "blakejs": "1.2.1", + "cachedir": "^2.4.0", + "isomorphic-fetch": "^3.0.0", + "js-sha256": "^0.9.0", + "reflect-metadata": "^0.1.13", + "tslib": "^2.3.0" + }, + "bin": { + "snarky-run": "src/build/run.js" + }, + "engines": { + "node": ">=18.14.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "dev": true, @@ -12046,7 +12139,6 @@ }, "node_modules/reflect-metadata": { "version": "0.1.13", - "dev": true, "license": "Apache-2.0" }, "node_modules/regenerate": { @@ -14488,6 +14580,11 @@ "iconv-lite": "0.4.24" } }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==" + }, "node_modules/whatwg-mimetype": { "version": "2.3.0", "dev": true, diff --git a/frontend/package.json b/frontend/package.json index 3b366703e2..d4462fe897 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -31,12 +31,14 @@ "@ngrx/store": "^16.2.0", "@openmina/shared": "^0.102.0", "base-x": "^5.0.0", + "bs58check": "^4.0.0", "buffer": "^6.0.3", "d3": "^7.8.4", "eigen": "^0.2.2", "mathjs": "^12.3.0", "mina-signer": "^3.0.7", "ngx-json-viewer": "^3.2.1", + "o1js": "^1.7.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.13.0" diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index 5282bc8752..7009c8da28 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -8,6 +8,24 @@ import { AppSelectors } from '@app/app.state'; import { AppActions } from '@app/app.actions'; import { Observable, timer } from 'rxjs'; import { CONFIG } from '@shared/constants/config'; +// import { AccountUpdate, declareMethods, Field, method, Mina, PrivateKey, SmartContract, State, state } from 'o1js'; + +// export class Square extends SmartContract { +// @state(Field) num = State(); +// +// override init() { +// super.init(); +// this.num.set(Field(3)); +// } +// +// // @method +// async update(square: Field) { +// const currentState = this.num.get(); +// this.num.requireEquals(currentState); +// square.assertEquals(currentState.mul(currentState)); +// this.num.set(square); +// } +// } @Component({ selector: 'app-root', @@ -36,8 +54,80 @@ export class AppComponent extends ManualDetection implements OnInit { this.scheduleNodeUpdates(); } this.listenToWindowResizing(); + // console.log('Start'); + // this.startZK(); + // console.log('Finish!'); } + +// async startZK() { +// //@ts-ignore +// declareMethods(Square, { update: [Field] }); +// +// const useProof = false; +// +// const Local = await Mina.LocalBlockchain({ proofsEnabled: useProof }); +// Mina.setActiveInstance(Local); +// +// const deployerAccount = Local.testAccounts[0]; +// const deployerKey = deployerAccount.key; +// const senderAccount = Local.testAccounts[1]; +// const senderKey = senderAccount.key; +// // ---------------------------------------------------- +// +// // Create a public/private key pair. The public key is your address and where you deploy the zkApp to +// const zkAppPrivateKey = PrivateKey.random(); +// const zkAppAddress = zkAppPrivateKey.toPublicKey(); +// +// // create an instance of Square - and deploy it to zkAppAddress +// const zkAppInstance = new Square(zkAppAddress); +// const deployTxn = await Mina.transaction(deployerAccount, async () => { +// AccountUpdate.fundNewAccount(deployerAccount); +// await zkAppInstance.deploy(); +// }); +// await deployTxn.sign([deployerKey, zkAppPrivateKey]).send(); +// +// // get the initial state of Square after deployment +// const num0 = zkAppInstance.num.get(); +// console.log('state after init:', num0.toString()); +// +// // ---------------------------------------------------- +// +// const txn1 = await Mina.transaction(senderAccount, async () => { +// await zkAppInstance.update(Field(9)); +// }); +// await txn1.prove(); +// await txn1.sign([senderKey]).send(); +// +// const num1 = zkAppInstance.num.get(); +// console.log('state after txn1:', num1.toString()); +// +// // ---------------------------------------------------- +// +// try { +// const txn2 = await Mina.transaction(senderAccount, async () => { +// await zkAppInstance.update(Field(75)); +// }); +// await txn2.prove(); +// await txn2.sign([senderKey]).send(); +// } catch (error: any) { +// console.log(error.message); +// } +// const num2 = zkAppInstance.num.get(); +// console.log('state after txn2:', num2.toString()); +// +// // ---------------------------------------------------- +// +// const txn3 = await Mina.transaction(senderAccount, async () => { +// await zkAppInstance.update(Field(81)); +// }); +// await txn3.prove(); +// await txn3.sign([senderKey]).send(); +// +// const num3 = zkAppInstance.num.get(); +// console.log('state after txn3:', num3.toString()); +// } + private scheduleNodeUpdates(): void { timer(1000, 5000).subscribe(() => this.store.dispatch(AppActions.getNodeDetails())); } diff --git a/frontend/src/app/app.effects.ts b/frontend/src/app/app.effects.ts index 3adfcc79ea..31c3c99799 100644 --- a/frontend/src/app/app.effects.ts +++ b/frontend/src/app/app.effects.ts @@ -12,6 +12,9 @@ import { getFirstFeature, isFeatureEnabled } from '@shared/constants/config'; import { RustService } from '@core/services/rust.service'; import { BaseEffect } from '@shared/base-classes/mina-rust-base.effect'; import { WebNodeService } from '@core/services/web-node.service'; +import { catchErrorAndRepeat2 } from '@shared/constants/store-functions'; +import { MinaErrorType } from '@shared/types/error-preview/mina-error-type.enum'; +import { AppNodeStatus } from '@shared/types/app/app-node-details.type'; const INIT_EFFECTS = '@ngrx/effects/init'; @@ -82,6 +85,18 @@ export class AppEffects extends BaseEffect { switchMap(() => this.appService.getActiveNodeDetails()), tap(() => this.requestInProgress = false), map(details => AppActions.getNodeDetailsSuccess({ details })), + catchErrorAndRepeat2(MinaErrorType.GENERIC, AppActions.getNodeDetailsSuccess({ + details: { + status: AppNodeStatus.OFFLINE, + blockHeight: null, + blockTime: null, + peers: 0, + download: 0, + upload: 0, + transactions: 0, + snarks: 0, + }, + })), )); } } diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index f0337190f0..f48340bf60 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -5,6 +5,7 @@ import { AppComponent } from './app.component'; import { AppRouting } from './app.routing'; import { MatSidenavModule } from '@angular/material/sidenav'; import { + CopyComponent, GlobalErrorHandlerService, HorizontalMenuComponent, NgrxRouterStoreModule, @@ -79,6 +80,7 @@ export class AppGlobalErrorhandler implements ErrorHandler { OpenminaEagerSharedModule, HorizontalMenuComponent, ReactiveFormsModule, + CopyComponent, ], providers: [ THEME_PROVIDER, diff --git a/frontend/src/app/app.routing.ts b/frontend/src/app/app.routing.ts index 7918f7fd26..aa4c02e7da 100644 --- a/frontend/src/app/app.routing.ts +++ b/frontend/src/app/app.routing.ts @@ -68,6 +68,11 @@ const routes: Routes = [ loadChildren: () => import('./features/benchmarks/benchmarks.module').then(m => m.BenchmarksModule), title: BENCHMARKS_TITLE, }, + { + path: 'zk', + loadChildren: () => import('./features/zk/zk.module').then(m => m.ZkModule), + title: BENCHMARKS_TITLE, + }, { path: '**', redirectTo: getFirstFeature(), diff --git a/frontend/src/app/app.service.ts b/frontend/src/app/app.service.ts index a078a38b98..91ed8f51a2 100644 --- a/frontend/src/app/app.service.ts +++ b/frontend/src/app/app.service.ts @@ -38,16 +38,7 @@ export class AppService { upload: 0, snarks: data.snark_pool.snarks, transactions: data.transaction_pool.transactions, - } as AppNodeDetails)), - catchError(() => of({ - status: AppNodeStatus.OFFLINE, - blockHeight: null, - blockTime: null, - peers: 0, - download: 0, - upload: 0, - transactions: 0, - snarks: 0, + chainId: data.chain_id, } as AppNodeDetails)), ); } @@ -71,6 +62,7 @@ export interface NodeDetailsResponse { transaction_pool: { transactions: number }; peers: Peer[]; snark_pool: SnarkPool; + chain_id: string | undefined; } interface TransitionFrontier { diff --git a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.service.ts b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.service.ts index 2e630d61d5..5e8676020d 100644 --- a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.service.ts +++ b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.service.ts @@ -7,10 +7,12 @@ import { RustService } from '@core/services/rust.service'; import { MempoolTransaction, MempoolTransactionKind, - SignedCommand, ZkappCommand, + SignedCommand, + ZkappCommand, } from '@shared/types/mempool/mempool-transaction.type'; -import { getTimeFromMemo, removeUnicodeEscapes } from '@shared/helpers/transaction.helper'; -import { any, ONE_BILLION } from '@openmina/shared'; +import { decodeMemo, getTimeFromMemo, removeUnicodeEscapes } from '@shared/helpers/transaction.helper'; +import { ONE_BILLION } from '@openmina/shared'; +import { MempoolTransactionResponseKind } from '@app/features/mempool/mempool.service'; export const WALLETS: { privateKey: string, publicKey: string }[] = [ { @@ -4098,28 +4100,40 @@ export class BenchmarksWalletsService { } getAllIncludedTransactions(): Observable { - return this.rust.get>('/best-chain-user-commands').pipe( + return this.rust.get>('/best-chain-user-commands').pipe( map(data => this.mapTxPoolResponse(data)), ); } - private mapTxPoolResponse(response: Array<{ SignedCommand: SignedCommand } | { - ZkappCommand: ZkappCommand - }>): MempoolTransaction[] { + private mapTxPoolResponse(response: Array<[MempoolTransactionResponseKind, SignedCommand | ZkappCommand]>): MempoolTransaction[] { + // return response + // .filter(tx => !!any(tx).SignedCommand) + // .map(tx => tx as { SignedCommand: SignedCommand }) + // .map((tx: { SignedCommand: SignedCommand }) => ({ + // kind: MempoolTransactionKind.PAYMENT, + // sender: tx.SignedCommand.payload.common.fee_payer_pk, + // fee: Number(tx.SignedCommand.payload.common.fee), + // nonce: Number(tx.SignedCommand.payload.common.nonce), + // memo: removeUnicodeEscapes(tx.SignedCommand.payload.common.memo), + // transactionData: tx.SignedCommand, + // sentFromStressingTool: tx.SignedCommand.payload.common.memo.includes('S.T.'), + // sentByMyBrowser: tx.SignedCommand.payload.common.memo.includes(localStorage.getItem('browserId')), + // } as MempoolTransaction)); return response - .filter(tx => !!any(tx).SignedCommand) - .map(tx => tx as { SignedCommand: SignedCommand }) - .map((tx: { SignedCommand: SignedCommand }) => ({ - kind: MempoolTransactionKind.PAYMENT, - sender: tx.SignedCommand.payload.common.fee_payer_pk, - fee: Number(tx.SignedCommand.payload.common.fee), - nonce: Number(tx.SignedCommand.payload.common.nonce), - memo: removeUnicodeEscapes(tx.SignedCommand.payload.common.memo), - transactionData: tx.SignedCommand, - sentFromStressingTool: tx.SignedCommand.payload.common.memo.includes('S.T.'), - sentByMyBrowser: tx.SignedCommand.payload.common.memo.includes(localStorage.getItem('browserId')), - } as MempoolTransaction)); + .filter(tx => tx[0] === MempoolTransactionResponseKind.SignedCommand) + .map(tx => tx[1] as SignedCommand) + .map((tx: SignedCommand) => { + const memo = decodeMemo(tx.payload.common.memo); + return { + kind: MempoolTransactionKind.PAYMENT, + sender: tx.payload.common.fee_payer_pk, + fee: Number(tx.payload.common.fee), + nonce: Number(tx.payload.common.nonce), + memo: removeUnicodeEscapes(memo), + transactionData: tx, + sentFromStressingTool: memo.includes('S.T.'), + sentByMyBrowser: memo.includes(localStorage.getItem('browserId')), + } as MempoolTransaction; + }); } } diff --git a/frontend/src/app/features/mempool/mempool.service.ts b/frontend/src/app/features/mempool/mempool.service.ts index d44b402100..7f06fbc57e 100644 --- a/frontend/src/app/features/mempool/mempool.service.ts +++ b/frontend/src/app/features/mempool/mempool.service.ts @@ -7,7 +7,7 @@ import { SignedCommand, ZkappCommand, } from '@shared/types/mempool/mempool-transaction.type'; -import { removeUnicodeEscapes } from '@shared/helpers/transaction.helper'; +import { decodeMemo, removeUnicodeEscapes } from '@shared/helpers/transaction.helper'; import { ONE_BILLION } from '@openmina/shared'; @Injectable({ @@ -19,275 +19,6 @@ export class MempoolService { getTransactionPool(limit?: number, from?: number): Observable<{ txs: MempoolTransaction[] }> { return this.rust.get('/transaction-pool').pipe( - // return of({ - // txs: [ - // { - // status: 'Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256530, - // kind: 'ZKApp command', - // txHash: 'bIUYGOUgouYgO68gwra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 1, - // nonce: 1, - // memo: 'memo1', - // }, - // { - // status: 'Not Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256745, - // kind: 'Payment', - // txHash: '3rg45gqq3gr3wqrg3wqgZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 2, - // nonce: 2, - // memo: 'memo2', - // }, - // { - // status: 'Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256847, - // kind: 'Delegation', - // txHash: 'q3wr4gw34gtq3tg35rMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 3, - // nonce: 3, - // memo: 'memo3', - // }, - // { - // status: 'Not Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256677, - // kind: 'ZKApp command', - // txHash: '5JthxoBLYoSawergfwegrewVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 4, - // nonce: 4, - // memo: 'memo4', - // }, - // { - // status: 'Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256099, - // kind: 'Payment', - // txHash: '5JthxorweagsgvfergvawergvfnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 5, - // nonce: 5, - // memo: 'memo5', - // }, - // { - // status: 'Not Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'Delegation', - // txHash: '5r3eg35g5rgwe4g5wg3qr3awrg5RZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 6, - // nonce: 6, - // memo: 'memo6', - // }, - // { - // status: 'Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'ZKApp command', - // txHash: 'q354ht3hu563qthuyeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 7, - // nonce: 7, - // memo: 'memo7', - // }, - // { - // status: 'Not Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'Payment', - // txHash: 'q346uh34q3hteu6ExUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 8, - // nonce: 8, - // memo: 'memo8', - // }, - // { - // status: 'Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'Delegation', - // txHash: 'hj4q3et6yj34ju6hjtUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 9, - // nonce: 9, - // memo: 'memo9', - // }, - // { - // status: 'Not Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'ZKApp command', - // txHash: '3q54uhUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 10, - // nonce: 10, - // memo: 'memo10', - // }, - // { - // status: 'Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'Payment', - // txHash: 'q3uhj6t54e5uUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 11, - // nonce: 11, - // memo: 'memo11', - // }, - // { - // status: 'Not Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'Delegation', - // txHash: 'q3euhj6BLYoSExUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 12, - // nonce: 12, - // memo: 'memo12', - // }, - // { - // status: 'Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'ZKApp command', - // txHash: 'w465uYoSExUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 13, - // nonce: 13, - // memo: 'memo13', - // }, - // { - // status: 'Not Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'Payment', - // txHash: 'w456ujtoSExUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 14, - // nonce: 14, - // memo: 'memo14', - // }, - // { - // status: 'Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'Delegation', - // txHash: '46tewtu4wtExUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 15, - // nonce: 15, - // memo: 'memo15', - // }, - // { - // status: 'Not Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'ZKApp command', - // txHash: 'je56yhtes456uUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 16, - // nonce: 16, - // memo: 'memo16', - // }, - // { - // status: 'Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'Payment', - // txHash: '46qhet6u4yh4thewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 17, - // nonce: 17, - // memo: 'memo17', - // }, - // { - // status: 'Not Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'Delegation', - // txHash: '426thy42yExUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 18, - // nonce: 18, - // memo: 'memo18', - // }, - // { - // status: 'Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'ZKApp command', - // txHash: '5435tghSExUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 19, - // nonce: 19, - // memo: 'memo19', - // }, - // { - // status: 'Not Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'Payment', - // txHash: '23q4th654334yxUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 20, - // nonce: 20, - // memo: 'memo20', - // }, - // { - // status: 'Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'Delegation', - // txHash: 'wrht3YoSExUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 21, - // nonce: 21, - // memo: 'memo21', - // }, - // { - // status: 'Not Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'ZKApp command', - // txHash: '5245436t43rExUMDeDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62hgre082fuehevC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 22, - // nonce: 22, - // memo: 'memo22', - // }, - // { - // status: 'Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'Payment', - // txHash: '5JthxoBLYoSExUMDe62wra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 23, - // nonce: 23, - // memo: 'memo23', - // }, - // { - // status: 'Not Applicable', - // date: '2021-07-14T11:00:00Z', - // timestamp: 1626256800, - // kind: 'Delegation', - // txHash: '5JthxoBL745eDewra8LRZpnDjvCVFfTcRq2EjKL3EwUVTho', - // sender: 'B62qif1RJqNXWmv5evC6tGpebdALcHKdCmn4CYFFTGiizauoEftYFWV', - // fee: 24, - // nonce: 24, - // memo: 'memo24', - // }, - // ], - // } as any).pipe( - // delay(1000), map(data => ({ txs: this.mapTxPoolResponse(data) })), map(({ txs }: { txs: any }) => ({ txs: [...txs] })), ); @@ -295,32 +26,35 @@ export class MempoolService { private mapTxPoolResponse(response: MempoolTransactionResponse[]): MempoolTransaction[] { return response.map((tx: MempoolTransactionResponse) => { - if (tx.data.SignedCommand) { - return { - kind: MempoolTransactionKind.PAYMENT, - txHash: tx.hash.join(''), - sender: tx.data.SignedCommand.payload.common.fee_payer_pk, - fee: Number(tx.data.SignedCommand.payload.common.fee) / ONE_BILLION, - amount: Number(tx.data.SignedCommand.payload.body.Payment.amount) / ONE_BILLION, - nonce: Number(tx.data.SignedCommand.payload.common.nonce), - memo: removeUnicodeEscapes(tx.data.SignedCommand.payload.common.memo), - transactionData: tx.data.SignedCommand, - sentFromStressingTool: tx.data.SignedCommand.payload.common.memo.includes('S.T.'), - sentByMyBrowser: tx.data.SignedCommand.payload.common.memo.includes(localStorage.getItem('browserId')), - } as MempoolTransaction; - } else { - return { - kind: MempoolTransactionKind.ZK_APP, - txHash: tx.hash.join(''), - sender: tx.data.ZkappCommand.fee_payer.body.public_key, - fee: Number(tx.data.ZkappCommand.fee_payer.body.fee) / ONE_BILLION, - amount: null, - nonce: Number(tx.data.ZkappCommand.fee_payer.body.nonce), - memo: tx.data.ZkappCommand.memo, - transactionData: tx.data.ZkappCommand, - sentFromStressingTool: false, - sentByMyBrowser: false, - } as MempoolTransaction; + switch (tx.data[0]) { + case MempoolTransactionResponseKind.SignedCommand: + const memo = decodeMemo(tx.data[1].payload.common.memo); + return { + kind: MempoolTransactionKind.PAYMENT, + txHash: tx.hash.join(''), + sender: tx.data[1].payload.common.fee_payer_pk, + fee: Number(tx.data[1].payload.common.fee), + amount: Number(tx.data[1].payload.body[1].amount) / ONE_BILLION, + nonce: Number(tx.data[1].payload.common.nonce), + memo: removeUnicodeEscapes(memo), + transactionData: tx.data[1], + sentFromStressingTool: memo.includes('S.T.'), + sentByMyBrowser: memo.includes(localStorage.getItem('browserId')), + } as MempoolTransaction; + case MempoolTransactionResponseKind.ZkappCommand: + const zkapp = tx.data[1] as ZkappCommand; + return { + kind: MempoolTransactionKind.ZK_APP, + txHash: tx.hash.join(''), + sender: zkapp.fee_payer.body.public_key, + fee: Number(zkapp.fee_payer.body.fee), + amount: null, + nonce: Number(zkapp.fee_payer.body.nonce), + memo: zkapp.memo, + transactionData: tx.data[1], + sentFromStressingTool: false, + sentByMyBrowser: false, + } as MempoolTransaction; } }); } @@ -328,11 +62,11 @@ export class MempoolService { export interface MempoolTransactionResponse { - data: Data; + data: [MempoolTransactionResponseKind, SignedCommand | ZkappCommand]; hash: number[]; } -interface Data { - SignedCommand?: SignedCommand; - ZkappCommand?: ZkappCommand; +export enum MempoolTransactionResponseKind { + SignedCommand = 'Signed_command', + ZkappCommand = 'Zkapp_command', } diff --git a/frontend/src/app/features/zk/zk.component.html b/frontend/src/app/features/zk/zk.component.html new file mode 100644 index 0000000000..7f6167bb5f --- /dev/null +++ b/frontend/src/app/features/zk/zk.component.html @@ -0,0 +1 @@ +

zk works!

diff --git a/frontend/src/app/features/zk/zk.component.scss b/frontend/src/app/features/zk/zk.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/src/app/features/zk/zk.component.ts b/frontend/src/app/features/zk/zk.component.ts new file mode 100644 index 0000000000..7d03185eed --- /dev/null +++ b/frontend/src/app/features/zk/zk.component.ts @@ -0,0 +1,103 @@ +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { AccountUpdate, Field, method, Mina, PrivateKey, Provable, PublicKey, SmartContract, state, State } from 'o1js'; + +class HelloWorld extends SmartContract {} + + +export class Square extends SmartContract { + @state(Field) num = State(); + + override init() { + super.init(); + this.num.set(Field(3)); + } + + @method + async update(square: Field) { + const currentState = this.num.get(); + this.num.requireEquals(currentState); + square.assertEquals(currentState.mul(currentState)); + this.num.set(square); + } +} + +@Component({ + selector: 'mina-zk', + templateUrl: './zk.component.html', + styleUrls: ['./zk.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ZkComponent implements OnInit { + + ngOnInit() { + console.log('Start'); + this.startZK(); + console.log('Finish!'); + } + + async startZK() { + + const useProof = false; + + const Local = await Mina.LocalBlockchain({ proofsEnabled: useProof }); + Mina.setActiveInstance(Local); + + const deployerAccount = Local.testAccounts[0]; + const deployerKey = deployerAccount.key; + const senderAccount = Local.testAccounts[1]; + const senderKey = senderAccount.key; +// ---------------------------------------------------- + +// Create a public/private key pair. The public key is your address and where you deploy the zkApp to + const zkAppPrivateKey = PrivateKey.random(); + const zkAppAddress = zkAppPrivateKey.toPublicKey(); + +// create an instance of Square - and deploy it to zkAppAddress + const zkAppInstance = new Square(zkAppAddress); + const deployTxn = await Mina.transaction(deployerAccount, async () => { + AccountUpdate.fundNewAccount(deployerAccount); + await zkAppInstance.deploy(); + }); + await deployTxn.sign([deployerKey, zkAppPrivateKey]).send(); + +// get the initial state of Square after deployment + const num0 = zkAppInstance.num.get(); + console.log('state after init:', num0.toString()); + +// ---------------------------------------------------- + + const txn1 = await Mina.transaction(senderAccount, async () => { + await zkAppInstance.update(Field(9)); + }); + await txn1.prove(); + await txn1.sign([senderKey]).send(); + + const num1 = zkAppInstance.num.get(); + console.log('state after txn1:', num1.toString()); + +// ---------------------------------------------------- + + try { + const txn2 = await Mina.transaction(senderAccount, async () => { + await zkAppInstance.update(Field(75)); + }); + await txn2.prove(); + await txn2.sign([senderKey]).send(); + } catch (error: any) { + console.log(error.message); + } + const num2 = zkAppInstance.num.get(); + console.log('state after txn2:', num2.toString()); + +// ---------------------------------------------------- + + const txn3 = await Mina.transaction(senderAccount, async () => { + await zkAppInstance.update(Field(81)); + }); + await txn3.prove(); + await txn3.sign([senderKey]).send(); + + const num3 = zkAppInstance.num.get(); + console.log('state after txn3:', num3.toString()); + } +} diff --git a/frontend/src/app/features/zk/zk.module.ts b/frontend/src/app/features/zk/zk.module.ts new file mode 100644 index 0000000000..404533b538 --- /dev/null +++ b/frontend/src/app/features/zk/zk.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ZkComponent } from './zk.component'; +import { RouterModule } from '@angular/router'; +import { ZKRouting } from '@app/features/zk/zk.routing'; + + +@NgModule({ + declarations: [ + ZkComponent, + ], + imports: [ + CommonModule, + ZKRouting, + ], +}) +export class ZkModule {} diff --git a/frontend/src/app/features/zk/zk.routing.ts b/frontend/src/app/features/zk/zk.routing.ts new file mode 100644 index 0000000000..aa2bd5d0b6 --- /dev/null +++ b/frontend/src/app/features/zk/zk.routing.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { STATE_TITLE } from '@app/app.routing'; +import { StateComponent } from '@app/features/state/state.component'; +import { ZkComponent } from '@app/features/zk/zk.component'; + +const routes: Routes = [ + { + path: '', + component: ZkComponent, + }, + { + path: '**', + redirectTo: '', + pathMatch: 'full', + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class ZKRouting {} diff --git a/frontend/src/app/layout/menu/menu.component.html b/frontend/src/app/layout/menu/menu.component.html index 24e8335381..474dbd42f5 100644 --- a/frontend/src/app/layout/menu/menu.component.html +++ b/frontend/src/app/layout/menu/menu.component.html @@ -1,8 +1,8 @@ -
- -
+
+
+ +
{{ appIdentifier }} -
+
+
+ +
+
+
+ wifi_tethering + {{ network }} +
+
+ {{ chainId.slice(0, 6) }}.. + content_copy +
+
+
diff --git a/frontend/src/app/layout/menu/menu.component.scss b/frontend/src/app/layout/menu/menu.component.scss index 0a6137fcee..1e8329053b 100644 --- a/frontend/src/app/layout/menu/menu.component.scss +++ b/frontend/src/app/layout/menu/menu.component.scss @@ -1,176 +1,195 @@ @import 'openmina'; .menu { - .menu-toggle { - padding: 8px 12px; - border: none; - border-radius: 0; - border-bottom: 1px solid $base-divider; - background-color: unset; - transition: width 200ms ease-out, background-color 80ms; - - .mina-icon { - font-size: 20px; - color: $base-tertiary; - font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 20; - transition: transform 200ms ease-out, color 80ms; - - &.flipped { - transform: rotateY(180deg); - } - } - - span:nth-child(1) { - overflow: hidden; - //max-width: 100px; - opacity: 1; - transition: 200ms ease-out; - - svg { - margin-right: 4px; - margin-left: -4px; - min-width: 25px; - min-height: 25px; - } - } - - &:hover { - background-color: $base-container; - - .mina-icon { - color: $base-primary; - } - } - } - - .item { - color: $base-secondary; - cursor: pointer; - padding-left: 4px; - display: flex; - align-items: center; - - .item-content { - width: 80%; - border-radius: 6px; - padding: 5px 7px; - display: flex; - flex-direction: row; - align-items: center; - font-weight: 600; - - .mina-icon { - font-size: 20px; - padding-right: 7px; - color: $base-tertiary; - font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 20; - } - - span:nth-child(2) { - opacity: 1; - transition: opacity 200ms ease-out; - } - } - - &:hover:not(.active) { - background-color: $base-container; - color: $base-secondary; - } - - &.active { - color: $selected-primary; - - .item-content .mina-icon { - color: $selected-primary; - font-variation-settings: 'FILL' 1, 'wght' 300, 'GRAD' 0, 'opsz' 20; - } - } - } - - &.collapsed { - .menu-toggle { - width: 44px; - - span:nth-child(1) { - max-width: 0; - opacity: 0; - } - } - - .item .item-content span:nth-child(2) { - opacity: 0; - } - } + .menu-toggle { + padding: 8px 12px; + border: none; + border-radius: 0; + border-bottom: 1px solid $base-divider; + background-color: unset; + transition: width 200ms ease-out, background-color 80ms; + + .mina-icon { + font-size: 20px; + color: $base-tertiary; + font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 20; + transition: transform 200ms ease-out, color 80ms; + + &.flipped { + transform: rotateY(180deg); + } + } + + span:nth-child(1) { + overflow: hidden; + //max-width: 100px; + opacity: 1; + transition: 200ms ease-out; + + svg { + margin-right: 4px; + margin-left: -4px; + min-width: 25px; + min-height: 25px; + } + } + + &:hover { + background-color: $base-container; + + .mina-icon { + color: $base-primary; + } + } + } + + .item { + color: $base-secondary; + cursor: pointer; + padding-left: 4px; + display: flex; + align-items: center; + + .item-content { + width: 80%; + border-radius: 6px; + padding: 5px 7px; + display: flex; + flex-direction: row; + align-items: center; + font-weight: 600; + + .mina-icon { + font-size: 20px; + padding-right: 7px; + color: $base-tertiary; + font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 20; + } + + span:nth-child(2) { + opacity: 1; + transition: opacity 200ms ease-out; + } + } + + &:hover:not(.active) { + background-color: $base-container; + color: $base-secondary; + } + + &.active { + color: $selected-primary; + + .item-content .mina-icon { + color: $selected-primary; + font-variation-settings: 'FILL' 1, 'wght' 300, 'GRAD' 0, 'opsz' 20; + } + } + } + + &.collapsed { + .menu-toggle { + width: 44px; + + span:nth-child(1) { + max-width: 0; + opacity: 0; + } + } + + .item .item-content span:nth-child(2) { + opacity: 0; + } + } } @media (max-width: 768px) { - .menu { - .menu-toggle { - height: 56px !important; - font-size: 20px !important; - } - - .mina-icon { - font-size: 24px !important; - } - - .item { - height: 54px !important; - - .item-content { - font-size: 18px; - } - } - } + .menu { + .menu-toggle { + height: 56px !important; + font-size: 20px !important; + } + + .mina-icon { + font-size: 24px !important; + } + + .item { + height: 54px !important; + + .item-content { + font-size: 18px; + } + } + } } .switcher { - background-color: $base-container; + background-color: transparent; - .mina-icon { - color: $base-secondary; - font-variation-settings: 'FILL' 1, 'wght' 200; - } + .mina-icon { + color: $base-secondary; + font-variation-settings: 'FILL' 1, 'wght' 200; + } - &:hover { - background-color: $base-divider; + &:hover { + background-color: $base-surface-top; - .mina-icon { - color: $base-primary; - } - } + .mina-icon { + color: $base-primary; + } + } } .identifier { - left: 47px; - top: 0; - transition: 0.3s ease-in-out; - transform: translate(0) rotate(0); - animation: rottWithOpc 0.3s linear; - - @media (min-width: 769px) { - left: 42px; - &.collapsed { - transform: translate(-75px, -76px) rotate(-90deg); - animation-name: rottWithOpc2; - } - } + left: 47px; + top: 0; + transition: 0.3s ease-in-out; + transform: translate(0) rotate(0); + animation: rotWithOpc 0.3s linear; + + @media (min-width: 769px) { + left: 42px; + &.collapsed { + transform: translate(-75px, -76px) rotate(-90deg); + animation-name: rotWithOpc2; + } + } } -@keyframes rottWithOpc { - 0%, 100% { - opacity: 1; - } - 20%, 80% { - opacity: 0; - } +.bottom-btn-action { + padding: 0 4px; + animation: rotWithOpc 0.3s linear; + + &:hover { + background: $base-surface-top; + } + + .network, + .chain-id { + transition: 0.3s 0.2s linear; + + &.hid { + opacity: 0; + transition: 0.1s linear; + } + } +} + +@keyframes rotWithOpc { + 0%, 100% { + opacity: 1; + } + 20%, 80% { + opacity: 0; + } } -@keyframes rottWithOpc2 { - 0%, 100% { - opacity: 1; - } - 20%, 80% { - opacity: 0; - } +@keyframes rotWithOpc2 { + 0%, 100% { + opacity: 1; + } + 20%, 80% { + opacity: 0; + } } diff --git a/frontend/src/app/layout/menu/menu.component.ts b/frontend/src/app/layout/menu/menu.component.ts index cc00975537..e240c6bd89 100644 --- a/frontend/src/app/layout/menu/menu.component.ts +++ b/frontend/src/app/layout/menu/menu.component.ts @@ -16,6 +16,7 @@ import { MinaNode } from '@shared/types/core/environment/mina-env.type'; import { filter, map, tap } from 'rxjs'; import { CONFIG, getAvailableFeatures } from '@shared/constants/config'; import { NavigationEnd, Router } from '@angular/router'; +import { MinaNetwork } from '@shared/types/core/mina/mina.type'; interface MenuItem { name: string; @@ -54,6 +55,8 @@ export class MenuComponent extends ManualDetection implements OnInit { appIdentifier: string = CONFIG.identifier; activeNode: MinaNode; activeRoute: string; + network: string; + chainId?: string; constructor(private router: Router, private store: Store, @@ -99,9 +102,21 @@ export class MenuComponent extends ManualDetection implements OnInit { ) .subscribe((node: MinaNode) => { this.activeNode = node; + this.network = node.minaExplorerNetwork ?? CONFIG.globalConfig?.minaExplorerNetwork; + this.network = this.network.charAt(0).toUpperCase() + this.network.slice(1); this.menuItems = this.allowedMenuItems; this.detect(); }); + + this.store.select(AppSelectors.activeNodeDetails) + .pipe( + filter(Boolean), + untilDestroyed(this), + ) + .subscribe(({ chainId }) => { + this.chainId = chainId; + this.detect(); + }); } private get allowedMenuItems(): MenuItem[] { diff --git a/frontend/src/app/layout/new-node/new-node.component.ts b/frontend/src/app/layout/new-node/new-node.component.ts index 93256431c9..ebfa753b64 100644 --- a/frontend/src/app/layout/new-node/new-node.component.ts +++ b/frontend/src/app/layout/new-node/new-node.component.ts @@ -96,6 +96,7 @@ export class NewNodeComponent extends StoreDispatcher implements OnInit { checked: true, subFeatures: [ { name: 'scan state', checked: true }, + { name: 'work pool', checked: true }, ], }, { diff --git a/frontend/src/app/layout/server-status/server-status.component.html b/frontend/src/app/layout/server-status/server-status.component.html index 82642bf6d9..dc9225e4ec 100644 --- a/frontend/src/app/layout/server-status/server-status.component.html +++ b/frontend/src/app/layout/server-status/server-status.component.html @@ -98,7 +98,7 @@