├── .browserslistrc ├── .editorconfig ├── .github └── workflows │ └── gh-pages.yml ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json └── tasks.json ├── LICENSE ├── README.md ├── angular.json ├── karma.conf.js ├── package-lock.json ├── package.json ├── src ├── app │ ├── app-routing.module.ts │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.spec.ts │ ├── app.component.ts │ └── app.module.ts ├── assets │ ├── .gitkeep │ ├── icon-256x256.png │ └── icon-48x48.png ├── blazor │ └── dapp-wasm │ │ ├── Blockcore.AtomicSwaps.BlockcoreDns │ │ ├── Blockcore.AtomicSwaps.BlockcoreDns.csproj │ │ ├── BlockcoreDns.razor │ │ ├── BlockcoreDns.razor.cs │ │ ├── BlockcoreDnsService.cs │ │ ├── IBlockcoreDnsService.cs │ │ ├── Models │ │ │ ├── DnsResult.cs │ │ │ ├── DnsServices.cs │ │ │ └── NsResult.cs │ │ ├── ServiceCollectionExtensions.cs │ │ ├── Toolkit │ │ │ └── JsonToolKit.cs │ │ └── _Imports.razor │ │ ├── Blockcore.AtomicSwaps.BlockcoreWallet │ │ ├── Blockcore.AtomicSwaps.BlockcoreWallet.csproj │ │ ├── BlockcoreWallet.razor │ │ ├── BlockcoreWallet.razor.cs │ │ ├── BlockcoreWalletConnector.cs │ │ ├── BlockcoreWalletModels.cs │ │ ├── Exceptions │ │ │ ├── NoBlockcoreWalletException.cs │ │ │ └── UserDeniedException.cs │ │ ├── IBlockcoreWalletConnector.cs │ │ ├── ServiceCollectionExtensions.cs │ │ ├── _Imports.razor │ │ └── wwwroot │ │ │ └── blockcoreWallet.js │ │ ├── Blockcore.MetaMask │ │ ├── Blockcore.MetaMask.csproj │ │ ├── Enums │ │ │ └── Chain.cs │ │ ├── Exceptions │ │ │ ├── NoMetaMaskException.cs │ │ │ └── UserDeniedException.cs │ │ ├── Extensions │ │ │ ├── HexExtensions.cs │ │ │ └── SendTransactionExtensions.cs │ │ ├── IMetaMaskService.cs │ │ ├── MetaMaskService.cs │ │ ├── Metamask.razor │ │ ├── Metamask.razor.cs │ │ ├── Models │ │ │ └── TypedDataPayload.cs │ │ ├── ServiceCollectionExtensions.cs │ │ ├── _Imports.razor │ │ └── wwwroot │ │ │ └── metaMask.js │ │ ├── dapp-wasm.sln │ │ └── dapp-wasm │ │ ├── App.razor │ │ ├── Data │ │ ├── BlockData.cs │ │ ├── BtcDecimalJsonConverter.cs │ │ ├── ToStringJsonConverter.cs │ │ └── TransactionModel.cs │ │ ├── Networks │ │ ├── BitcoinMain.cs │ │ ├── CityMain.cs │ │ ├── Networks.cs │ │ └── StraxMain.cs │ │ ├── Pages │ │ ├── FetchData.razor │ │ ├── GenerateAddresses.razor │ │ ├── Index.razor │ │ ├── ParseData.razor │ │ └── SignMessage.razor │ │ ├── Program.cs │ │ ├── Properties │ │ └── launchSettings.json │ │ ├── Shared │ │ ├── MainLayout.razor │ │ ├── MainLayout.razor.css │ │ ├── NavMenu.razor │ │ └── NavMenu.razor.css │ │ ├── _Imports.razor │ │ ├── dapp-wasm.csproj │ │ └── wwwroot │ │ ├── css │ │ ├── app.css │ │ ├── bootstrap │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ └── open-iconic │ │ │ ├── FONT-LICENSE │ │ │ ├── ICON-LICENSE │ │ │ ├── README.md │ │ │ └── font │ │ │ ├── css │ │ │ └── open-iconic-bootstrap.min.css │ │ │ └── fonts │ │ │ ├── open-iconic.eot │ │ │ ├── open-iconic.otf │ │ │ ├── open-iconic.svg │ │ │ ├── open-iconic.ttf │ │ │ └── open-iconic.woff │ │ ├── favicon.png │ │ ├── icon-192.png │ │ ├── index.html │ │ └── sample-data │ │ └── weather.json ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.css ├── styles.scss ├── test.ts └── webpack.config.js ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json /.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | max_line_length = 240 11 | 12 | [*.ts] 13 | quote_type = single 14 | 15 | [*.md] 16 | max_line_length = off 17 | trim_trailing_whitespace = false 18 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: github pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | workflow_dispatch: 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - name: Setup Node 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: '18.x' 19 | 20 | - name: Cache dependencies 21 | uses: actions/cache@v1 22 | with: 23 | path: ~/.npm 24 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 25 | restore-keys: | 26 | ${{ runner.os }}-node- 27 | - run: npm ci 28 | - run: npm run build 29 | 30 | - name: Deploy 31 | uses: peaceiris/actions-gh-pages@v3 32 | with: 33 | github_token: ${{ secrets.GITHUB_TOKEN }} 34 | publish_dir: ./dist/dapp-sample 35 | cname: dapp.blockcore.net -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | /src/blazor/dapp-wasm/.vs/dapp-wasm 44 | /src/blazor/dapp-wasm/dapp-wasm/obj 45 | /src/blazor/dapp-wasm/.vs/ProjectEvaluation 46 | /src/blazor/dapp-wasm/dapp-wasm/bin/Debug/net7.0 47 | /src/blazor/dapp-wasm/Blockcore.MetaMask/bin 48 | /src/blazor/dapp-wasm/Blockcore.MetaMask/obj 49 | /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreDns/obj 50 | /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/obj 51 | /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/Script/node_modules/.bin 52 | /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/Script/node_modules 53 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template", "esbenp.prettier-vscode"] 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "pwa-chrome", 8 | "request": "launch", 9 | "preLaunchTask": "npm: start", 10 | "url": "http://localhost:4200/" 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Blockcore 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Blockcore DApp Sample 2 | 3 | Decentralized application (DApp) that demonstrates interaction from third party apps and Blockcore ecosystem 4 | 5 | ## Resources 6 | 7 | [Verifiable Credentials Data Model v2.0](https://w3c.github.io/vc-data-model/) 8 | 9 | [Verifiable Credentials Implementation Guidelines 1.0](https://w3c.github.io/vc-imp-guide/) 10 | 11 | ## Inspiration 12 | 13 | This app will have similar features as the E2E Test Dapp for MetaMask: [https://metamask.github.io/test-dapp/](https://metamask.github.io/test-dapp/) 14 | 15 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.2.7. 16 | 17 | ## Development server 18 | 19 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. 20 | 21 | ## Code scaffolding 22 | 23 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 24 | 25 | ## Build 26 | 27 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. 28 | 29 | ## Running unit tests 30 | 31 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 32 | 33 | ## Running end-to-end tests 34 | 35 | Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. 36 | 37 | ## Further help 38 | 39 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 40 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "dapp-sample": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-builders/custom-webpack:browser", 19 | "options": { 20 | "customWebpackConfig": { 21 | "path": "./src/webpack.config.js", 22 | "mergeRules": { 23 | "externals": "replace" 24 | } 25 | }, 26 | "outputPath": "dist/dapp-sample", 27 | "index": "src/index.html", 28 | "main": "src/main.ts", 29 | "polyfills": "src/polyfills.ts", 30 | "tsConfig": "tsconfig.app.json", 31 | "inlineStyleLanguage": "scss", 32 | "assets": [ 33 | "src/favicon.ico", 34 | "src/assets" 35 | ], 36 | "styles": [ 37 | "./node_modules/@angular/material/prebuilt-themes/pink-bluegrey.css", 38 | "src/styles.scss" 39 | ], 40 | "scripts": [] 41 | }, 42 | "configurations": { 43 | "production": { 44 | "budgets": [ 45 | { 46 | "type": "initial", 47 | "maximumWarning": "500kb", 48 | "maximumError": "1mb" 49 | }, 50 | { 51 | "type": "anyComponentStyle", 52 | "maximumWarning": "2kb", 53 | "maximumError": "4kb" 54 | } 55 | ], 56 | "fileReplacements": [ 57 | { 58 | "replace": "src/environments/environment.ts", 59 | "with": "src/environments/environment.prod.ts" 60 | } 61 | ], 62 | "outputHashing": "all" 63 | }, 64 | "development": { 65 | "buildOptimizer": false, 66 | "optimization": false, 67 | "vendorChunk": true, 68 | "extractLicenses": false, 69 | "sourceMap": true, 70 | "namedChunks": true 71 | } 72 | }, 73 | "defaultConfiguration": "production" 74 | }, 75 | "serve": { 76 | "builder": "@angular-builders/custom-webpack:dev-server", 77 | "configurations": { 78 | "production": { 79 | "browserTarget": "dapp-sample:build:production" 80 | }, 81 | "development": { 82 | "browserTarget": "dapp-sample:build:development" 83 | } 84 | }, 85 | "defaultConfiguration": "development" 86 | }, 87 | "extract-i18n": { 88 | "builder": "@angular-builders/custom-webpack:extract-i18n", 89 | "options": { 90 | "browserTarget": "dapp-sample:build" 91 | } 92 | }, 93 | "test": { 94 | "builder": "@angular-builders/custom-webpack:karma", 95 | "options": { 96 | "customWebpackConfig": { 97 | "path": "./src/webpack.config.js", 98 | "mergeRules": { 99 | "externals": "replace" 100 | } 101 | }, 102 | "main": "src/test.ts", 103 | "polyfills": "src/polyfills.ts", 104 | "tsConfig": "tsconfig.spec.json", 105 | "karmaConfig": "karma.conf.js", 106 | "inlineStyleLanguage": "scss", 107 | "assets": [ 108 | "src/favicon.ico", 109 | "src/assets" 110 | ], 111 | "styles": [ 112 | "./node_modules/@angular/material/prebuilt-themes/pink-bluegrey.css", 113 | "src/styles.scss" 114 | ], 115 | "scripts": [] 116 | } 117 | } 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | jasmine: { 17 | // you can add configuration options for Jasmine here 18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 19 | // for example, you can disable the random execution with `random: false` 20 | // or set a specific seed with `seed: 4321` 21 | }, 22 | clearContext: false // leave Jasmine Spec Runner output visible in browser 23 | }, 24 | jasmineHtmlReporter: { 25 | suppressAll: true // removes the duplicated traces 26 | }, 27 | coverageReporter: { 28 | dir: require('path').join(__dirname, './coverage/dapp-sample'), 29 | subdir: '.', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text-summary' } 33 | ] 34 | }, 35 | reporters: ['progress', 'kjhtml'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | restartOnFileChange: true 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dapp-sample", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | "@angular/animations": "^14.2.0", 14 | "@angular/cdk": "^14.2.6", 15 | "@angular/common": "^14.2.0", 16 | "@angular/compiler": "^14.2.0", 17 | "@angular/core": "^14.2.0", 18 | "@angular/forms": "^14.2.0", 19 | "@angular/material": "^14.2.6", 20 | "@angular/platform-browser": "^14.2.0", 21 | "@angular/platform-browser-dynamic": "^14.2.0", 22 | "@angular/router": "^14.2.0", 23 | "@blockcore/did-resolver": "^0.0.3", 24 | "@blockcore/provider": "^0.0.12", 25 | "@noble/hashes": "^1.1.5", 26 | "@noble/secp256k1": "^1.7.0", 27 | "bitcoinjs-message": "^2.2.0", 28 | "did-resolver": "^4.0.1", 29 | "rxjs": "~7.5.0", 30 | "stream-browserify": "^3.0.0", 31 | "tslib": "^2.3.0", 32 | "uuid": "^9.0.0", 33 | "zone.js": "~0.11.4" 34 | }, 35 | "devDependencies": { 36 | "@angular-builders/custom-webpack": "^14.0.1", 37 | "@angular-devkit/build-angular": "^14.2.7", 38 | "@angular/cli": "~14.2.7", 39 | "@angular/compiler-cli": "^14.2.0", 40 | "@types/jasmine": "~4.0.0", 41 | "jasmine-core": "~4.3.0", 42 | "karma": "~6.4.0", 43 | "karma-chrome-launcher": "~3.1.0", 44 | "karma-coverage": "~2.2.0", 45 | "karma-jasmine": "~5.1.0", 46 | "karma-jasmine-html-reporter": "~2.0.0", 47 | "typescript": "~4.7.2" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | 4 | const routes: Routes = []; 5 | 6 | @NgModule({ 7 | imports: [RouterModule.forRoot(routes)], 8 | exports: [RouterModule] 9 | }) 10 | export class AppRoutingModule { } 11 | -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | .example-spacer { 2 | width: 50px; 3 | } 4 | 5 | .logo { 6 | margin-left: auto; 7 | margin-right: auto; 8 | width: 100%; 9 | max-width: 256px; 10 | } 11 | 12 | .actions button { 13 | margin-right: 0.6em; 14 | margin-bottom: 0.6em; 15 | } 16 | 17 | .input-full-width { 18 | width: 100%; 19 | } 20 | 21 | .card { 22 | margin-bottom: 1em; 23 | } 24 | 25 | .long { 26 | word-wrap: break-word; 27 | } 28 | 29 | .blockcore-logo { 30 | margin: 0 4px 3px 0; 31 | height: 48px; 32 | vertical-align: middle; 33 | } 34 | .fill-remaining-space { 35 | flex: 1 1 auto; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | }); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'dapp-sample'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.componentInstance; 26 | expect(app.title).toEqual('dapp-sample'); 27 | }); 28 | 29 | it('should render title', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.nativeElement as HTMLElement; 33 | expect(compiled.querySelector('.content span')?.textContent).toContain('dapp-sample app is running!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { WebProvider } from '@blockcore/provider'; 3 | import * as bitcoinMessage from 'bitcoinjs-message'; 4 | const { v4: uuidv4 } = require('uuid'); 5 | import { DIDResolutionOptions, Resolver } from 'did-resolver'; 6 | import is from '@blockcore/did-resolver'; 7 | import * as secp256k1 from '@noble/secp256k1'; 8 | import { sha256 } from '@noble/hashes/sha256'; 9 | 10 | @Component({ 11 | selector: 'app-root', 12 | templateUrl: './app.component.html', 13 | styleUrls: ['./app.component.scss'], 14 | }) 15 | export class AppComponent implements OnInit { 16 | title = 'dapp-sample'; 17 | provider?: WebProvider; 18 | 19 | signingText: string = 'Hello World'; 20 | signingJson: string = '{ "id": 5, "text": "Hello World" }'; 21 | 22 | signedTextSignature?: string; 23 | signedTextKey?: string; 24 | signedTextNetwork?: string; 25 | signedTextValidSignature?: boolean; 26 | 27 | // rawPSBT is a Base64-encoded string representing the PSBT 28 | rawPSBT: string = 29 | '70736274ff010052020000000197ad5142d4b313e39d06320d52aa608c06525dd3aad59f3033306cc7dae20ecc0000000000ffffffff01e803000000000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00000000000100e10200000000010179c41695a3be63ad012bdfb3e4fa1e1ed529b546671ee175eca105193940394f0100000000fdffffff02e8030000000000001976a914ad0e5d23994e4aedea78930662c1488ca2544efd88ac4232000000000000160014e3b767040067973106e977f46b9b449fd67f92120247304402200268c49c6e89dd3b8d59b78e35612ec2685730bc471aba3a49edd58d08d089cb02203e12e950cd59f7e0af3da88e33e221247c9ccada7a43ee4910e4d589245c37c80121026b0945d725e12b3c8fe123858bfb4d6da697329b8fbe5e02ee1e0b6ccdf3be79efd42b002206030272524d872070574dc2d183060efb8e691b0d3523e965644384446ec53190f4186c127a852c000080010000800000008000000000000000000000'; 30 | 31 | signedPsbtSignature?: string; 32 | 33 | signedJsonSignature?: string; 34 | signedJsonKey?: string; 35 | signedJsonNetwork?: string; 36 | signedJsonValidSignature?: boolean; 37 | 38 | paymentRequestAmount = 2; 39 | paymentVerificationRequestAmount = 5; 40 | paymentVerificationTransactionId: string | undefined = undefined; 41 | paymentTransactionId: string | undefined = undefined; 42 | 43 | didSupportedMethodsResponse?: string[]; 44 | didRequestResponse: any; 45 | 46 | wallet: any; 47 | nostrPublicKey = ''; 48 | nostrSignedEvent = ''; 49 | nostrRelays?: string[]; 50 | 51 | nostrEvent = { 52 | created_at: Date.now(), 53 | kind: 1, 54 | tags: [], 55 | content: 'This is my nostr message', 56 | pubkey: '', 57 | }; 58 | 59 | // vcSubject = 'did:is:'; 60 | vcType = 'EmailVerification'; 61 | vcID = uuidv4(); 62 | vcClaim = '{ "id": "did:is:0f254e55a2633d468e92aa7dd5a76c0c9101fab8e282c8c20b3fefde0d68f217", "sameAs": "mail@mail.com" }'; 63 | vc: string | undefined | null = null; 64 | 65 | networks = [ 66 | { name: 'Any (user selected)', id: '' }, 67 | { name: 'Bitcoin', id: 'BTC' }, 68 | { name: 'City Chain', id: 'CITY' }, 69 | { name: 'Stratis', id: 'STRAX' }, 70 | { name: 'x42', id: 'X42' }, 71 | ]; 72 | 73 | network = 'BTC'; 74 | 75 | constructor() {} 76 | 77 | ngOnInit(): void { 78 | console.log('This will be false:', this.isBlockcoreInstalled()); 79 | 80 | setTimeout(() => { 81 | console.log('This will hopefully be true:', this.isBlockcoreInstalled()); 82 | }, 250); 83 | } 84 | 85 | isBlockcoreInstalled = () => { 86 | const { blockcore } = globalThis as any; 87 | return Boolean(blockcore); 88 | }; 89 | 90 | async initialize() { 91 | // Creating the WebProvider will perform multiple network requests to 92 | // get all known blockchain APIs. 93 | this.provider = await WebProvider.Create(); 94 | this.provider.setNetwork(this.network); 95 | 96 | this.vcID = uuidv4(); 97 | } 98 | 99 | async getNostrPublicKey() { 100 | const gt = globalThis as any; 101 | 102 | // Use nostr directly on global, similar to how most Nostr app will interact with the provider. 103 | const pubKey = await gt.nostr.getPublicKey(); 104 | 105 | this.nostrPublicKey = pubKey; 106 | 107 | this.nostrEvent.pubkey = this.nostrPublicKey; 108 | } 109 | 110 | serializeEvent(evt: any): string { 111 | return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]); 112 | } 113 | 114 | getEventHash(event: Event): string { 115 | const utf8Encoder = new TextEncoder(); 116 | let eventHash = sha256(utf8Encoder.encode(this.serializeEvent(event))); 117 | return secp256k1.utils.bytesToHex(eventHash); 118 | } 119 | 120 | async nostrSignEvent(event: any) { 121 | const gt = globalThis as any; 122 | 123 | event.id = this.getEventHash(event); 124 | 125 | try { 126 | // Use nostr directly on global, similar to how most Nostr app will interact with the provider. 127 | const signedEvent = await gt.nostr.signEvent(event); 128 | this.nostrSignedEvent = signedEvent; 129 | } catch (err: any) { 130 | console.error(err); 131 | this.nostrSignedEvent = err.toString(); 132 | } 133 | } 134 | 135 | async getNostrPublicRelays() { 136 | const gt = globalThis as any; 137 | const relays = await gt.nostr.getRelays(); 138 | this.nostrRelays = relays; 139 | } 140 | 141 | async nostrEncrypt() { 142 | this.nostrCipher = null; 143 | 144 | const gt = globalThis as any; 145 | const cipher = await gt.nostr.nip04.encrypt(this.nostrPublicKey, this.nostrEvent.content); 146 | this.nostrCipher = cipher; 147 | } 148 | 149 | nostrCipher = null; 150 | nostrDecrypted = null; 151 | 152 | async nostrDecrypt() { 153 | this.nostrDecrypted = null; 154 | 155 | const gt = globalThis as any; 156 | const content = await gt.nostr.nip04.decrypt(this.nostrPublicKey, this.nostrCipher); 157 | this.nostrDecrypted = content; 158 | } 159 | 160 | transactionResult: any = undefined; 161 | 162 | async sendTransaction() { 163 | const result: any = await this.provider!.request({ 164 | method: 'transaction.send', 165 | params: [ 166 | { 167 | recipients: [ 168 | { hint: 'Swap', address: 'CMrc2rFsPd9VnxPiHvN2wHFVNfNd9vY8Ze', amount: 100000000 }, 169 | { hint: 'Fee Service', address: 'CMrc2rFsPd9VnxPiHvN2wHFVNfNd9vY8Ze', amount: 20000000 }, 170 | ], 171 | // data: 'op_return', 172 | feeRate: 'medium', 173 | network: this.provider?.indexer.network, 174 | }, 175 | ], 176 | }); 177 | 178 | console.log('Result:', result); 179 | 180 | this.transactionResult = result; 181 | 182 | // this.signedTextKey = result.key; 183 | // this.signedTextSignature = result.response.signature; 184 | // this.signedTextNetwork = result.network; 185 | // this.signedTextValidSignature = bitcoinMessage.verify(value, result.key, result.response.signature); 186 | } 187 | 188 | async atomicSwapKey() { 189 | const result: any = await this.provider!.request({ 190 | method: 'atomicswaps.key', 191 | params: [ 192 | { 193 | walletId: this.wallet.response.wallet.id, 194 | accountId: this.atomicSwapAccountId, 195 | network: this.provider?.indexer.network, 196 | }, 197 | ], 198 | }); 199 | 200 | console.log('Result:', result); 201 | this.atomicSwapPublicKey = result.response.publicKey; 202 | } 203 | 204 | atomicSwapPublicKey?: string; 205 | atomicSwapSecretKey?: string; 206 | 207 | async atomicSwapSecret() { 208 | const result: any = await this.provider!.request({ 209 | method: 'atomicswaps.secret', 210 | params: [ 211 | { 212 | walletId: this.wallet.response.wallet.id, 213 | accountId: this.atomicSwapAccountId, 214 | network: this.provider?.indexer.network, 215 | message: '1', // "sessionid"? 216 | }, 217 | ], 218 | }); 219 | 220 | console.log('Result:', result); 221 | this.atomicSwapSecretKey = result.response.secret; 222 | } 223 | 224 | async atomicSwapSend() { 225 | const result: any = await this.provider!.request({ 226 | method: 'atomicswaps.send', 227 | params: [ 228 | { 229 | walletId: this.wallet.response.wallet.id, 230 | accountId: this.atomicSwapAccountId, 231 | network: this.provider?.indexer.network, 232 | }, 233 | ], 234 | }); 235 | 236 | console.log('Result:', result); 237 | } 238 | 239 | async signMessageAnyAccount(value: string) { 240 | const result: any = await this.provider!.request({ 241 | method: 'signMessage', 242 | params: [{ message: value, network: this.provider?.indexer.network }], 243 | }); 244 | console.log('Result:', result); 245 | 246 | this.signedTextKey = result.key; 247 | this.signedTextSignature = result.response.signature; 248 | this.signedTextNetwork = result.network; 249 | this.signedTextValidSignature = bitcoinMessage.verify(value, result.key, result.response.signature); 250 | } 251 | 252 | async signPsbtAnyAccount(value: string) { 253 | const result: any = await this.provider!.request({ 254 | method: 'signPsbt', 255 | params: [{ message: value, network: this.provider?.indexer.network }], 256 | }); 257 | console.log('Result:', result); 258 | 259 | this.signedPsbtSignature = result.response.signature; 260 | } 261 | 262 | async signMessageAnyAccountJson(value: string) { 263 | const message = JSON.parse(value); 264 | 265 | const result: any = await this.provider!.request({ 266 | method: 'signMessage', 267 | params: [{ message: message, network: this.provider?.indexer.network }], 268 | }); 269 | 270 | console.log('Result:', result); 271 | 272 | this.signedJsonKey = result.key; 273 | this.signedJsonSignature = result.response.signature; 274 | this.signedJsonNetwork = result.network; 275 | const preparedMessage = JSON.stringify(message); 276 | this.signedJsonValidSignature = bitcoinMessage.verify(preparedMessage, result.key, result.response.signature); 277 | } 278 | 279 | async connect() { 280 | const challenge = uuidv4(); 281 | 282 | try { 283 | var result: any = await this.provider!.request({ 284 | method: 'wallets', 285 | params: [ 286 | { 287 | challenge: challenge, 288 | // reason: 'Sample app want you to sign a verifiable credential with any of your DIDs.', 289 | }, 290 | ], 291 | }); 292 | 293 | console.log('Result:', result); 294 | this.wallet = result; 295 | } catch (err) { 296 | console.error(err); 297 | } 298 | } 299 | 300 | atomicSwapAccountId?: string; 301 | 302 | getAccounts() {} 303 | 304 | async paymentVerificationRequest(network: string, amount: number) { 305 | const paymentId = uuidv4(); 306 | 307 | try { 308 | var result: any = await this.provider!.request({ 309 | method: 'payment', 310 | params: [ 311 | { 312 | network: network.toLowerCase(), 313 | amount: amount, 314 | address: 'CRp1q2hdFN5e1hVEEkFY3egyD2cT9ed6S3', 315 | label: 'City Chain Registry', 316 | message: 'Please make the initial payment for crypto company registration', 317 | id: paymentId, 318 | }, 319 | ], 320 | }); 321 | 322 | console.log('PAYMENT VERIFICATION REQUEST CLOSED...'); 323 | console.log('Result:', result); 324 | 325 | this.paymentVerificationTransactionId = result.transactionId; 326 | } catch (err) { 327 | console.error(err); 328 | } 329 | } 330 | 331 | async paymentRequest(network: string, amount: number) { 332 | try { 333 | var result: any = await this.provider!.request({ 334 | method: 'payment', 335 | params: [ 336 | { 337 | network: network.toLowerCase(), 338 | amount: amount, 339 | address: 'Ccoquhaae7u6ASqQ5BiYueASz8EavUXrKn', 340 | label: 'Your Local Info', 341 | message: 'Invoice Number 5', 342 | data: 'MzExMzUzNDIzNDY', 343 | id: '4324', 344 | }, 345 | ], 346 | }); 347 | 348 | console.log('Result:', result); 349 | this.paymentTransactionId = result.transactionId; 350 | } catch (err) { 351 | console.error(err); 352 | } 353 | } 354 | 355 | async paymentRequestCity() { 356 | try { 357 | var result = await this.provider!.request({ 358 | method: 'payment', 359 | params: [ 360 | { 361 | network: 'city', 362 | amount: 10.5, 363 | address: 'Ccoquhaae7u6ASqQ5BiYueASz8EavUXrKn', 364 | label: 'Your Local Info', 365 | message: 'Invoice Number 5', 366 | data: 'MzExMzUzNDIzNDY', 367 | id: '4324', 368 | }, 369 | ], 370 | }); 371 | 372 | console.log('Result:', result); 373 | } catch (err) { 374 | console.error(err); 375 | } 376 | } 377 | 378 | async request(method: string, params?: object | unknown[]) { 379 | if (!params) { 380 | params = []; 381 | } 382 | 383 | const result: any = await this.provider!.request({ 384 | method: method, 385 | params: params, 386 | }); 387 | console.log('Result:', result); 388 | 389 | return result; 390 | } 391 | 392 | async didSupportedMethods() { 393 | const result = await this.request('did.supportedMethods'); 394 | this.didSupportedMethodsResponse = result.response; 395 | } 396 | 397 | async didRequest(methods: string[]) { 398 | const result = await this.request('did.request', [ 399 | { 400 | challenge: 'fc0949c4-fd9c-4825-b18d-79348e358156', 401 | methods: methods, 402 | reason: 'Sample app need access to any of your DIDs.', 403 | }, 404 | ]); 405 | 406 | this.didRequestResponse = result; 407 | } 408 | 409 | vcRequestResponse: any; 410 | didLookup = 'did:is:0f254e55a2633d468e92aa7dd5a76c0c9101fab8e282c8c20b3fefde0d68f217'; 411 | didLookupResponse: any | undefined; 412 | 413 | async resolveDid() { 414 | const isResolver = is.getResolver(); 415 | const resolver = new Resolver(isResolver); 416 | this.didLookupResponse = await resolver.resolve(this.didLookup, {}); 417 | } 418 | 419 | async vcRequest() { 420 | const result = await this.request('vc.request', [ 421 | { 422 | challenge: 'fc0949c4-fd9c-4825-b18d-79348e358156', 423 | type: this.vcType, 424 | id: this.vcID, 425 | claim: this.vcClaim, 426 | reason: 'Sample app want you to sign a verifiable credential with any of your DIDs.', 427 | }, 428 | ]); 429 | 430 | this.vcRequestResponse = result; 431 | } 432 | 433 | onNetworkChanged() { 434 | console.log(this.network); 435 | this.provider?.setNetwork(this.network); 436 | } 437 | 438 | async paymentRequestStrax() { 439 | try { 440 | var result = await this.provider!.request({ 441 | method: 'payment', 442 | params: [ 443 | { 444 | network: 'strax', 445 | amount: 2, 446 | address: 'Xcoquhaae7u6ASqQ5BiYueASz8EavUXrKn', 447 | label: 'Your Local Info', 448 | message: 'Invoice Number 5', 449 | data: 'MzExMzUzNDIzNDY', 450 | id: '4324', 451 | }, 452 | ], 453 | }); 454 | 455 | console.log('Result:', result); 456 | } catch (err) { 457 | console.error(err); 458 | } 459 | } 460 | } 461 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | 4 | import { AppRoutingModule } from './app-routing.module'; 5 | import { AppComponent } from './app.component'; 6 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 7 | import { MatToolbarModule } from '@angular/material/toolbar'; 8 | import { MatIconModule } from '@angular/material/icon'; 9 | import { MatButtonModule } from '@angular/material/button'; 10 | import { MatCommonModule } from '@angular/material/core'; 11 | import { MatCardModule } from '@angular/material/card'; 12 | import { MatInputModule } from '@angular/material/input'; 13 | import { MatFormFieldModule } from '@angular/material/form-field'; 14 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 15 | import { MatSelectModule } from '@angular/material/select'; 16 | import { MatTabsModule } from '@angular/material/tabs'; 17 | 18 | @NgModule({ 19 | declarations: [AppComponent], 20 | imports: [ 21 | BrowserModule, 22 | FormsModule, 23 | MatTabsModule, 24 | ReactiveFormsModule, 25 | AppRoutingModule, 26 | BrowserAnimationsModule, 27 | MatCommonModule, 28 | MatSelectModule, 29 | MatToolbarModule, 30 | MatIconModule, 31 | MatButtonModule, 32 | MatCardModule, 33 | MatInputModule, 34 | MatFormFieldModule, 35 | ], 36 | providers: [], 37 | bootstrap: [AppComponent], 38 | }) 39 | export class AppModule {} 40 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/super-devninja/dapp-sample/c56c620048fafbe15117540e248ecd9de3d509ac/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/assets/icon-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/super-devninja/dapp-sample/c56c620048fafbe15117540e248ecd9de3d509ac/src/assets/icon-256x256.png -------------------------------------------------------------------------------- /src/assets/icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/super-devninja/dapp-sample/c56c620048fafbe15117540e248ecd9de3d509ac/src/assets/icon-48x48.png -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreDns/Blockcore.AtomicSwaps.BlockcoreDns.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | True 6 | True 7 | Blockcore 8 | 1.0.0 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreDns/BlockcoreDns.razor: -------------------------------------------------------------------------------- 1 | @page "/blockcoredns" 2 | @using Blockcore.AtomicSwaps.BlockcoreDns 3 | @using Microsoft.JSInterop 4 | @inject IJSRuntime JSRuntime; 5 | 6 | Blockcore Dns 7 | 8 |

Blockcore Dns!

9 | 10 | 11 |
@blockcoreDnsUrl
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 | @if (services != null) 23 | { 24 | foreach (var ns in services) 25 | { 26 |

@ns.Url

27 | @foreach (var dr in ns.DnsResults) 28 | { 29 | 41 | } 42 | } 43 | } 44 | 45 |
46 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreDns/BlockcoreDns.razor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using Blockcore.AtomicSwaps.BlockcoreDns.Models; 5 | using Microsoft.AspNetCore.Components; 6 | 7 | namespace Blockcore.AtomicSwaps.BlockcoreDns 8 | { 9 | public partial class BlockcoreDns : IDisposable 10 | { 11 | private bool disposedValue; 12 | [Inject] 13 | public IBlockcoreDnsService blockcoreDnsService { get; set; } = default!; 14 | public string? blockcoreDnsUrl { get; set; } 15 | public string? network { get; set; } 16 | public string? type { get; set; } 17 | public string textColor { get; set; } = "text-success"; 18 | 19 | public IList services { get; set; } 20 | 21 | protected override Task OnInitializedAsync() 22 | { 23 | blockcoreDnsUrl = blockcoreDnsService.GetDnsServiceUrl(); 24 | return Task.CompletedTask; 25 | } 26 | 27 | public async Task GetServicesByNetwork() 28 | { 29 | services = await blockcoreDnsService.GetServicesByNetwork(network); 30 | } 31 | 32 | public async Task GetServicesByType() 33 | { 34 | services = await blockcoreDnsService.GetServicesByType(type); 35 | } 36 | 37 | public async Task GetServicesByTypeAndNetwork() 38 | { 39 | services = await blockcoreDnsService.GetServicesByTypeAndNetwork(type,network); 40 | } 41 | 42 | protected virtual void Dispose(bool disposing) 43 | { 44 | if (!disposedValue) 45 | { 46 | if (disposing) 47 | { 48 | // TODO: dispose managed state (managed objects) 49 | } 50 | 51 | // TODO: free unmanaged resources (unmanaged objects) and override finalizer 52 | // TODO: set large fields to null 53 | disposedValue = true; 54 | } 55 | } 56 | 57 | public void Dispose() 58 | { 59 | // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method 60 | Dispose(disposing: true); 61 | GC.SuppressFinalize(this); 62 | } 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreDns/BlockcoreDnsService.cs: -------------------------------------------------------------------------------- 1 | using Blockcore.AtomicSwaps.BlockcoreDns.Models; 2 | using Blockcore.AtomicSwaps.BlockcoreDns.Toolkit; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace Blockcore.AtomicSwaps.BlockcoreDns 9 | { 10 | public class BlockcoreDnsService : IBlockcoreDnsService 11 | { 12 | private readonly string dnsServiceUrl = "https://chains.blockcore.net/services/DNS.json"; 13 | 14 | public async ValueTask> GetNsServices(string url) 15 | { 16 | var services = await new JsonToolKit>().DownloadAndConverJsonToObjectAsync(url); 17 | return services; 18 | } 19 | 20 | public async ValueTask> GetServicesByNetwork(string network) 21 | { 22 | if (string.IsNullOrEmpty(network)) 23 | { 24 | return null; 25 | } 26 | var nsServices = await GetNsServices(dnsServiceUrl); 27 | if (nsServices.Any()) 28 | { 29 | List dnsservices = new List(); 30 | foreach (var ns in nsServices) 31 | { 32 | List dnsResult = new List(); 33 | var result = await new JsonToolKit>().DownloadAndConverJsonToObjectAsync(ns.Url + "/api/dns/services/symbol/"+ network); 34 | if (result.Any()) 35 | { 36 | dnsResult.AddRange(result); 37 | dnsservices.Add(new DnsServices { Url = ns.Url, DnsResults = dnsResult }); 38 | } 39 | } 40 | return dnsservices; 41 | } 42 | return null; 43 | } 44 | 45 | public async ValueTask> GetServicesByType(string type) 46 | { 47 | if (string.IsNullOrEmpty(type)) 48 | { 49 | return null; 50 | } 51 | var nsServices = await GetNsServices(dnsServiceUrl); 52 | if (nsServices.Any()) 53 | { 54 | List dnsservices = new List(); 55 | foreach (var ns in nsServices) 56 | { 57 | List dnsResult = new List(); 58 | var result = await new JsonToolKit>().DownloadAndConverJsonToObjectAsync(ns.Url + "/api/dns/services/service/" + type); 59 | if (result.Any()) 60 | { 61 | dnsResult.AddRange(result); 62 | dnsservices.Add(new DnsServices { Url = ns.Url, DnsResults = dnsResult }); 63 | } 64 | } 65 | return dnsservices; 66 | } 67 | return null; 68 | } 69 | 70 | public async ValueTask> GetServicesByTypeAndNetwork(string type, string network) 71 | { 72 | if (string.IsNullOrEmpty(type) || string.IsNullOrEmpty(network)) 73 | { 74 | return null; 75 | } 76 | 77 | var nsServices = await GetNsServices(dnsServiceUrl); 78 | if (nsServices.Any()) 79 | { 80 | List dnsservices = new List(); 81 | foreach (var ns in nsServices) 82 | { 83 | List dnsResult = new List(); 84 | var result = await new JsonToolKit>().DownloadAndConverJsonToObjectAsync(ns.Url + "/api/dns/services/symbol/"+ network + "/service/" + type); 85 | if (result.Any()) 86 | { 87 | dnsResult.AddRange(result); 88 | dnsservices.Add(new DnsServices { Url = ns.Url, DnsResults = dnsResult }); 89 | } 90 | } 91 | return dnsservices; 92 | } 93 | return null; 94 | } 95 | 96 | public string GetDnsServiceUrl() 97 | { 98 | return dnsServiceUrl; 99 | } 100 | 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreDns/IBlockcoreDnsService.cs: -------------------------------------------------------------------------------- 1 |  2 | using Blockcore.AtomicSwaps.BlockcoreDns.Models; 3 | using System.Collections.Generic; 4 | using System.Net; 5 | using System.Threading.Tasks; 6 | 7 | namespace Blockcore.AtomicSwaps.BlockcoreDns 8 | { 9 | public interface IBlockcoreDnsService 10 | { 11 | string GetDnsServiceUrl(); 12 | ValueTask> GetNsServices(string url); 13 | ValueTask> GetServicesByType(string type); 14 | ValueTask> GetServicesByNetwork(string network); 15 | ValueTask> GetServicesByTypeAndNetwork(string type, string network); 16 | } 17 | } -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreDns/Models/DnsResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Blockcore.AtomicSwaps.BlockcoreDns.Models 8 | { 9 | public class DnsResult 10 | { 11 | public string Domain { get; set; } 12 | public string Symbol { get; set; } 13 | public string Service { get; set; } 14 | public int Ttl { get; set; } 15 | public bool Online { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreDns/Models/DnsServices.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Blockcore.AtomicSwaps.BlockcoreDns.Models 9 | { 10 | public class DnsServices 11 | { 12 | public string Url { get; set; } 13 | public List DnsResults { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreDns/Models/NsResult.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Blockcore.AtomicSwaps.BlockcoreDns.Models 9 | { 10 | public class NsResult 11 | { 12 | [JsonProperty("url")] 13 | public string Url { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreDns/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace Blockcore.AtomicSwaps.BlockcoreDns 4 | { 5 | public static class ServiceCollectionExtensions 6 | { 7 | public static void AddBlockcoreDns(this IServiceCollection services) 8 | { 9 | services.AddScoped(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreDns/Toolkit/JsonToolKit.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Linq; 6 | using System.Net.Http; 7 | using System.Text; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | 12 | namespace Blockcore.AtomicSwaps.BlockcoreDns.Toolkit 13 | { 14 | public class JsonToolKit where T : class 15 | { 16 | public T ConverJsonToObject(string json) 17 | { 18 | var result = JsonConvert.DeserializeObject(json); 19 | return result; 20 | } 21 | 22 | public async Task DownloadAndConverJsonToObjectAsync(string Url) 23 | { 24 | try 25 | { 26 | using (var httpClient = new HttpClient()) 27 | { 28 | Uri uri = new Uri(Url); 29 | var json = await httpClient.GetStringAsync(uri); 30 | var result = JsonConvert.DeserializeObject(json); 31 | return result; 32 | } 33 | } 34 | catch 35 | { 36 | return null; 37 | } 38 | 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreDns/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/Blockcore.AtomicSwaps.BlockcoreWallet.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | enable 6 | nullable 7 | True 8 | True 9 | Blockcore 10 | 1.0.0 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/BlockcoreWallet.razor: -------------------------------------------------------------------------------- 1 | @page "/blockcorewallet" 2 | @using Microsoft.JSInterop 3 | @inject IJSRuntime JSRuntime; 4 | 5 | Blockcore Wallet 6 | 7 |

Blockcore Wallet!

8 | @if (!HasBlockcoreWallet) 9 | { 10 |

No Blockcore Wallet detected. Please install Blockcore Wallet.

11 | } 12 | else 13 | { 14 | 15 |
16 |
17 |

@SignedMessage

18 |
19 | 20 |
21 | 22 | 23 |
24 |
25 |

@SignedMessageAnyAccount

26 |
27 | 28 |
29 | 30 | 31 |
32 |
33 |

@SignedMessageAnyAccountJson

34 |
35 | 36 |
37 | 38 | 39 |
40 |
41 |

@PaymentRequestResult

42 |
43 | 44 |
45 | 46 | 47 |
48 |
49 |

@DIDSupportedMethodsResult

50 |
51 | 52 |
53 | 54 | 55 |
56 |
57 |

@DIDRequestResult

58 |
59 | 60 | 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/BlockcoreWallet.razor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Blockcore.AtomicSwaps.BlockcoreWallet; 4 | using Blockcore.AtomicSwaps.BlockcoreWallet.Exceptions; 5 | using Microsoft.AspNetCore.Components; 6 | 7 | 8 | namespace Blockcore.AtomicSwaps.BlockcoreWallet 9 | { 10 | 11 | public partial class BlockcoreWallet : IDisposable 12 | { 13 | private bool disposedValue; 14 | 15 | [Inject] 16 | public IBlockcoreWalletConnector BlockcoreWalletConnector { get; set; } = default!; 17 | public bool HasBlockcoreWallet { get; set; } 18 | string[] arr = new string[] { }; 19 | 20 | public string? SignedMessage { get; set; } 21 | public string? SignedMessageAnyAccount { get; set; } 22 | public string? SignedMessageAnyAccountJson { get; set; } 23 | public string? PaymentRequestResult { get; set; } 24 | public string? DIDSupportedMethodsResult { get; set; } 25 | public string? DIDRequestResult { get; set; } 26 | 27 | protected override async Task OnInitializedAsync() 28 | { 29 | HasBlockcoreWallet = await BlockcoreWalletConnector.HasBlockcoreWallet(); 30 | } 31 | 32 | public async Task SignMessageAnyAccount(string value) 33 | { 34 | var result = await BlockcoreWalletConnector.SignMessageAnyAccount(value); 35 | SignedMessageAnyAccount = $"Signed: {result}"; 36 | } 37 | 38 | public async Task SignMessageAnyAccountJson(string value) 39 | { 40 | var result = await BlockcoreWalletConnector.SignMessageAnyAccountJson(value); 41 | SignedMessageAnyAccountJson = $"Signed: {result}"; 42 | } 43 | 44 | public async Task PaymentRequest(string network, string amount) 45 | { 46 | var result = await BlockcoreWalletConnector.PaymentRequest(network, amount); 47 | PaymentRequestResult = $"{result}"; 48 | } 49 | 50 | public async Task DIDSupportedMethods() 51 | { 52 | var result = await BlockcoreWalletConnector.DIDSupportedMethods(); 53 | DIDSupportedMethodsResult = $"{result}"; 54 | } 55 | 56 | public async Task DIDRequest(string[] methods) 57 | { 58 | var result = await BlockcoreWalletConnector.DIDRequest(methods); 59 | DIDRequestResult = $"{result}"; 60 | } 61 | 62 | public async Task SignMessage(string message) 63 | { 64 | try 65 | { 66 | var result = await BlockcoreWalletConnector.SignMessage(message); 67 | SignedMessage = $"Signed: {result}"; 68 | } 69 | catch (UserDeniedException) 70 | { 71 | SignedMessage = "User Denied"; 72 | } 73 | catch (Exception ex) 74 | { 75 | SignedMessage = $"Exception: {ex}"; 76 | } 77 | } 78 | 79 | 80 | 81 | 82 | protected virtual void Dispose(bool disposing) 83 | { 84 | if (!disposedValue) 85 | { 86 | if (disposing) 87 | { 88 | // TODO: dispose managed state (managed objects) 89 | } 90 | 91 | // TODO: free unmanaged resources (unmanaged objects) and override finalizer 92 | // TODO: set large fields to null 93 | disposedValue = true; 94 | } 95 | } 96 | 97 | 98 | 99 | public void Dispose() 100 | { 101 | // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method 102 | Dispose(disposing: true); 103 | GC.SuppressFinalize(this); 104 | } 105 | } 106 | 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/BlockcoreWalletConnector.cs: -------------------------------------------------------------------------------- 1 | using Blockcore.AtomicSwaps.BlockcoreWallet.Exceptions; 2 | using Microsoft.JSInterop; 3 | using System; 4 | using System.Numerics; 5 | using System.Reflection.Emit; 6 | using System.Text.Json; 7 | using System.Threading.Tasks; 8 | 9 | namespace Blockcore.AtomicSwaps.BlockcoreWallet 10 | { 11 | // This class provides JavaScript functionality for BlockcoreWallet wrapped 12 | // in a .NET class for easy consumption. The associated JavaScript module is 13 | // loaded on demand when first needed. 14 | // 15 | // This class can be registered as scoped DI service and then injected into Blazor 16 | // components for use. 17 | 18 | public class BlockcoreWalletConnector : IAsyncDisposable, IBlockcoreWalletConnector 19 | { 20 | private readonly Lazy> moduleTask; 21 | 22 | //public static event Func? ConnectEvent; 23 | //public static event Func? DisconnectEvent; 24 | 25 | public BlockcoreWalletConnector(IJSRuntime jsRuntime) 26 | { 27 | moduleTask = new(() => LoadScripts(jsRuntime).AsTask()); 28 | } 29 | 30 | public ValueTask LoadScripts(IJSRuntime jsRuntime) 31 | { 32 | return jsRuntime.InvokeAsync("import", "./_content/Blockcore.AtomicSwaps.BlockcoreWallet/blockcoreWallet.js"); 33 | } 34 | 35 | public async ValueTask ConnectBlockcoreWallet() 36 | { 37 | var module = await moduleTask.Value; 38 | try 39 | { 40 | await module.InvokeVoidAsync("checkBlockcoreWallet"); 41 | } 42 | catch (Exception ex) 43 | { 44 | HandleExceptions(ex); 45 | throw; 46 | } 47 | } 48 | 49 | public async ValueTask HasBlockcoreWallet() 50 | { 51 | var module = await moduleTask.Value; 52 | try 53 | { 54 | return await module.InvokeAsync("hasBlockcoreWallet"); 55 | } 56 | catch (Exception ex) 57 | { 58 | HandleExceptions(ex); 59 | throw; 60 | } 61 | } 62 | 63 | public async ValueTask IsSiteConnected() 64 | { 65 | var module = await moduleTask.Value; 66 | try 67 | { 68 | return await module.InvokeAsync("isSiteConnected"); 69 | } 70 | catch (Exception ex) 71 | { 72 | HandleExceptions(ex); 73 | throw; 74 | } 75 | } 76 | 77 | public async ValueTask SendCoins(BlockcoreWalletSendFunds data) 78 | { 79 | var input = JsonSerializer.Serialize(data); 80 | var module = await moduleTask.Value; 81 | try 82 | { 83 | var result = await module.InvokeAsync("sendCoins", input); 84 | return JsonSerializer.Deserialize(result); 85 | } 86 | catch (Exception ex) 87 | { 88 | HandleExceptions(ex); 89 | throw; 90 | } 91 | } 92 | 93 | public async ValueTask SwapCoins(BlockcoreWalletSwapCoins data) 94 | { 95 | var input = JsonSerializer.Serialize(data); 96 | var module = await moduleTask.Value; 97 | try 98 | { 99 | var result = await module.InvokeAsync("swapCoins", input); 100 | return JsonSerializer.Deserialize(result); 101 | } 102 | catch (Exception ex) 103 | { 104 | HandleExceptions(ex); 105 | throw; 106 | } 107 | } 108 | 109 | public async ValueTask GetWallet(string? key = null) 110 | { 111 | var module = await moduleTask.Value; 112 | try 113 | { 114 | var result = await module.InvokeAsync("getWallet", key); 115 | return JsonSerializer.Deserialize(result); 116 | 117 | } 118 | catch (Exception ex) 119 | { 120 | HandleExceptions(ex); 121 | throw; 122 | } 123 | } 124 | 125 | public async ValueTask GetSwapKey(string key, string walletId, string accountId, bool includePrivateKey) 126 | { 127 | var module = await moduleTask.Value; 128 | try 129 | { 130 | return await module.InvokeAsync("getSwapKey", key, walletId, accountId, includePrivateKey); 131 | } 132 | catch (Exception ex) 133 | { 134 | HandleExceptions(ex); 135 | throw; 136 | } 137 | } 138 | 139 | public async ValueTask GetSwapSecret(string key, string walletId, string accountId, string message) 140 | { 141 | var module = await moduleTask.Value; 142 | try 143 | { 144 | return await module.InvokeAsync("getSwapSecret", key, walletId, accountId, message); 145 | } 146 | catch (Exception ex) 147 | { 148 | HandleExceptions(ex); 149 | throw; 150 | } 151 | } 152 | 153 | public async ValueTask SignMessageAnyAccount(string value) 154 | { 155 | var module = await moduleTask.Value; 156 | try 157 | { 158 | return await module.InvokeAsync("signMessageAnyAccount", value); 159 | 160 | 161 | } 162 | catch (Exception ex) 163 | { 164 | HandleExceptions(ex); 165 | throw; 166 | } 167 | } 168 | 169 | public async ValueTask SignMessageAnyAccountJson(string value) 170 | { 171 | var module = await moduleTask.Value; 172 | try 173 | { 174 | return await module.InvokeAsync("signMessageAnyAccountJson", value); 175 | } 176 | catch (Exception ex) 177 | { 178 | HandleExceptions(ex); 179 | throw; 180 | } 181 | } 182 | 183 | public async ValueTask PaymentRequest(string network, string amount) 184 | { 185 | var module = await moduleTask.Value; 186 | try 187 | { 188 | return await module.InvokeAsync("paymentRequest", network, amount); 189 | } 190 | catch (Exception ex) 191 | { 192 | HandleExceptions(ex); 193 | throw; 194 | } 195 | } 196 | 197 | public async ValueTask DIDSupportedMethods() 198 | { 199 | var module = await moduleTask.Value; 200 | try 201 | { 202 | return await module.InvokeAsync("didSupportedMethods"); 203 | } 204 | catch (Exception ex) 205 | { 206 | HandleExceptions(ex); 207 | throw; 208 | } 209 | } 210 | 211 | public async ValueTask DIDRequest(string[] methods) 212 | { 213 | var module = await moduleTask.Value; 214 | try 215 | { 216 | return await module.InvokeAsync("didRequest", methods); 217 | } 218 | catch (Exception ex) 219 | { 220 | HandleExceptions(ex); 221 | throw; 222 | } 223 | } 224 | 225 | public async ValueTask SignMessage(string msg) 226 | { 227 | var module = await moduleTask.Value; 228 | try 229 | { 230 | return await module.InvokeAsync("signMessage", msg); 231 | } 232 | catch (Exception ex) 233 | { 234 | HandleExceptions(ex); 235 | throw; 236 | } 237 | } 238 | 239 | public async ValueTask DisposeAsync() 240 | { 241 | if (moduleTask.IsValueCreated) 242 | { 243 | var module = await moduleTask.Value; 244 | await module.DisposeAsync(); 245 | } 246 | } 247 | 248 | private void HandleExceptions(Exception ex) 249 | { 250 | switch (ex.Message) 251 | { 252 | case "NoBlockcoreWallet": 253 | throw new NoBlockcoreWalletException(); 254 | case "UserDenied": 255 | throw new UserDeniedException(); 256 | } 257 | } 258 | 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/BlockcoreWalletModels.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.JSInterop; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Numerics; 5 | using System.Threading.Tasks; 6 | #pragma warning disable CS8618 7 | 8 | namespace Blockcore.AtomicSwaps.BlockcoreWallet 9 | { 10 | public class BlockcoreWalletSendFundsRecipients 11 | { 12 | public string address { get; set; } = null!; 13 | public long amount { get; set; } 14 | public string hint { get; set; } = string.Empty; 15 | } 16 | public class BlockcoreWalletSendFunds 17 | { 18 | public List recipients { get; set; } = new(); 19 | 20 | public string data { get; set; } 21 | public string feeRate { get; set; } 22 | public string network { get; set; } 23 | } 24 | 25 | public class BlockcoreWalletSendFundsOut 26 | { 27 | public string transactionId { get; set; } 28 | public string transactionHex { get; set; } 29 | } 30 | 31 | public class BlockcoreWalletSwapCoins 32 | { 33 | public string walletId { get; set; } 34 | public string accountId { get; set; } 35 | public string swapTrxHex { get; set; } 36 | public string trxToSignHex { get; set; } 37 | public string redeemScriptHex { get; set; } 38 | public string secretHashHex { get; set; } 39 | public string network { get; set; } 40 | public string message { get; set; } 41 | } 42 | 43 | public class BlockcoreWalletSwapCoinsOut 44 | { 45 | public string privateKey { get; set; } 46 | public string transactionId { get; set; } 47 | public string transactionHex { get; set; } 48 | 49 | } 50 | 51 | public class BlockcoreWalletMessageOut 52 | { 53 | public string key { get; set; } 54 | public ContentData response { get; set; } 55 | 56 | public class Account 57 | { 58 | public string icon { get; set; } 59 | public string name { get; set; } 60 | public string id { get; set; } 61 | public int network { get; set; } 62 | public string networkType { get; set; } 63 | public int purpose { get; set; } 64 | public int purposeAddress { get; set; } 65 | public string type { get; set; } 66 | public History history { get; set; } 67 | public State state { get; set; } 68 | public NetworkDefinition networkDefinition { get; set; } 69 | } 70 | 71 | public class Bip32 72 | { 73 | public int @public { get; set; } 74 | public int @private { get; set; } 75 | } 76 | 77 | public class Change 78 | { 79 | public string address { get; set; } 80 | public int index { get; set; } 81 | } 82 | 83 | public class Confirmation 84 | { 85 | public int low { get; set; } 86 | public int high { get; set; } 87 | public int count { get; set; } 88 | } 89 | 90 | public class History 91 | { 92 | public long balance { get; set; } 93 | public List history { get; set; } 94 | public int unconfirmed { get; set; } 95 | public List unspent { get; set; } 96 | } 97 | 98 | public class HistoryItem 99 | { 100 | public int blockIndex { get; set; } 101 | public string calculatedAddress { get; set; } 102 | public long calculatedValue { get; set; } 103 | public string entryType { get; set; } 104 | public int fee { get; set; } 105 | public bool finalized { get; set; } 106 | public bool isCoinbase { get; set; } 107 | public bool isCoinstake { get; set; } 108 | public int timestamp { get; set; } 109 | public string transactionHash { get; set; } 110 | } 111 | 112 | public class NetworkDefinition 113 | { 114 | public string id { get; set; } 115 | public string name { get; set; } 116 | public string symbol { get; set; } 117 | public int network { get; set; } 118 | public int purpose { get; set; } 119 | public string messagePrefix { get; set; } 120 | public string bech32 { get; set; } 121 | public Bip32 bip32 { get; set; } 122 | public int pubKeyHash { get; set; } 123 | public int scriptHash { get; set; } 124 | public int wif { get; set; } 125 | public int minimumFeeRate { get; set; } 126 | public int maximumFeeRate { get; set; } 127 | public bool testnet { get; set; } 128 | public bool isProofOfStake { get; set; } 129 | public bool smartContractSupport { get; set; } 130 | public string type { get; set; } 131 | public int? purposeAddress { get; set; } 132 | } 133 | 134 | public class Param 135 | { 136 | public object key { get; set; } 137 | } 138 | 139 | public class Peg 140 | { 141 | public string type { get; set; } 142 | public string address { get; set; } 143 | } 144 | 145 | public class Receive 146 | { 147 | public string address { get; set; } 148 | public int index { get; set; } 149 | } 150 | 151 | 152 | public class ContentData 153 | { 154 | public Wallet wallet { get; set; } 155 | public List accounts { get; set; } 156 | } 157 | 158 | public class State 159 | { 160 | public int balance { get; set; } 161 | public List change { get; set; } 162 | public bool completedScan { get; set; } 163 | public string id { get; set; } 164 | public DateTime lastScan { get; set; } 165 | public List receive { get; set; } 166 | } 167 | 168 | public class Unspent 169 | { 170 | public string address { get; set; } 171 | public long balance { get; set; } 172 | public int index { get; set; } 173 | public string transactionHash { get; set; } 174 | public bool unconfirmed { get; set; } 175 | } 176 | 177 | public class Wallet 178 | { 179 | public string id { get; set; } 180 | public string name { get; set; } 181 | public string key { get; set; } 182 | } 183 | 184 | } 185 | } -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/Exceptions/NoBlockcoreWalletException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Blockcore.AtomicSwaps.BlockcoreWallet.Exceptions 8 | { 9 | public class NoBlockcoreWalletException : ApplicationException 10 | { 11 | public NoBlockcoreWalletException() : base("BlockcoreWallet is not installed.") 12 | { 13 | 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/Exceptions/UserDeniedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Blockcore.AtomicSwaps.BlockcoreWallet.Exceptions 8 | { 9 | public class UserDeniedException : ApplicationException 10 | { 11 | public UserDeniedException() : base("User denied access to BlockcoreWallet.") 12 | { 13 | 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/IBlockcoreWalletConnector.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.JSInterop; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Numerics; 5 | using System.Threading.Tasks; 6 | 7 | namespace Blockcore.AtomicSwaps.BlockcoreWallet 8 | { 9 | public interface IBlockcoreWalletConnector 10 | { 11 | 12 | ValueTask ConnectBlockcoreWallet(); 13 | ValueTask DisposeAsync(); 14 | ValueTask HasBlockcoreWallet(); 15 | ValueTask IsSiteConnected(); 16 | ValueTask SignMessageAnyAccount(string value); 17 | ValueTask GetWallet(string? key = null); 18 | ValueTask GetSwapKey(string key, string walletId, string accountId, bool includePrivateKey); 19 | ValueTask GetSwapSecret(string key, string walletId, string accountId, string message); 20 | ValueTask SignMessageAnyAccountJson(string value); 21 | ValueTask PaymentRequest(string network, string amount); 22 | ValueTask DIDSupportedMethods(); 23 | ValueTask DIDRequest(string[] methods); 24 | ValueTask SignMessage(string msg); 25 | ValueTask SendCoins(BlockcoreWalletSendFunds data); 26 | ValueTask SwapCoins(BlockcoreWalletSwapCoins data); 27 | } 28 | } -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.JSInterop; 3 | 4 | namespace Blockcore.AtomicSwaps.BlockcoreWallet 5 | { 6 | public static class ServiceCollectionExtensions 7 | { 8 | public static void AddBlockcoreWallet(this IServiceCollection services) 9 | { 10 | services.AddScoped(sp => new BlockcoreWalletConnector(sp.GetRequiredService())); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.AtomicSwaps.BlockcoreWallet/wwwroot/blockcoreWallet.js: -------------------------------------------------------------------------------- 1 | export async function hasBlockcoreWallet() { 2 | return (globalThis.blockcore != undefined); 3 | } 4 | 5 | export async function signMessageAnyAccount(value) { 6 | const provider = globalThis.blockcore; 7 | 8 | const result = await provider.request({ 9 | method: 'signMessage', 10 | params: [{ message: value }], 11 | }); 12 | console.log('Result:', result); 13 | return JSON.stringify(result); 14 | 15 | //var key = result.key; 16 | //var signature = result.signature; 17 | //var network = result.network; 18 | //var verify = bitcoinMessage.verify(value, result.key, result.signature); 19 | } 20 | 21 | export async function sendCoins(input) { 22 | const provider = globalThis.blockcore; 23 | 24 | var data = JSON.parse(input) 25 | const result = await provider.request({ 26 | method: 'transaction.send', 27 | params: [data], 28 | }); 29 | console.log('Result:', result); 30 | return JSON.stringify(result); 31 | } 32 | 33 | export async function swapCoins(input) { 34 | const provider = globalThis.blockcore; 35 | 36 | var data = JSON.parse(input) 37 | const result = await provider.request({ 38 | method: 'atomicswaps.send', 39 | params: [data], 40 | }); 41 | console.log('Result:', result); 42 | return JSON.stringify(result.response); 43 | } 44 | 45 | export async function getWallet(key) { 46 | const provider = globalThis.blockcore; 47 | 48 | const result = await provider.request({ 49 | method: 'wallets', 50 | params: [{ key: key }], 51 | }); 52 | console.log('Result:', result); 53 | return JSON.stringify(result); 54 | } 55 | 56 | export async function getSwapKey(key, walletId, accountId, includePrivateKey) { 57 | const provider = globalThis.blockcore; 58 | 59 | const result = await provider.request({ 60 | method: 'atomicswaps.key', 61 | params: [{ key: key, walletId: walletId, accountId: accountId, includePrivateKey: includePrivateKey }], 62 | }); 63 | console.log('Result:', result); 64 | return JSON.stringify(result); 65 | } 66 | 67 | export async function getSwapSecret(key, walletId, accountId, message) { 68 | const provider = globalThis.blockcore; 69 | 70 | const result = await provider.request({ 71 | method: 'atomicswaps.secret', 72 | params: [{ key: key, walletId: walletId, accountId: accountId, message: message }], 73 | }); 74 | console.log('Result:', result); 75 | return JSON.stringify(result); 76 | } 77 | 78 | export async function signMessageAnyAccountJson(value) { 79 | const message = JSON.parse(value); 80 | 81 | const provider = globalThis.blockcore; 82 | 83 | const result = await provider.request({ 84 | method: 'signMessage', 85 | params: [{ message: message }], 86 | }); 87 | 88 | console.log('Result:', result); 89 | return JSON.stringify(result); 90 | 91 | //this.signedJsonKey = result.key; 92 | //this.signedJsonSignature = result.signature; 93 | //this.signedJsonNetwork = result.network; 94 | //const preparedMessage = JSON.stringify(message); 95 | //this.signedJsonValidSignature = bitcoinMessage.verify(preparedMessage, result.key, result.signature); 96 | } 97 | 98 | export async function paymentRequest(network, amount) { 99 | try { 100 | const provider = globalThis.blockcore; 101 | 102 | var result = await provider.request({ 103 | method: 'payment', 104 | params: [ 105 | { 106 | network: network.toLowerCase(), 107 | amount: amount, 108 | address: 'Ccoquhaae7u6ASqQ5BiYueASz8EavUXrKn', 109 | label: 'Your Local Info', 110 | message: 'Invoice Number 5', 111 | data: 'MzExMzUzNDIzNDY', 112 | id: '4324', 113 | }, 114 | ], 115 | }); 116 | 117 | console.log('Result:', result); 118 | return JSON.stringify(result); 119 | } catch (err) { 120 | console.error(err); 121 | } 122 | } 123 | 124 | async function request(method, params) { 125 | if (!params) { 126 | params = []; 127 | } 128 | const provider = globalThis.blockcore; 129 | const result = await provider.request({ 130 | method: method, 131 | params: params, 132 | }); 133 | console.log('Result:', result); 134 | 135 | return result; 136 | } 137 | 138 | export async function didSupportedMethods() { 139 | const result = await request('did.supportedMethods'); 140 | return JSON.stringify(result.response); 141 | } 142 | 143 | export async function didRequest(methods) { 144 | const result = await request('did.request', [ 145 | { 146 | challenge: 'fc0949c4-fd9c-4825-b18d-79348e358156', 147 | methods: methods, 148 | reason: 'Sample app need access to any of your DIDs.', 149 | }, 150 | ]); 151 | 152 | return JSON.stringify(result.response); 153 | } 154 | 155 | export async function signMessage(msg) { 156 | const provider = globalThis.blockcore; 157 | let signature; 158 | try { 159 | signature = await provider.request({ method: "signMessage", params: [{ scheme: "schnorr", message: msg }] }); 160 | return JSON.stringify(signature); 161 | } 162 | catch (error) { 163 | console.error("Error: " + error.message); 164 | // User denied account access... 165 | throw "UserDenied"; 166 | } 167 | } 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/Blockcore.MetaMask.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | enable 6 | nullable 7 | True 8 | True 9 | Blockcore 10 | 1.0.0 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/Enums/Chain.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Blockcore.AtomicSwaps.MetaMask.Enums 8 | { 9 | /// 10 | /// https://docs.metamask.io/guide/ethereum-provider.html#chain-ids 11 | /// 12 | public enum Chain 13 | { 14 | Mainnet = 1, 15 | Ropsten = 3, 16 | Rinkeby = 4, 17 | Goerli = 5, 18 | Kovan = 42, 19 | BinanceSmartChain = 56, 20 | BinanceTestnet = 97 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/Exceptions/NoMetaMaskException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Blockcore.AtomicSwaps.MetaMask.Exceptions 8 | { 9 | public class NoMetaMaskException : ApplicationException 10 | { 11 | public NoMetaMaskException() : base("MetaMask is not installed.") 12 | { 13 | 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/Exceptions/UserDeniedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Blockcore.AtomicSwaps.MetaMask.Exceptions 8 | { 9 | public class UserDeniedException : ApplicationException 10 | { 11 | public UserDeniedException() : base("User denied access to MetaMask.") 12 | { 13 | 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/Extensions/HexExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Numerics; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Blockcore.AtomicSwaps.MetaMask.Extensions 9 | { 10 | public static class HexExtensions 11 | { 12 | public static long HexToInt(this string hexString) 13 | { 14 | if (hexString.StartsWith("0x")) 15 | hexString = hexString[2..]; 16 | 17 | return long.Parse(hexString, System.Globalization.NumberStyles.HexNumber); 18 | } 19 | public static BigInteger HexToBigInteger(this string hexString) 20 | { 21 | if (hexString.StartsWith("0x")) 22 | hexString = hexString[2..]; 23 | 24 | return BigInteger.Parse(hexString, System.Globalization.NumberStyles.HexNumber); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/Extensions/SendTransactionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Nethereum.ABI.FunctionEncoding; 2 | using Nethereum.ABI.Model; 3 | using Nethereum.JsonRpc.Client; 4 | using Nethereum.RPC.Eth.DTOs; 5 | using Nethereum.RPC.Eth.Transactions; 6 | using System.Numerics; 7 | using System.Threading.Tasks; 8 | 9 | namespace Blockcore.AtomicSwaps.MetaMask 10 | { 11 | public static class SendTransactionExtensions 12 | { 13 | private static async Task CallFunction(IMetaMaskService metaMask, string funcName, string contractAddress, BigInteger valueInWei, Parameter[] paramaters, params object[] values) 14 | { 15 | FunctionABI function = new FunctionABI(funcName, false); 16 | 17 | function.InputParameters = paramaters; 18 | var functionCallEncoder = new FunctionCallEncoder(); 19 | 20 | var data = functionCallEncoder.EncodeRequest(function.Sha3Signature, paramaters, 21 | values); 22 | 23 | data = data[2..]; 24 | var result = await metaMask.SendTransaction(contractAddress, valueInWei, data); 25 | 26 | return result; 27 | } 28 | 29 | private static async Task GetTransactionReceipt(string txHash, IClient client, int interval = 1000) 30 | { 31 | EthGetTransactionReceipt getTransactionReceipt = new EthGetTransactionReceipt(client); 32 | TransactionReceipt? receipt = null; 33 | while (receipt == null) 34 | { 35 | receipt = await getTransactionReceipt.SendRequestAsync(txHash); 36 | await Task.Delay(interval); 37 | } 38 | return receipt; 39 | } 40 | 41 | /// 42 | /// Send transaction to smart contract and wait for receipt 43 | /// 44 | /// Web3 Client 45 | /// Function To Call 46 | /// Smart Contract Address 47 | /// Value In Wei 48 | /// Function Parameters 49 | /// Function Values 50 | /// Receipt Of Transaction 51 | public static async Task SendTransactionAndWaitForReceipt 52 | ( 53 | this IMetaMaskService metaMask, 54 | IClient client, 55 | string funcName, 56 | string contractAddress, 57 | BigInteger value, 58 | Parameter[] inputParams, 59 | params object[] values 60 | ) 61 | { 62 | var txHash = await CallFunction(metaMask, funcName, contractAddress, value, inputParams, values); 63 | var receipt = await GetTransactionReceipt(txHash, client); 64 | return receipt; 65 | } 66 | 67 | /// 68 | /// Send transaction to smart contract and wait for receipt 69 | /// 70 | /// Web3 Client 71 | /// Function To Call 72 | /// Smart Contract Address 73 | /// Value In Wei 74 | /// Function Parameters 75 | /// Function Values 76 | /// The interval at which we check for a transaction receipt 77 | /// Receipt Of Transaction 78 | public static async Task SendTransactionAndWaitForReceipt 79 | ( 80 | this IMetaMaskService metaMask, 81 | IClient client, 82 | string funcName, 83 | string contractAddress, 84 | BigInteger value, 85 | Parameter[] inputParams, 86 | int interval = 1000, 87 | params object[] values 88 | ) 89 | { 90 | var txHash = await CallFunction(metaMask, funcName, contractAddress, value, inputParams, values); 91 | return await GetTransactionReceipt(txHash, client, interval); 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/IMetaMaskService.cs: -------------------------------------------------------------------------------- 1 | using Blockcore.AtomicSwaps.MetaMask.Enums; 2 | using Blockcore.AtomicSwaps.MetaMask.Extensions; 3 | using Microsoft.JSInterop; 4 | using System; 5 | using System.Numerics; 6 | using System.Threading.Tasks; 7 | 8 | namespace Blockcore.AtomicSwaps.MetaMask 9 | { 10 | public interface IMetaMaskService 11 | { 12 | public static event Func? AccountChangedEvent; 13 | public static event Func<(long, Chain), Task>? ChainChangedEvent; 14 | 15 | ValueTask ConnectMetaMask(); 16 | ValueTask DisposeAsync(); 17 | ValueTask GenericRpc(string method, params dynamic[]? args); 18 | Task GetBalance(string address, string block = "latest"); 19 | ValueTask GetSelectedAddress(); 20 | ValueTask<(long chainId, Chain chain)> GetSelectedChain(); 21 | ValueTask GetTransactionCount(); 22 | ValueTask HasMetaMask(); 23 | ValueTask IsSiteConnected(); 24 | ValueTask ListenToEvents(); 25 | ValueTask LoadScripts(IJSRuntime jsRuntime); 26 | Task RequestAccounts(); 27 | ValueTask SendTransaction(string to, BigInteger weiValue, string? data = null); 28 | ValueTask SignTypedData(string label, string value); 29 | ValueTask SignTypedDataV4(string typedData); 30 | 31 | [JSInvokable()] 32 | static async Task OnAccountsChanged(string selectedAccount) 33 | { 34 | if (AccountChangedEvent != null) 35 | { 36 | await AccountChangedEvent.Invoke(selectedAccount); 37 | } 38 | } 39 | 40 | [JSInvokable()] 41 | static async Task OnChainChanged(string chainhex) 42 | { 43 | if (ChainChangedEvent != null) 44 | { 45 | await ChainChangedEvent.Invoke(ChainHexToChainResponse(chainhex)); 46 | } 47 | } 48 | 49 | protected static (long chainId, Chain chain) ChainHexToChainResponse(string chainHex) 50 | { 51 | long chainId = chainHex.HexToInt(); 52 | return (chainId, (Chain)chainId); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/MetaMaskService.cs: -------------------------------------------------------------------------------- 1 | using Blockcore.AtomicSwaps.MetaMask.Enums; 2 | using Blockcore.AtomicSwaps.MetaMask.Exceptions; 3 | using Blockcore.AtomicSwaps.MetaMask.Extensions; 4 | using Microsoft.JSInterop; 5 | using System; 6 | using System.Numerics; 7 | using System.Text.Json; 8 | using System.Threading.Tasks; 9 | 10 | namespace Blockcore.AtomicSwaps.MetaMask 11 | { 12 | // This class provides JavaScript functionality for MetaMask wrapped 13 | // in a .NET class for easy consumption. The associated JavaScript module is 14 | // loaded on demand when first needed. 15 | // 16 | // This class can be registered as scoped DI service and then injected into Blazor 17 | // components for use. 18 | 19 | public class MetaMaskService : IAsyncDisposable, IMetaMaskService 20 | { 21 | private readonly Lazy> moduleTask; 22 | 23 | //public static event Func? ConnectEvent; 24 | //public static event Func? DisconnectEvent; 25 | 26 | public MetaMaskService(IJSRuntime jsRuntime) 27 | { 28 | moduleTask = new(() => LoadScripts(jsRuntime).AsTask()); 29 | } 30 | 31 | public ValueTask LoadScripts(IJSRuntime jsRuntime) 32 | { 33 | //await jsRuntime.InvokeAsync("import", "https://cdn.ethers.io/lib/ethers-5.1.0.umd.min.js"); 34 | return jsRuntime.InvokeAsync("import", "./_content/Blockcore.MetaMask/metaMask.js"); 35 | } 36 | 37 | public async ValueTask ConnectMetaMask() 38 | { 39 | var module = await moduleTask.Value; 40 | try 41 | { 42 | await module.InvokeVoidAsync("checkMetaMask"); 43 | } 44 | catch (Exception ex) 45 | { 46 | HandleExceptions(ex); 47 | throw; 48 | } 49 | } 50 | 51 | public async ValueTask HasMetaMask() 52 | { 53 | var module = await moduleTask.Value; 54 | try 55 | { 56 | return await module.InvokeAsync("hasMetaMask"); 57 | } 58 | catch (Exception ex) 59 | { 60 | HandleExceptions(ex); 61 | throw; 62 | } 63 | } 64 | 65 | public async ValueTask IsSiteConnected() 66 | { 67 | var module = await moduleTask.Value; 68 | try 69 | { 70 | return await module.InvokeAsync("isSiteConnected"); 71 | } 72 | catch (Exception ex) 73 | { 74 | HandleExceptions(ex); 75 | throw; 76 | } 77 | } 78 | 79 | public async ValueTask ListenToEvents() 80 | { 81 | var module = await moduleTask.Value; 82 | try 83 | { 84 | await module.InvokeVoidAsync("listenToChangeEvents"); 85 | } 86 | catch (Exception ex) 87 | { 88 | HandleExceptions(ex); 89 | throw; 90 | } 91 | } 92 | 93 | public async ValueTask GetSelectedAddress() 94 | { 95 | var module = await moduleTask.Value; 96 | try 97 | { 98 | return await module.InvokeAsync("getSelectedAddress", null); 99 | } 100 | catch (Exception ex) 101 | { 102 | HandleExceptions(ex); 103 | throw; 104 | } 105 | } 106 | 107 | public async ValueTask<(long chainId, Chain chain)> GetSelectedChain() 108 | { 109 | var module = await moduleTask.Value; 110 | try 111 | { 112 | string chainHex = await module.InvokeAsync("getSelectedChain", null); 113 | return IMetaMaskService.ChainHexToChainResponse(chainHex); 114 | } 115 | catch (Exception ex) 116 | { 117 | HandleExceptions(ex); 118 | throw; 119 | } 120 | } 121 | 122 | public async ValueTask GetTransactionCount() 123 | { 124 | var module = await moduleTask.Value; 125 | try 126 | { 127 | var result = await module.InvokeAsync("getTransactionCount"); 128 | var resultString = result.GetString(); 129 | if (resultString != null) 130 | { 131 | long intValue = resultString.HexToInt(); 132 | return intValue; 133 | } 134 | return 0; 135 | } 136 | catch (Exception ex) 137 | { 138 | HandleExceptions(ex); 139 | throw; 140 | } 141 | } 142 | 143 | public async ValueTask SignTypedData(string label, string value) 144 | { 145 | var module = await moduleTask.Value; 146 | try 147 | { 148 | return await module.InvokeAsync("signTypedData", label, value); 149 | } 150 | catch (Exception ex) 151 | { 152 | HandleExceptions(ex); 153 | throw; 154 | } 155 | } 156 | 157 | public async ValueTask SignTypedDataV4(string typedData) 158 | { 159 | var module = await moduleTask.Value; 160 | try 161 | { 162 | return await module.InvokeAsync("signTypedDataV4", typedData); 163 | } 164 | catch (Exception ex) 165 | { 166 | HandleExceptions(ex); 167 | throw; 168 | } 169 | } 170 | 171 | public async ValueTask SendTransaction(string to, BigInteger weiValue, string? data = null) 172 | { 173 | var module = await moduleTask.Value; 174 | try 175 | { 176 | string hexValue = "0x" + weiValue.ToString("X"); 177 | return await module.InvokeAsync("sendTransaction", to, hexValue, data); 178 | } 179 | catch (Exception ex) 180 | { 181 | HandleExceptions(ex); 182 | throw; 183 | } 184 | } 185 | 186 | public async ValueTask GenericRpc(string method, params dynamic?[]? args) 187 | { 188 | var module = await moduleTask.Value; 189 | try 190 | { 191 | return await module.InvokeAsync("genericRpc", method, args); 192 | } 193 | catch (Exception ex) 194 | { 195 | HandleExceptions(ex); 196 | throw; 197 | } 198 | } 199 | 200 | public async Task RequestAccounts() 201 | { 202 | var result = await GenericRpc("eth_requestAccounts"); 203 | 204 | return result.ToString(); 205 | } 206 | 207 | public async Task GetBalance(string address, string block = "latest") 208 | { 209 | var result = await GenericRpc("eth_getBalance", address, block); 210 | 211 | string hex = result.ToString(); 212 | 213 | return hex.HexToBigInteger(); 214 | } 215 | 216 | //[JSInvokable()] 217 | //public static async Task OnConnect() 218 | //{ 219 | // Console.WriteLine("connected"); 220 | // if (ConnectEvent != null) 221 | // { 222 | // await ConnectEvent.Invoke(); 223 | // } 224 | //} 225 | 226 | //[JSInvokable()] 227 | //public static async Task OnDisconnect() 228 | //{ 229 | // Console.WriteLine("disconnected"); 230 | // if (DisconnectEvent != null) 231 | // { 232 | // await DisconnectEvent.Invoke(); 233 | // } 234 | //} 235 | 236 | public async ValueTask DisposeAsync() 237 | { 238 | if (moduleTask.IsValueCreated) 239 | { 240 | var module = await moduleTask.Value; 241 | await module.DisposeAsync(); 242 | } 243 | } 244 | 245 | private void HandleExceptions(Exception ex) 246 | { 247 | switch (ex.Message) 248 | { 249 | case "NoMetaMask": 250 | throw new NoMetaMaskException(); 251 | case "UserDenied": 252 | throw new UserDeniedException(); 253 | } 254 | } 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/Metamask.razor: -------------------------------------------------------------------------------- 1 | @page "/metamask" 2 | @using Nethereum.Signer 3 | 4 | MetaMask 5 | 6 |

MetaMask

7 | 8 | @if (!HasMetaMask) 9 | { 10 |

No MetaMask detected. Please install MetaMask.

11 | } 12 | else if (string.IsNullOrEmpty(SelectedAddress)) 13 | { 14 | 15 |
16 |
17 | } 18 | else 19 | { 20 | 21 |
22 |

@SelectedAddress

23 |
24 | 25 | 26 |
27 |

@SelectedChain

28 |
29 | 30 | 31 |
32 |

@TransactionCount

33 |
34 | 35 | 36 |
37 |

@SignedData

38 |
39 | 40 | 41 |
42 |

@SignedDataV4

43 |
44 | 45 | 46 | 47 | 48 | 49 |
50 |
51 |

@RpcResult

52 |
53 | 54 |

Kovan testnet only:

55 |

Interact with a smart contract. These two example smart contracts are only deployed to the Kovan testnet. Make sure to select Kovan in MetaMask

56 | 57 | @if (Chain == Blockcore.AtomicSwaps.MetaMask.Enums.Chain.Kovan) 58 | { 59 | 60 |
61 | 62 | 63 |
64 |

@FunctionResult

65 |
66 | } 67 | else 68 | { 69 |

Please switch to Kovan testnet!

70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/Metamask.razor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Numerics; 4 | using System.Threading.Tasks; 5 | using Blockcore.AtomicSwaps.MetaMask; 6 | using Blockcore.AtomicSwaps.MetaMask.Enums; 7 | using Blockcore.AtomicSwaps.MetaMask.Exceptions; 8 | using Blockcore.AtomicSwaps.MetaMask.Models; 9 | using Microsoft.AspNetCore.Components; 10 | using Nethereum.ABI.FunctionEncoding; 11 | using Nethereum.ABI.Model; 12 | using Nethereum.Web3; 13 | 14 | namespace Blockcore.MetaMask 15 | { 16 | 17 | public partial class Metamask : IDisposable 18 | { 19 | [Inject] 20 | public IMetaMaskService MetaMaskService { get; set; } = default!; 21 | 22 | public bool HasMetaMask { get; set; } 23 | public string? SelectedAddress { get; set; } 24 | public string? SelectedChain { get; set; } 25 | public string? TransactionCount { get; set; } 26 | public string? SignedData { get; set; } 27 | public string? SignedDataV4 { get; set; } 28 | public string? FunctionResult { get; set; } 29 | public string? RpcResult { get; set; } 30 | public Chain? Chain { get; set; } 31 | 32 | protected override async Task OnInitializedAsync() 33 | { 34 | //Subscribe to events 35 | IMetaMaskService.AccountChangedEvent += MetaMaskService_AccountChangedEvent; 36 | IMetaMaskService.ChainChangedEvent += MetaMaskService_ChainChangedEvent; 37 | 38 | HasMetaMask = await MetaMaskService.HasMetaMask(); 39 | if (HasMetaMask) 40 | await MetaMaskService.ListenToEvents(); 41 | 42 | bool isSiteConnected = await MetaMaskService.IsSiteConnected(); 43 | if (isSiteConnected) 44 | { 45 | await GetSelectedAddress(); 46 | await GetSelectedNetwork(); 47 | } 48 | 49 | } 50 | 51 | private async Task MetaMaskService_ChainChangedEvent((long, Chain) arg) 52 | { 53 | await GetSelectedNetwork(); 54 | StateHasChanged(); 55 | } 56 | 57 | private async Task MetaMaskService_AccountChangedEvent(string arg) 58 | { 59 | await GetSelectedAddress(); 60 | StateHasChanged(); 61 | } 62 | 63 | public async Task ConnectMetaMask() 64 | { 65 | await MetaMaskService.ConnectMetaMask(); 66 | await GetSelectedAddress(); 67 | } 68 | 69 | public async Task GetSelectedAddress() 70 | { 71 | SelectedAddress = await MetaMaskService.GetSelectedAddress(); 72 | Console.WriteLine($"Address: {SelectedAddress}"); 73 | } 74 | 75 | public async Task GetSelectedNetwork() 76 | { 77 | var chainInfo = await MetaMaskService.GetSelectedChain(); 78 | Chain = chainInfo.chain; 79 | 80 | SelectedChain = $"ChainID: {chainInfo.chainId}, Name: {chainInfo.chain.ToString()}"; 81 | Console.WriteLine($"ChainID: {chainInfo.chainId}"); 82 | } 83 | 84 | public async Task GetTransactionCount() 85 | { 86 | var transactionCount = await MetaMaskService.GetTransactionCount(); 87 | TransactionCount = $"Transaction count: {transactionCount}"; 88 | } 89 | 90 | public async Task SignData(string label, string value) 91 | { 92 | try 93 | { 94 | var result = await MetaMaskService.SignTypedData("test label", "test value"); 95 | SignedData = $"Signed: {result}"; 96 | } 97 | catch (UserDeniedException) 98 | { 99 | SignedData = "User Denied"; 100 | } 101 | catch (Exception ex) 102 | { 103 | SignedData = $"Exception: {ex}"; 104 | } 105 | } 106 | 107 | public async Task SignDataV4() 108 | { 109 | try 110 | { 111 | var chainInfo = await MetaMaskService.GetSelectedChain(); 112 | 113 | var data = new TypedDataPayload 114 | { 115 | Domain = new AtomicSwaps.MetaMask.Models.Domain 116 | { 117 | Name = "AAA", 118 | Version = "1", 119 | ChainId = chainInfo.chainId 120 | }, 121 | Types = new Dictionary 122 | { 123 | ["EIP712Domain"] = new[] 124 | { 125 | new TypeMemberValue { Name = "name", Type = "string" }, 126 | new TypeMemberValue { Name = "version", Type = "string" }, 127 | new TypeMemberValue { Name = "chainId", Type = "uint256" } 128 | }, 129 | ["Message"] = new[] 130 | { 131 | new TypeMemberValue { Name = "contents", Type = "string" } 132 | } 133 | }, 134 | PrimaryType = "Message", 135 | Message = new AtomicSwaps.MetaMask.Models.Message 136 | { 137 | contents = "Blockcore" 138 | } 139 | }; 140 | 141 | var result = await MetaMaskService.SignTypedDataV4(data.ToJson()); 142 | 143 | SignedDataV4 = $"Signed: {result}"; 144 | } 145 | catch (UserDeniedException) 146 | { 147 | SignedDataV4 = "User Denied"; 148 | } 149 | catch (Exception ex) 150 | { 151 | SignedDataV4 = $"Exception: {ex}"; 152 | } 153 | } 154 | 155 | public async Task CallSmartContractFunctionExample1() 156 | { 157 | try 158 | { 159 | string address = "0x21253c6f5E16a56031dc8d8AF0bb372bc4A4DfDA"; 160 | BigInteger weiValue = 0; 161 | string data = GetEncodedFunctionCall(); 162 | 163 | data = data[2..]; //Remove the 0x from the generated string 164 | var result = await MetaMaskService.SendTransaction(address, weiValue, data); 165 | FunctionResult = $"TX Hash: {result}"; 166 | } 167 | catch (UserDeniedException) 168 | { 169 | FunctionResult = "User Denied"; 170 | } 171 | catch (Exception ex) 172 | { 173 | FunctionResult = $"Exception: {ex}"; 174 | } 175 | } 176 | 177 | public async Task CallSmartContractFunctionExample2() 178 | { 179 | try 180 | { 181 | string address = "0x722BcdA7BD1a0f8C1c9b7c0eefabE36c1f0fBF2a"; 182 | BigInteger weiValue = 1000000000000000; 183 | string data = GetEncodedFunctionCallExample2(); 184 | 185 | data = data[2..]; //Remove the 0x from the generated string 186 | var result = await MetaMaskService.SendTransaction(address, weiValue, data); 187 | FunctionResult = $"TX Hash: {result}"; 188 | } 189 | catch (UserDeniedException) 190 | { 191 | FunctionResult = "User Denied"; 192 | } 193 | catch (Exception ex) 194 | { 195 | FunctionResult = $"Exception: {ex}"; 196 | } 197 | } 198 | 199 | private string GetEncodedFunctionCall() 200 | { 201 | //This example uses Nethereum.ABI to create the ABI encoded string to call a smart contract function 202 | 203 | //Smart contract has a function called "share" 204 | FunctionABI function = new FunctionABI("share", false); 205 | 206 | //With 4 inputs 207 | var inputsParameters = new[] { 208 | new Parameter("address", "receiver"), 209 | new Parameter("string", "appId"), 210 | new Parameter("string", "shareType"), 211 | new Parameter("string", "data") 212 | }; 213 | function.InputParameters = inputsParameters; 214 | 215 | var functionCallEncoder = new FunctionCallEncoder(); 216 | 217 | var data = functionCallEncoder.EncodeRequest(function.Sha3Signature, inputsParameters, 218 | "0x92B143F46C3F8B4242bA85F800579cdF73882e98", 219 | "Blockcore.AtomicSwaps.MetaMask", 220 | "Sample", 221 | DateTime.UtcNow.ToString()); 222 | return data; 223 | } 224 | 225 | private string GetEncodedFunctionCallExample2() 226 | { 227 | //This example uses Nethereum.ABI to create the ABI encoded string to call a smart contract function 228 | 229 | //Smart contract has a function called "share" 230 | FunctionABI function = new FunctionABI("setColor", false); 231 | 232 | //With 4 inputs 233 | var inputsParameters = new[] { 234 | new Parameter("string", "color") 235 | }; 236 | function.InputParameters = inputsParameters; 237 | 238 | var functionCallEncoder = new FunctionCallEncoder(); 239 | 240 | var data = functionCallEncoder.EncodeRequest(function.Sha3Signature, inputsParameters, new object[] { "green" }); 241 | 242 | return data; 243 | } 244 | 245 | 246 | public async Task GenericRpc() 247 | { 248 | var result = await MetaMaskService.RequestAccounts(); 249 | RpcResult = $"RPC result: {result}"; 250 | } 251 | 252 | public async Task GetBalance() 253 | { 254 | var address = await MetaMaskService.GetSelectedAddress(); 255 | var result = await MetaMaskService.GetBalance(address); 256 | var balance = Web3.Convert.FromWei(result); 257 | RpcResult = $"Balance result: {Math.Round(balance, 4)} ETH"; 258 | } 259 | 260 | public void Dispose() 261 | { 262 | IMetaMaskService.AccountChangedEvent -= MetaMaskService_AccountChangedEvent; 263 | IMetaMaskService.ChainChangedEvent -= MetaMaskService_ChainChangedEvent; 264 | } 265 | } 266 | 267 | } 268 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/Models/TypedDataPayload.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Numerics; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Serialization; 5 | 6 | namespace Blockcore.AtomicSwaps.MetaMask.Models 7 | { 8 | public record struct Message(string contents); 9 | 10 | 11 | public class TypedDataPayload 12 | { 13 | public Dictionary Types { get; set; } = new(); 14 | public string? PrimaryType { get; set; } 15 | public Domain? Domain { get; set; } 16 | public T? Message { get; set; } 17 | 18 | 19 | public string ToJson() 20 | { 21 | var serializerSettings = new JsonSerializerSettings 22 | { 23 | ContractResolver = new CamelCasePropertyNamesContractResolver() 24 | { 25 | NamingStrategy = new CamelCaseNamingStrategy() 26 | { 27 | ProcessDictionaryKeys = false 28 | } 29 | }, 30 | 31 | DefaultValueHandling = DefaultValueHandling.Ignore 32 | }; 33 | return JsonConvert.SerializeObject(this, serializerSettings); 34 | } 35 | } 36 | 37 | public class Domain 38 | { 39 | public string? Name { get; set; } 40 | public string? Version { get; set; } 41 | public BigInteger? ChainId { get; set; } 42 | } 43 | 44 | public class TypeMemberValue 45 | { 46 | public string? Name { get; set; } 47 | public string? Type { get; set; } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.JSInterop; 3 | 4 | namespace Blockcore.AtomicSwaps.MetaMask 5 | { 6 | public static class ServiceCollectionExtensions 7 | { 8 | public static void AddMetaMask(this IServiceCollection services) 9 | { 10 | services.AddScoped(sp => new MetaMaskService(sp.GetRequiredService())); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/Blockcore.MetaMask/wwwroot/metaMask.js: -------------------------------------------------------------------------------- 1 | // This is a JavaScript module that is loaded on demand. It can export any number of 2 | // functions, and may import other JavaScript modules if required. 3 | 4 | export async function checkMetaMask() { 5 | // Modern dapp browsers... 6 | if (window.ethereum) { 7 | if (ethereum.selectedAddress === null || ethereum.selectedAddress === undefined) { 8 | try { 9 | // Request account access if needed 10 | await requestAccounts(); 11 | } catch (error) { 12 | // User denied account access... 13 | throw "UserDenied" 14 | } 15 | } 16 | else { 17 | console.log("Selected:" + ethereum.selectedAddress); 18 | } 19 | } 20 | // Non-dapp browsers... 21 | else { 22 | throw "NoMetaMask" 23 | } 24 | } 25 | 26 | export async function requestAccounts() { 27 | console.log('reqAccount'); 28 | var result = await ethereum.request({ 29 | method: 'eth_requestAccounts', 30 | }); 31 | return result; 32 | } 33 | 34 | export function hasMetaMask() { 35 | return (window.ethereum != undefined); 36 | } 37 | 38 | export function isSiteConnected() { 39 | return (window.ethereum != undefined && (ethereum.selectedAddress != undefined || ethereum.selectedAddress != null)); 40 | } 41 | 42 | export async function getSelectedAddress() { 43 | await checkMetaMask(); 44 | 45 | return ethereum.selectedAddress; 46 | } 47 | 48 | export async function listenToChangeEvents() { 49 | if (hasMetaMask()) { 50 | //ethereum.on("connect", function () { 51 | // DotNet.invokeMethodAsync('Blockcore.AtomicSwaps.MetaMask', 'OnConnect'); 52 | //}); 53 | 54 | //ethereum.on("disconnect", function () { 55 | // DotNet.invokeMethodAsync('Blockcore.AtomicSwaps.MetaMask', 'OnDisconnect'); 56 | //}); 57 | 58 | ethereum.on("accountsChanged", function (accounts) { 59 | DotNet.invokeMethodAsync('Blockcore.AtomicSwaps.MetaMask', 'OnAccountsChanged', accounts[0]); 60 | }); 61 | 62 | ethereum.on("chainChanged", function (chainId) { 63 | DotNet.invokeMethodAsync('Blockcore.AtomicSwaps.MetaMask', 'OnChainChanged', chainId); 64 | }); 65 | } 66 | } 67 | 68 | export async function getSelectedChain() { 69 | await checkMetaMask(); 70 | 71 | var result = await ethereum.request({ 72 | method: 'eth_chainId' 73 | }); 74 | return result; 75 | } 76 | 77 | export async function getTransactionCount() { 78 | await checkMetaMask(); 79 | 80 | var result = await ethereum.request({ 81 | method: 'eth_getTransactionCount', 82 | params: 83 | [ 84 | ethereum.selectedAddress, 85 | 'latest' 86 | ] 87 | 88 | }); 89 | return result; 90 | } 91 | 92 | export async function signTypedData(label, value) { 93 | await checkMetaMask(); 94 | 95 | const msgParams = [ 96 | { 97 | type: 'string', // Valid solidity type 98 | name: label, 99 | value: value 100 | } 101 | ] 102 | 103 | try { 104 | var result = await ethereum.request({ 105 | method: 'eth_signTypedData', 106 | params: 107 | [ 108 | msgParams, 109 | ethereum.selectedAddress 110 | ] 111 | }); 112 | 113 | return result; 114 | } catch (error) { 115 | // User denied account access... 116 | throw "UserDenied" 117 | } 118 | } 119 | 120 | export async function signTypedDataV4(typedData) { 121 | await checkMetaMask(); 122 | 123 | try { 124 | var result = await ethereum.request({ 125 | method: 'eth_signTypedData_v4', 126 | params: 127 | [ 128 | ethereum.selectedAddress, 129 | typedData 130 | ], 131 | from: ethereum.selectedAddress 132 | }); 133 | 134 | return result; 135 | } catch (error) { 136 | // User denied account access... 137 | throw "UserDenied" 138 | } 139 | } 140 | 141 | export async function sendTransaction(to, value, data) { 142 | await checkMetaMask(); 143 | 144 | const transactionParameters = { 145 | to: to, 146 | from: ethereum.selectedAddress, // must match user's active address. 147 | value: value, 148 | data: data 149 | }; 150 | 151 | try { 152 | var result = await ethereum.request({ 153 | method: 'eth_sendTransaction', 154 | params: [transactionParameters] 155 | }); 156 | 157 | return result; 158 | } catch (error) { 159 | if (error.code == 4001) { 160 | throw "UserDenied" 161 | } 162 | throw error; 163 | } 164 | } 165 | 166 | export async function genericRpc(method, params) { 167 | await checkMetaMask(); 168 | 169 | var result = await ethereum.request({ 170 | method: method, 171 | params: params 172 | }); 173 | 174 | return result; 175 | } -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/dapp-wasm.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33110.190 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dapp-wasm", "dapp-wasm\dapp-wasm.csproj", "{791D7A5E-0A39-49E0-BABA-E11A6581FCFF}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.MetaMask", "Blockcore.MetaMask\Blockcore.MetaMask.csproj", "{E959D45D-6931-4977-89A7-60BF2FDDE18D}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.AtomicSwaps.BlockcoreDns", "Blockcore.AtomicSwaps.BlockcoreDns\Blockcore.AtomicSwaps.BlockcoreDns.csproj", "{6E5116F7-7A42-45C8-A389-6BD7DBBEF052}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.AtomicSwaps.BlockcoreWallet", "Blockcore.AtomicSwaps.BlockcoreWallet\Blockcore.AtomicSwaps.BlockcoreWallet.csproj", "{602033E1-57C3-458F-BC2C-B0B1E88A91E7}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {791D7A5E-0A39-49E0-BABA-E11A6581FCFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {791D7A5E-0A39-49E0-BABA-E11A6581FCFF}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {791D7A5E-0A39-49E0-BABA-E11A6581FCFF}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {791D7A5E-0A39-49E0-BABA-E11A6581FCFF}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {E959D45D-6931-4977-89A7-60BF2FDDE18D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {E959D45D-6931-4977-89A7-60BF2FDDE18D}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {E959D45D-6931-4977-89A7-60BF2FDDE18D}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {E959D45D-6931-4977-89A7-60BF2FDDE18D}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {6E5116F7-7A42-45C8-A389-6BD7DBBEF052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {6E5116F7-7A42-45C8-A389-6BD7DBBEF052}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {6E5116F7-7A42-45C8-A389-6BD7DBBEF052}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {6E5116F7-7A42-45C8-A389-6BD7DBBEF052}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {602033E1-57C3-458F-BC2C-B0B1E88A91E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {602033E1-57C3-458F-BC2C-B0B1E88A91E7}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {602033E1-57C3-458F-BC2C-B0B1E88A91E7}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {602033E1-57C3-458F-BC2C-B0B1E88A91E7}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {A87AE351-CD8C-43F7-A8F8-F88181F0352E} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/dapp-wasm/App.razor: -------------------------------------------------------------------------------- 1 | @using Blockcore.MetaMask 2 | 6 | 7 | 8 | 9 | 10 | 11 | Not found 12 | 13 |

Sorry, there's nothing at this address.

14 |
15 |
16 |
17 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/dapp-wasm/Data/BlockData.cs: -------------------------------------------------------------------------------- 1 | namespace Data; 2 | 3 | public class BlockData 4 | { 5 | public string blockHash { get; set; } 6 | 7 | public int blockIndex { get; set; } 8 | 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/dapp-wasm/Data/BtcDecimalJsonConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Newtonsoft.Json; 4 | 5 | namespace Blockcore.Controllers.Converters 6 | { 7 | /// 8 | /// Converts a decimal value to a string with the minimum number of decimals used by bitcoin (8). 9 | /// 10 | public class BtcDecimalJsonConverter : JsonConverter 11 | { 12 | private const int MinDecimals = 8; 13 | 14 | /// 15 | /// Method for writing a string formatted decimal to Json that truncates at decimal points. 16 | /// A instance. 17 | /// The value to be written. 18 | /// A instance. 19 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 20 | { 21 | decimal btcDecimal = (decimal)value; 22 | string result = btcDecimal.ToString(CultureInfo.InvariantCulture); 23 | if (!result.Contains('.') || result.Split('.')[1].Length < MinDecimals) 24 | { 25 | result = btcDecimal.ToString("0." + new string('0', MinDecimals), CultureInfo.InvariantCulture); 26 | } 27 | 28 | writer.WriteRawValue(result); 29 | } 30 | 31 | /// 32 | /// A method for reading a string formatted decimal in Json that was truncated at decimals. 33 | /// 34 | /// Not implemented. 35 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, 36 | JsonSerializer serializer) 37 | { 38 | throw new NotImplementedException(); 39 | } 40 | 41 | public override bool CanRead => false; 42 | 43 | public override bool CanConvert(Type objectType) => objectType == typeof(decimal); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/dapp-wasm/Data/ToStringJsonConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | 4 | namespace Blockcore.Controllers.Converters 5 | { 6 | public class ToStringJsonConverter : JsonConverter 7 | { 8 | public override bool CanConvert(Type objectType) 9 | { 10 | return true; 11 | } 12 | 13 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 14 | { 15 | writer.WriteValue(value.ToString()); 16 | } 17 | 18 | public override bool CanRead 19 | { 20 | get { return false; } 21 | } 22 | 23 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 24 | { 25 | throw new NotImplementedException(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/dapp-wasm/Data/TransactionModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Blockcore.Consensus.Chain; 4 | using Blockcore.Consensus.ScriptInfo; 5 | using Blockcore.Consensus.TransactionInfo; 6 | using Blockcore.Controllers.Converters; 7 | using Blockcore.Networks; 8 | using NBitcoin; 9 | using NBitcoin.DataEncoders; 10 | using Newtonsoft.Json; 11 | 12 | namespace Blockcore.Controllers.Models 13 | { 14 | /// 15 | /// A class representing a transaction. 16 | /// 17 | public abstract class TransactionModel 18 | { 19 | public TransactionModel(Network network = null) 20 | { 21 | } 22 | 23 | /// 24 | /// Creates a containing the hash of the given transaction. 25 | /// 26 | /// A valid 27 | public TransactionModel(Transaction trx) 28 | { 29 | this.Hex = trx?.ToHex(); 30 | } 31 | 32 | /// The transaction in hexadecimal format. 33 | [JsonProperty(Order = 0, PropertyName = "hex", NullValueHandling = NullValueHandling.Ignore)] 34 | public string Hex { get; set; } 35 | 36 | public override string ToString() 37 | { 38 | return this.Hex; 39 | } 40 | } 41 | 42 | /// 43 | /// Creates a concise transaction model containing the hashed transaction. 44 | /// 45 | [JsonConverter(typeof(ToStringJsonConverter))] 46 | public class TransactionBriefModel : TransactionModel 47 | { 48 | public TransactionBriefModel() 49 | { 50 | } 51 | 52 | public TransactionBriefModel(Transaction trx) : base(trx) 53 | { 54 | } 55 | } 56 | 57 | /// 58 | /// Creates a more robust transaction model. 59 | /// 60 | public class TransactionVerboseModel : TransactionModel 61 | { 62 | public TransactionVerboseModel() 63 | { 64 | } 65 | 66 | /// 67 | /// Initializes a new instance of the class. 68 | /// 69 | /// The transaction. 70 | /// The network the transaction occurred on. 71 | /// A of the block that contains the transaction. 72 | /// A of the current tip. 73 | public TransactionVerboseModel(Transaction trx, Network network, ChainedHeader block = null, ChainedHeader tip = null) : base(trx) 74 | { 75 | if (trx != null) 76 | { 77 | this.TxId = trx.GetHash().ToString(); 78 | this.Hash = trx.HasWitness ? trx.GetWitHash().ToString() : trx.GetHash().ToString(); 79 | this.Size = trx.GetSerializedSize(); 80 | this.VSize = trx.HasWitness ? trx.GetVirtualSize(network.Consensus.Options.WitnessScaleFactor) : trx.GetSerializedSize(); 81 | this.Version = trx.Version; 82 | this.LockTime = trx.LockTime; 83 | 84 | // size = (weight + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR; 85 | // hence, weight = size * WITNESS_SCALE_FACTOR - (WITNESS_SCALE_FACTOR - 1) (only subtract if has witness). 86 | this.Weight = this.VSize * network.Consensus.Options.WitnessScaleFactor - (network.Consensus.Options.WitnessScaleFactor - 1); 87 | 88 | this.VIn = trx.Inputs.Select(txin => new Vin(txin.PrevOut, txin.Sequence, txin.ScriptSig)).ToList(); 89 | 90 | int n = 0; 91 | this.VOut = trx.Outputs.Select(txout => new Vout(n++, txout, network)).ToList(); 92 | 93 | if (block != null) 94 | { 95 | this.BlockHash = block.HashBlock.ToString(); 96 | this.Time = this.BlockTime = Utils.DateTimeToUnixTime(block.Header.BlockTime); 97 | if (tip != null) 98 | this.Confirmations = tip.Height - block.Height + 1; 99 | } 100 | } 101 | } 102 | 103 | /// The transaction id. 104 | [JsonProperty(Order = 1, PropertyName = "txid")] 105 | public string TxId { get; set; } 106 | 107 | /// The transaction hash (differs from txid for witness transactions). 108 | [JsonProperty(Order = 2, PropertyName = "hash")] 109 | public string Hash { get; set; } 110 | 111 | /// The transaction version number (typically 1). 112 | [JsonProperty(Order = 3, PropertyName = "version")] 113 | public uint Version { get; set; } 114 | 115 | /// The serialized transaction size. 116 | [JsonProperty(Order = 4, PropertyName = "size")] 117 | public int Size { get; set; } 118 | 119 | /// The virtual transaction size (differs from size for witness transactions). 120 | [JsonProperty(Order = 5, PropertyName = "vsize")] 121 | public int VSize { get; set; } 122 | 123 | /// The transaction's weight (between vsize*4-3 and vsize*4). 124 | [JsonProperty(Order = 6, PropertyName = "weight", DefaultValueHandling = DefaultValueHandling.Ignore)] 125 | public int Weight { get; set; } 126 | 127 | /// If nonzero, block height or timestamp when transaction is final. 128 | [JsonProperty(Order = 7, PropertyName = "locktime")] 129 | public uint LockTime { get; set; } 130 | 131 | /// A list of inputs. 132 | [JsonProperty(Order = 8, PropertyName = "vin")] 133 | public List VIn { get; set; } 134 | 135 | /// A list of outputs. 136 | [JsonProperty(Order = 9, PropertyName = "vout")] 137 | public List VOut { get; set; } 138 | 139 | /// The hash of the block containing this transaction. 140 | [JsonProperty(Order = 10, PropertyName = "blockhash", DefaultValueHandling = DefaultValueHandling.Ignore)] 141 | public string BlockHash { get; set; } 142 | 143 | /// The number of confirmations of the transaction. 144 | [JsonProperty(Order = 11, PropertyName = "confirmations", DefaultValueHandling = DefaultValueHandling.Ignore)] 145 | public int? Confirmations { get; set; } 146 | 147 | /// The time the transaction was added to a block. 148 | [JsonProperty(Order = 12, PropertyName = "time", DefaultValueHandling = DefaultValueHandling.Ignore)] 149 | public uint? Time { get; set; } 150 | 151 | /// The time the block was confirmed. 152 | [JsonProperty(Order = 13, PropertyName = "blocktime", DefaultValueHandling = DefaultValueHandling.Ignore)] 153 | public uint? BlockTime { get; set; } 154 | } 155 | 156 | /// 157 | /// A class describing a transaction input. 158 | /// 159 | public class Vin 160 | { 161 | public Vin() 162 | { 163 | } 164 | 165 | /// 166 | /// Initializes a instance. 167 | /// 168 | /// The previous output being used as an input. 169 | /// The transaction's sequence number. 170 | /// The scriptSig 171 | public Vin(OutPoint prevOut, Sequence sequence, Consensus.ScriptInfo.Script scriptSig) 172 | { 173 | if (prevOut.Hash == uint256.Zero) 174 | { 175 | this.Coinbase = Encoders.Hex.EncodeData(scriptSig.ToBytes()); 176 | } 177 | else 178 | { 179 | this.TxId = prevOut.Hash.ToString(); 180 | this.VOut = prevOut.N; 181 | this.ScriptSig = new Script(scriptSig); 182 | } 183 | 184 | this.Sequence = (uint)sequence; 185 | } 186 | 187 | /// The scriptsig if this was a coinbase transaction. 188 | [JsonProperty(Order = 0, PropertyName = "coinbase", DefaultValueHandling = DefaultValueHandling.Ignore)] 189 | public string Coinbase { get; set; } 190 | 191 | /// The transaction ID. 192 | [JsonProperty(Order = 1, PropertyName = "txid", DefaultValueHandling = DefaultValueHandling.Ignore)] 193 | public string TxId { get; set; } 194 | 195 | /// The index of the output. 196 | [JsonProperty(Order = 2, PropertyName = "vout", DefaultValueHandling = DefaultValueHandling.Ignore)] 197 | public uint? VOut { get; set; } 198 | 199 | /// The transaction's scriptsig. 200 | [JsonProperty(Order = 3, PropertyName = "scriptSig", DefaultValueHandling = DefaultValueHandling.Ignore)] 201 | public Script ScriptSig { get; set; } 202 | 203 | /// The transaction's sequence number. 204 | [JsonProperty(Order = 4, PropertyName = "sequence")] 205 | public uint Sequence { get; set; } 206 | } 207 | 208 | /// 209 | /// A class describing a transaction output. 210 | /// 211 | public class Vout 212 | { 213 | public Vout() 214 | { 215 | } 216 | 217 | /// 218 | /// Initializes an instance of the class. 219 | /// 220 | /// The index of the output. 221 | /// A 222 | /// The network where the transaction occured. 223 | public Vout(int n, TxOut txout, Network network) 224 | { 225 | this.N = n; 226 | this.Value = txout.Value.ToDecimal(MoneyUnit.BTC); 227 | this.ScriptPubKey = new ScriptPubKey(txout.ScriptPubKey, network); 228 | } 229 | 230 | /// The value of the output. 231 | [JsonConverter(typeof(BtcDecimalJsonConverter))] 232 | [JsonProperty(Order = 0, PropertyName = "value")] 233 | public decimal Value { get; set; } 234 | 235 | /// The index of the output. 236 | [JsonProperty(Order = 1, PropertyName = "n")] 237 | public int N { get; set; } 238 | 239 | /// The output's scriptpubkey. 240 | [JsonProperty(Order = 2, PropertyName = "scriptPubKey")] 241 | public ScriptPubKey ScriptPubKey { get; set; } 242 | } 243 | 244 | /// 245 | /// A class describing a transaction script. 246 | /// 247 | public class Script 248 | { 249 | public Script() 250 | { 251 | } 252 | 253 | /// 254 | /// Initializes a transaction , which contains the assembly and a hexadecimal representation of the script. 255 | /// 256 | /// A . 257 | public Script(Consensus.ScriptInfo.Script script) 258 | { 259 | this.Asm = script.ToString(); 260 | this.Hex = Encoders.Hex.EncodeData(script.ToBytes()); 261 | } 262 | 263 | /// The script's assembly. 264 | [JsonProperty(Order = 0, PropertyName = "asm")] 265 | public string Asm { get; set; } 266 | 267 | /// A hexadecimal representation of the script. 268 | [JsonProperty(Order = 1, PropertyName = "hex")] 269 | public string Hex { get; set; } 270 | } 271 | 272 | /// 273 | /// A class describing a ScriptPubKey. 274 | /// 275 | public class ScriptPubKey : Script 276 | { 277 | public ScriptPubKey() 278 | { 279 | } 280 | 281 | /// 282 | /// Initializes an instance of the class. 283 | /// 284 | /// The script. 285 | /// The network where the transaction was conducted. 286 | public ScriptPubKey(Consensus.ScriptInfo.Script script, Network network) : base(script) 287 | { 288 | var destinations = new List { script.GetDestination(network) }; 289 | this.Type = this.GetScriptType(script.FindTemplate(network)); 290 | 291 | if (destinations[0] == null) 292 | { 293 | destinations = script.GetDestinationPublicKeys(network).Select(p => p.Hash).ToList(); 294 | } 295 | 296 | if (destinations.Count == 1) 297 | { 298 | this.ReqSigs = 1; 299 | this.Addresses = new List { destinations[0].GetAddress(network).ToString() }; 300 | } 301 | else if (destinations.Count > 1) 302 | { 303 | PayToMultiSigTemplateParameters multi = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(script); 304 | this.ReqSigs = multi.SignatureCount; 305 | this.Addresses = multi.PubKeys.Select(m => m.GetAddress(network).ToString()).ToList(); 306 | } 307 | } 308 | 309 | /// The number of required sigs. 310 | [JsonProperty(Order = 2, PropertyName = "reqSigs", DefaultValueHandling = DefaultValueHandling.Ignore)] 311 | public int? ReqSigs { get; set; } 312 | 313 | /// The type of script. 314 | [JsonProperty(Order = 3, PropertyName = "type", DefaultValueHandling = DefaultValueHandling.Ignore)] 315 | public string Type { get; set; } 316 | 317 | /// A list of output addresses. 318 | [JsonProperty(Order = 4, PropertyName = "addresses", DefaultValueHandling = DefaultValueHandling.Ignore)] 319 | public List Addresses { get; set; } 320 | 321 | /// 322 | /// A method that returns a script type description. 323 | /// 324 | /// A used for the script. 325 | /// A string describin the script type. 326 | protected string GetScriptType(ScriptTemplate template) 327 | { 328 | if (template == null) 329 | return "nonstandard"; 330 | switch (template.Type) 331 | { 332 | case TxOutType.TX_PUBKEY: 333 | return "pubkey"; 334 | 335 | case TxOutType.TX_PUBKEYHASH: 336 | return "pubkeyhash"; 337 | 338 | case TxOutType.TX_SCRIPTHASH: 339 | return "scripthash"; 340 | 341 | case TxOutType.TX_MULTISIG: 342 | return "multisig"; 343 | 344 | case TxOutType.TX_NULL_DATA: 345 | return "nulldata"; 346 | } 347 | 348 | return "nonstandard"; 349 | } 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/dapp-wasm/Networks/BitcoinMain.cs: -------------------------------------------------------------------------------- 1 | using Blockcore.Consensus; 2 | using Blockcore.Consensus.ScriptInfo; 3 | using Blockcore.Consensus.TransactionInfo; 4 | using NBitcoin; 5 | using NBitcoin.BitcoinCore; 6 | using NBitcoin.DataEncoders; 7 | using NBitcoin.Protocol; 8 | 9 | namespace Blockcore.Networks.Bitcoin 10 | { 11 | public class BitcoinMain : Network 12 | { 13 | public BitcoinMain() 14 | { 15 | this.Name = "Main"; 16 | this.AdditionalNames = new List { "Mainnet" }; 17 | this.NetworkType = NetworkType.Mainnet; 18 | 19 | // The message start string is designed to be unlikely to occur in normal data. 20 | // The characters are rarely used upper ASCII, not valid as UTF-8, and produce 21 | // a large 4-byte int at any alignment. 22 | this.Magic = 0xD9B4BEF9; 23 | this.DefaultPort = 8333; 24 | this.DefaultMaxOutboundConnections = 8; 25 | this.DefaultMaxInboundConnections = 117; 26 | this.DefaultRPCPort = 8332; 27 | this.DefaultAPIPort = 37220; 28 | this.MinTxFee = 1000; 29 | this.MaxTxFee = Money.Coins(0.1m).Satoshi; 30 | this.FallbackFee = 20000; 31 | this.MinRelayTxFee = 1000; 32 | this.CoinTicker = "BTC"; 33 | this.DefaultBanTimeSeconds = 60 * 60 * 24; // 24 Hours 34 | 35 | var consensusFactory = new ConsensusFactory(); 36 | 37 | 38 | 39 | consensusFactory.Protocol = new ConsensusProtocol() 40 | { 41 | ProtocolVersion = ProtocolVersion.FEEFILTER_VERSION, 42 | MinProtocolVersion = ProtocolVersion.SENDHEADERS_VERSION, 43 | }; 44 | 45 | this.Consensus = new Consensus.Consensus( 46 | consensusFactory: consensusFactory, 47 | consensusOptions: new ConsensusOptions(), // Default - set to Bitcoin params. 48 | coinType: 0, 49 | hashGenesisBlock: null, 50 | subsidyHalvingInterval: 210000, 51 | majorityEnforceBlockUpgrade: 750, 52 | majorityRejectBlockOutdated: 950, 53 | majorityWindow: 1000, 54 | buriedDeployments: null, 55 | bip9Deployments: null, 56 | bip34Hash: null, 57 | minerConfirmationWindow: 2016, // nPowTargetTimespan / nPowTargetSpacing 58 | maxReorgLength: 0, 59 | defaultAssumeValid: null, // 629000 60 | maxMoney: 21000000 * Money.COIN, 61 | coinbaseMaturity: 100, 62 | premineHeight: 0, 63 | premineReward: Money.Zero, 64 | proofOfWorkReward: Money.Coins(50), 65 | targetTimespan: TimeSpan.FromSeconds(14 * 24 * 60 * 60), // two weeks 66 | targetSpacing: TimeSpan.FromSeconds(10 * 60), 67 | powAllowMinDifficultyBlocks: false, 68 | posNoRetargeting: false, 69 | powNoRetargeting: false, 70 | powLimit: null, 71 | minimumChainWork: null, 72 | isProofOfStake: false, 73 | lastPowBlock: default(int), 74 | proofOfStakeLimit: null, 75 | proofOfStakeLimitV2: null, 76 | proofOfStakeReward: Money.Zero, 77 | proofOfStakeTimestampMask: 0 78 | ); 79 | 80 | this.Base58Prefixes = new byte[12][]; 81 | this.Base58Prefixes[(int)Base58Type.PUBKEY_ADDRESS] = new byte[] { (0) }; 82 | this.Base58Prefixes[(int)Base58Type.SCRIPT_ADDRESS] = new byte[] { (5) }; 83 | this.Base58Prefixes[(int)Base58Type.SECRET_KEY] = new byte[] { (128) }; 84 | this.Base58Prefixes[(int)Base58Type.ENCRYPTED_SECRET_KEY_NO_EC] = new byte[] { 0x01, 0x42 }; 85 | this.Base58Prefixes[(int)Base58Type.ENCRYPTED_SECRET_KEY_EC] = new byte[] { 0x01, 0x43 }; 86 | this.Base58Prefixes[(int)Base58Type.EXT_PUBLIC_KEY] = new byte[] { (0x04), (0x88), (0xB2), (0x1E) }; 87 | this.Base58Prefixes[(int)Base58Type.EXT_SECRET_KEY] = new byte[] { (0x04), (0x88), (0xAD), (0xE4) }; 88 | this.Base58Prefixes[(int)Base58Type.PASSPHRASE_CODE] = new byte[] { 0x2C, 0xE9, 0xB3, 0xE1, 0xFF, 0x39, 0xE2 }; 89 | this.Base58Prefixes[(int)Base58Type.CONFIRMATION_CODE] = new byte[] { 0x64, 0x3B, 0xF6, 0xA8, 0x9A }; 90 | this.Base58Prefixes[(int)Base58Type.ASSET_ID] = new byte[] { 23 }; 91 | 92 | var encoder = new Bech32Encoder("bc"); 93 | this.Bech32Encoders = new Bech32Encoder[2]; 94 | this.Bech32Encoders[(int)Bech32Type.WITNESS_PUBKEY_ADDRESS] = encoder; 95 | this.Bech32Encoders[(int)Bech32Type.WITNESS_SCRIPT_ADDRESS] = encoder; 96 | 97 | this.StandardScriptsRegistry = new BitcoinStandardScriptsRegistry(); 98 | 99 | } 100 | } 101 | 102 | public class BitcoinStandardScriptsRegistry : StandardScriptsRegistry 103 | { 104 | // See MAX_OP_RETURN_RELAY in Bitcoin Core, 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/blazor/dapp-wasm/dapp-wasm/wwwroot/sample-data/weather.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "date": "2022-01-06", 4 | "temperatureC": 1, 5 | "summary": "Freezing" 6 | }, 7 | { 8 | "date": "2022-01-07", 9 | "temperatureC": 14, 10 | "summary": "Bracing" 11 | }, 12 | { 13 | "date": "2022-01-08", 14 | "temperatureC": -13, 15 | "summary": "Freezing" 16 | }, 17 | { 18 | "date": "2022-01-09", 19 | "temperatureC": -16, 20 | "summary": "Balmy" 21 | }, 22 | { 23 | "date": "2022-01-10", 24 | "temperatureC": -2, 25 | "summary": "Chilly" 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/super-devninja/dapp-sample/c56c620048fafbe15117540e248ecd9de3d509ac/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Blockcore DApp Sample 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes recent versions of Safari, Chrome (including 12 | * Opera), Edge on the desktop, and iOS and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | /*************************************************************************************************** 46 | * Zone JS is required by default for Angular itself. 47 | */ 48 | import 'zone.js'; // Included with Angular CLI. 49 | 50 | 51 | /*************************************************************************************************** 52 | * APPLICATION IMPORTS 53 | */ 54 | 55 | 56 | // Needed for BIP39 and likely more. 57 | (window as any)['global'] = window; 58 | 59 | import * as buffer from 'buffer'; 60 | (window as any).Buffer = buffer.Buffer; 61 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | html, body { height: 100%; } 4 | body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } 5 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | html, 4 | body { 5 | height: 100%; 6 | } 7 | body { 8 | margin: 0; 9 | background-color: #303030; 10 | font-family: Roboto, "Helvetica Neue", sans-serif; 11 | } 12 | 13 | .page { 14 | max-width: 1200px; 15 | margin-left: auto; 16 | margin-right: auto; 17 | padding-left: 1em; 18 | padding-right: 1em; 19 | } 20 | 21 | a { 22 | color: white; 23 | } 24 | 25 | a:hover { 26 | color: silver; 27 | } -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | (id: string): T; 13 | keys(): string[]; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting(), 21 | ); 22 | 23 | // Then we find all the tests. 24 | const context = require.context('./', true, /\.spec\.ts$/); 25 | // And load the modules. 26 | context.keys().forEach(context); 27 | -------------------------------------------------------------------------------- /src/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | resolve: { 3 | fallback: { 4 | // buffer: require.resolve("buffer/"), 5 | stream: require.resolve("stream-browserify"), 6 | // crypto: require.resolve("crypto-browserify"), 7 | }, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "es2020", 20 | "module": "es2020", 21 | "lib": [ 22 | "es2020", 23 | "dom" 24 | ] 25 | }, 26 | "angularCompilerOptions": { 27 | "enableI18nLegacyMessageIdFormat": false, 28 | "strictInjectionParameters": true, 29 | "strictInputAccessModifiers": true, 30 | "strictTemplates": true 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | --------------------------------------------------------------------------------