├── api
├── public
│ ├── favicon.ico
│ ├── robots.txt
│ ├── .htaccess
│ └── index.php
├── database
│ ├── .gitignore
│ ├── seeders
│ │ └── DatabaseSeeder.php
│ ├── migrations
│ │ ├── 2023_10_10_024458_create_wallets_table.php
│ │ └── 2023_10_10_024453_create_transactions_table.php
│ └── factories
│ │ └── UserFactory.php
├── bootstrap
│ ├── cache
│ │ └── .gitignore
│ └── app.php
├── storage
│ ├── logs
│ │ └── .gitignore
│ ├── app
│ │ ├── public
│ │ │ └── .gitignore
│ │ └── .gitignore
│ └── framework
│ │ ├── sessions
│ │ └── .gitignore
│ │ ├── testing
│ │ └── .gitignore
│ │ ├── views
│ │ └── .gitignore
│ │ ├── cache
│ │ ├── data
│ │ │ └── .gitignore
│ │ └── .gitignore
│ │ └── .gitignore
├── config
│ ├── regex.php
│ ├── cors.php
│ ├── services.php
│ ├── view.php
│ ├── hashing.php
│ ├── broadcasting.php
│ ├── filesystems.php
│ ├── cache.php
│ ├── queue.php
│ ├── mail.php
│ ├── auth.php
│ ├── logging.php
│ ├── database.php
│ └── app.php
├── tests
│ ├── TestCase.php
│ ├── Unit
│ │ └── ExampleTest.php
│ ├── Feature
│ │ └── ExampleTest.php
│ └── CreatesApplication.php
├── .gitattributes
├── app
│ ├── Models
│ │ ├── Wallet.php
│ │ └── Transaction.php
│ ├── Http
│ │ ├── Controllers
│ │ │ ├── Controller.php
│ │ │ └── API.php
│ │ ├── Middleware
│ │ │ ├── EncryptCookies.php
│ │ │ ├── VerifyCsrfToken.php
│ │ │ ├── PreventRequestsDuringMaintenance.php
│ │ │ ├── TrimStrings.php
│ │ │ ├── TrustHosts.php
│ │ │ ├── Authenticate.php
│ │ │ ├── ValidateSignature.php
│ │ │ ├── TrustProxies.php
│ │ │ └── RedirectIfAuthenticated.php
│ │ └── Kernel.php
│ ├── Providers
│ │ ├── BroadcastServiceProvider.php
│ │ ├── AppServiceProvider.php
│ │ ├── AuthServiceProvider.php
│ │ ├── EventServiceProvider.php
│ │ └── RouteServiceProvider.php
│ ├── Console
│ │ └── Kernel.php
│ └── Exceptions
│ │ └── Handler.php
├── package.json
├── vite.config.js
├── routes
│ ├── web.php
│ ├── channels.php
│ ├── console.php
│ └── api.php
├── .gitignore
├── .editorconfig
├── .env.example
├── phpunit.xml
├── artisan
└── composer.json
├── webApp
├── src
│ ├── scss
│ │ ├── _responsive.scss
│ │ ├── app.scss
│ │ ├── _variables.scss
│ │ ├── _fonts.scss
│ │ └── _toastify.scss
│ ├── assets
│ │ ├── fonts
│ │ │ ├── IconFont
│ │ │ │ ├── icomoon.eot
│ │ │ │ ├── icomoon.ttf
│ │ │ │ └── icomoon.woff
│ │ │ └── IRANYekanX
│ │ │ │ ├── woff
│ │ │ │ ├── IRANYekanXVF.woff
│ │ │ │ ├── IRANYekanX-Black.woff
│ │ │ │ ├── IRANYekanX-Bold.woff
│ │ │ │ ├── IRANYekanX-Light.woff
│ │ │ │ ├── IRANYekanX-Regular.woff
│ │ │ │ └── IRANYekanX-ExtraBlack.woff
│ │ │ │ └── woff2
│ │ │ │ ├── IRANYekanXVF.woff2
│ │ │ │ ├── IRANYekanX-Black.woff2
│ │ │ │ ├── IRANYekanX-Bold.woff2
│ │ │ │ ├── IRANYekanX-Light.woff2
│ │ │ │ ├── IRANYekanX-Regular.woff2
│ │ │ │ └── IRANYekanX-ExtraBlack.woff2
│ │ └── images
│ │ │ └── credit.svg
│ ├── stores
│ │ └── useRanks.js
│ ├── main.js
│ ├── components
│ │ ├── Hint.vue
│ │ ├── Header.vue
│ │ └── badge.vue
│ ├── router
│ │ └── index.js
│ ├── views
│ │ ├── Settings.vue
│ │ ├── Transactions.vue
│ │ ├── Login.vue
│ │ ├── Transaction.vue
│ │ ├── Badges.vue
│ │ ├── Transfer.vue
│ │ └── Receive.vue
│ ├── App.vue
│ ├── i18n
│ │ ├── lang-ar.js
│ │ ├── lang-en.js
│ │ ├── lang-fa.js
│ │ ├── lang-tr.js
│ │ ├── lang-de.js
│ │ └── lang-fr.js
│ └── utils
│ │ └── index.js
├── public
│ └── assets
│ │ └── sounds
│ │ ├── Failed.mp3
│ │ └── Success.mp3
├── vite.config.js
├── .gitignore
├── index.html
└── package.json
├── docs
├── DPXWallet.gif
├── DPXWallet.mp4
├── DPXWallet.png
├── package.json
├── introduction.md
├── .gitignore
├── index.md
├── getting-started.md
├── .vitepress
│ └── config.mjs
├── setting-up-backend.md
├── setting-up-frontend.md
├── environment-variables.md
├── technologies-used.md
└── dpx-api.md
├── LICENSE
├── README.md
└── .github
└── workflows
└── deploy.yml
/api/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/webApp/src/scss/_responsive.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/api/database/.gitignore:
--------------------------------------------------------------------------------
1 | *.sqlite*
2 |
--------------------------------------------------------------------------------
/api/bootstrap/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/api/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/api/storage/logs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/api/storage/app/public/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/api/storage/app/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !public/
3 | !.gitignore
4 |
--------------------------------------------------------------------------------
/api/storage/framework/sessions/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/api/storage/framework/testing/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/api/storage/framework/views/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/api/storage/framework/cache/data/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/api/storage/framework/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !data/
3 | !.gitignore
4 |
--------------------------------------------------------------------------------
/docs/DPXWallet.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/docs/DPXWallet.gif
--------------------------------------------------------------------------------
/docs/DPXWallet.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/docs/DPXWallet.mp4
--------------------------------------------------------------------------------
/docs/DPXWallet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/docs/DPXWallet.png
--------------------------------------------------------------------------------
/api/config/regex.php:
--------------------------------------------------------------------------------
1 | "^[a-fA-Z0-9]{32}$",
5 | 'amount' => "^((\d+)\.?(\d)?)$",
6 | ];
--------------------------------------------------------------------------------
/webApp/public/assets/sounds/Failed.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/public/assets/sounds/Failed.mp3
--------------------------------------------------------------------------------
/webApp/public/assets/sounds/Success.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/public/assets/sounds/Success.mp3
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IconFont/icomoon.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IconFont/icomoon.eot
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IconFont/icomoon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IconFont/icomoon.ttf
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IconFont/icomoon.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IconFont/icomoon.woff
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IRANYekanX/woff/IRANYekanXVF.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IRANYekanX/woff/IRANYekanXVF.woff
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IRANYekanX/woff2/IRANYekanXVF.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IRANYekanX/woff2/IRANYekanXVF.woff2
--------------------------------------------------------------------------------
/webApp/src/scss/app.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | @import "_variables";
4 | @import "_fonts";
5 | @import "toastify";
6 | @import "_general";
7 | @import "_responsive";
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IRANYekanX/woff/IRANYekanX-Black.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IRANYekanX/woff/IRANYekanX-Black.woff
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IRANYekanX/woff/IRANYekanX-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IRANYekanX/woff/IRANYekanX-Bold.woff
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IRANYekanX/woff/IRANYekanX-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IRANYekanX/woff/IRANYekanX-Light.woff
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IRANYekanX/woff/IRANYekanX-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IRANYekanX/woff/IRANYekanX-Regular.woff
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IRANYekanX/woff2/IRANYekanX-Black.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IRANYekanX/woff2/IRANYekanX-Black.woff2
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IRANYekanX/woff2/IRANYekanX-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IRANYekanX/woff2/IRANYekanX-Bold.woff2
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IRANYekanX/woff2/IRANYekanX-Light.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IRANYekanX/woff2/IRANYekanX-Light.woff2
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IRANYekanX/woff/IRANYekanX-ExtraBlack.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IRANYekanX/woff/IRANYekanX-ExtraBlack.woff
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IRANYekanX/woff2/IRANYekanX-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IRANYekanX/woff2/IRANYekanX-Regular.woff2
--------------------------------------------------------------------------------
/webApp/src/assets/fonts/IRANYekanX/woff2/IRANYekanX-ExtraBlack.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erfanmola/DPXWallet/HEAD/webApp/src/assets/fonts/IRANYekanX/woff2/IRANYekanX-ExtraBlack.woff2
--------------------------------------------------------------------------------
/api/storage/framework/.gitignore:
--------------------------------------------------------------------------------
1 | compiled.php
2 | config.php
3 | down
4 | events.scanned.php
5 | maintenance.php
6 | routes.php
7 | routes.scanned.php
8 | schedule-*
9 | services.json
10 |
--------------------------------------------------------------------------------
/api/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | json([
8 | 'status' => 'error',
9 | 'error' => 'not-allowed',
10 | 'info' => 'Method is not allowed'
11 | ], 405);
12 |
13 | })->where([ 'any' => '.*' ]);
--------------------------------------------------------------------------------
/api/.gitignore:
--------------------------------------------------------------------------------
1 | /.phpunit.cache
2 | /node_modules
3 | /public/build
4 | /public/hot
5 | /public/storage
6 | /storage/*.key
7 | /vendor
8 | .env
9 | .env.backup
10 | .env.production
11 | .phpunit.result.cache
12 | Homestead.json
13 | Homestead.yaml
14 | auth.json
15 | npm-debug.log
16 | yarn-error.log
17 | /.fleet
18 | /.idea
19 | /.vscode
20 |
--------------------------------------------------------------------------------
/api/tests/Unit/ExampleTest.php:
--------------------------------------------------------------------------------
1 | assertTrue(true);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/api/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 4
7 | indent_style = space
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
14 | [*.{yml,yaml}]
15 | indent_size = 2
16 |
17 | [docker-compose.yml]
18 | indent_size = 4
19 |
--------------------------------------------------------------------------------
/api/app/Models/Transaction.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | protected $except = [
15 | //
16 | ];
17 | }
18 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 | .env
26 | .vitepress/cache
27 | .vitepress/dist
--------------------------------------------------------------------------------
/api/app/Http/Middleware/VerifyCsrfToken.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | protected $except = [
15 | //
16 | ];
17 | }
18 |
--------------------------------------------------------------------------------
/api/tests/Feature/ExampleTest.php:
--------------------------------------------------------------------------------
1 | get('/');
16 |
17 | $response->assertStatus(200);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/api/app/Providers/BroadcastServiceProvider.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | protected $except = [
15 | //
16 | ];
17 | }
18 |
--------------------------------------------------------------------------------
/api/tests/CreatesApplication.php:
--------------------------------------------------------------------------------
1 | make(Kernel::class)->bootstrap();
18 |
19 | return $app;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/webApp/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | DPXWallet
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/api/app/Http/Middleware/TrimStrings.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | protected $except = [
15 | 'current_password',
16 | 'password',
17 | 'password_confirmation',
18 | ];
19 | }
20 |
--------------------------------------------------------------------------------
/api/app/Http/Middleware/TrustHosts.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | public function hosts(): array
15 | {
16 | return [
17 | $this->allSubdomainsOfApplicationUrl(),
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/api/app/Providers/AppServiceProvider.php:
--------------------------------------------------------------------------------
1 | expectsJson() ? null : route('login');
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/webApp/src/scss/_variables.scss:
--------------------------------------------------------------------------------
1 | :root {
2 | color-scheme: light dark;
3 | --shimmer-static-bg: #DDDBDD;
4 | --stroke-color: #000000;
5 | --success-green: #4CAF50;
6 | --failed-red: #F44336;
7 | --button-danger: #F44336;
8 | --border-red: rgba(244, 67, 54, 0.5);
9 | --border-green: rgba(76, 175, 80, 0.5);
10 | }
11 |
12 | .tele-vue-colorScheme-dark {
13 | --shimmer-static-bg: #253030;
14 | --stroke-color: white;
15 | --success-green: #4CAF50;
16 | --failed-red: #F44336;
17 | --button-danger: #F44336;
18 | }
--------------------------------------------------------------------------------
/webApp/src/stores/useRanks.js:
--------------------------------------------------------------------------------
1 | import { defineStore } from "pinia";
2 | import { useI18n } from "vue-i18n";
3 |
4 | export const useRankStore = defineStore("ranks", {
5 |
6 | state: () => ({
7 | data: [
8 | { rank: 1, min: 0 },
9 | { rank: 2, min: 100 },
10 | { rank: 3, min: 500 },
11 | { rank: 4, min: 1000 },
12 | { rank: 5, min: 5000 },
13 | { rank: 6, min: 10000 },
14 | { rank: 7, min: 25000 },
15 | { rank: 8, min: 50000 },
16 | ]
17 | }),
18 |
19 | });
--------------------------------------------------------------------------------
/api/app/Http/Middleware/ValidateSignature.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | protected $except = [
15 | // 'fbclid',
16 | // 'utm_campaign',
17 | // 'utm_content',
18 | // 'utm_medium',
19 | // 'utm_source',
20 | // 'utm_term',
21 | ];
22 | }
23 |
--------------------------------------------------------------------------------
/api/database/seeders/DatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | create();
16 |
17 | // \App\Models\User::factory()->create([
18 | // 'name' => 'Test User',
19 | // 'email' => 'test@example.com',
20 | // ]);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/api/.env.example:
--------------------------------------------------------------------------------
1 | APP_NAME=Laravel
2 | APP_ENV=local
3 | APP_KEY=
4 | APP_DEBUG=true
5 | APP_URL=http://localhost
6 |
7 | LOG_CHANNEL=stack
8 | LOG_DEPRECATIONS_CHANNEL=null
9 | LOG_LEVEL=debug
10 |
11 | DB_CONNECTION=mysql
12 | DB_HOST=127.0.0.1
13 | DB_PORT=3306
14 | DB_DATABASE=laravel
15 | DB_USERNAME=root
16 | DB_PASSWORD=
17 |
18 | BROADCAST_DRIVER=log
19 | CACHE_DRIVER=file
20 | FILESYSTEM_DISK=local
21 | QUEUE_CONNECTION=sync
22 | SESSION_DRIVER=file
23 | SESSION_LIFETIME=120
24 |
25 | FEE=0.2
26 | FEE_WALLET=
27 | TRANSACTIONS_PER_FETCH=250
28 | VITE_HEX_HMAC_SIGNATURE=
29 | VITE_APP_URL="${APP_URL}"
30 | VITE_FEE="${FEE}"
--------------------------------------------------------------------------------
/api/routes/channels.php:
--------------------------------------------------------------------------------
1 | id === (int) $id;
18 | });
19 |
--------------------------------------------------------------------------------
/api/app/Providers/AuthServiceProvider.php:
--------------------------------------------------------------------------------
1 |
14 | */
15 | protected $policies = [
16 | //
17 | ];
18 |
19 | /**
20 | * Register any authentication / authorization services.
21 | */
22 | public function boot(): void
23 | {
24 | //
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/api/routes/console.php:
--------------------------------------------------------------------------------
1 | comment(Inspiring::quote());
19 | })->purpose('Display an inspiring quote');
20 |
--------------------------------------------------------------------------------
/api/public/.htaccess:
--------------------------------------------------------------------------------
1 |
2 |
3 | Options -MultiViews -Indexes
4 |
5 |
6 | RewriteEngine On
7 |
8 | # Handle Authorization Header
9 | RewriteCond %{HTTP:Authorization} .
10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
11 |
12 | # Redirect Trailing Slashes If Not A Folder...
13 | RewriteCond %{REQUEST_FILENAME} !-d
14 | RewriteCond %{REQUEST_URI} (.+)/$
15 | RewriteRule ^ %1 [L,R=301]
16 |
17 | # Send Requests To Front Controller...
18 | RewriteCond %{REQUEST_FILENAME} !-d
19 | RewriteCond %{REQUEST_FILENAME} !-f
20 | RewriteRule ^ index.php [L]
21 |
22 |
--------------------------------------------------------------------------------
/api/app/Console/Kernel.php:
--------------------------------------------------------------------------------
1 | command('inspire')->hourly();
16 | }
17 |
18 | /**
19 | * Register the commands for the application.
20 | */
21 | protected function commands(): void
22 | {
23 | $this->load(__DIR__.'/Commands');
24 |
25 | require base_path('routes/console.php');
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/webApp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webapp",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite --host",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "@erfanmola/televue": "^0.1.8",
13 | "@twa-dev/sdk": "^7.10.1",
14 | "pinia": "^2.2.6",
15 | "qr-code-styling": "^1.8.4",
16 | "toastify-js": "^1.12.0",
17 | "vue": "^3.5.13",
18 | "vue-i18n": "^10.0.4",
19 | "vue-router": "^4.4.5"
20 | },
21 | "devDependencies": {
22 | "@vitejs/plugin-vue": "^5.2.0",
23 | "sass": "^1.81.0",
24 | "vite": "^5.4.11",
25 | "vite-svg-loader": "^5.1.0"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/api/app/Exceptions/Handler.php:
--------------------------------------------------------------------------------
1 |
14 | */
15 | protected $dontFlash = [
16 | 'current_password',
17 | 'password',
18 | 'password_confirmation',
19 | ];
20 |
21 | /**
22 | * Register the exception handling callbacks for the application.
23 | */
24 | public function register(): void
25 | {
26 | $this->reportable(function (Throwable $e) {
27 | //
28 | });
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/api/app/Http/Middleware/TrustProxies.php:
--------------------------------------------------------------------------------
1 | |string|null
14 | */
15 | protected $proxies;
16 |
17 | /**
18 | * The headers that should be used to detect proxies.
19 | *
20 | * @var int
21 | */
22 | protected $headers =
23 | Request::HEADER_X_FORWARDED_FOR |
24 | Request::HEADER_X_FORWARDED_HOST |
25 | Request::HEADER_X_FORWARDED_PORT |
26 | Request::HEADER_X_FORWARDED_PROTO |
27 | Request::HEADER_X_FORWARDED_AWS_ELB;
28 | }
29 |
--------------------------------------------------------------------------------
/api/routes/api.php:
--------------------------------------------------------------------------------
1 | where([ 'wallet' => config('regex.md5') ]);
7 | Route::get('/transaction/{id}', [ API::class, 'Transaction' ])->where([ 'id' => config('regex.md5') ]);
8 | Route::any('/transactions', [ API::class, 'Transactions' ]);
9 | Route::post('/transfer', [ API::class, 'Transfer' ]);
10 | Route::post('/verify', [ API::class, 'Verify' ])->middleware('throttle:6,1');
11 | Route::post('/revoke', [ API::class, 'Revoke' ])->middleware('throttle:6,1');
12 | Route::post('/generate', [ API::class, 'Generate' ])->middleware('throttle:6,1');
13 | Route::get('/{any}', [ API::class, 'Invalid' ])->where([ 'any' => '.*' ]);
--------------------------------------------------------------------------------
/api/database/migrations/2023_10_10_024458_create_wallets_table.php:
--------------------------------------------------------------------------------
1 | id();
13 | $table->string('wallet', 32);
14 | $table->string('secret', 64)->nullable();
15 | $table->float('balance')->default(0);
16 | $table->float('bonus')->default(0);
17 | $table->integer('locked')->default(0);
18 | $table->timestamps();
19 | });
20 | }
21 |
22 | public function down()
23 | {
24 | Schema::dropIfExists('wallets');
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/api/database/migrations/2023_10_10_024453_create_transactions_table.php:
--------------------------------------------------------------------------------
1 | id();
13 | $table->string('transaction', 32);
14 | $table->string('departure', 32);
15 | $table->string('destination', 32);
16 | $table->float('amount');
17 | $table->float('fee');
18 | $table->integer('timestamp');
19 | $table->timestamps();
20 | });
21 | }
22 |
23 | public function down()
24 | {
25 | Schema::dropIfExists('transactions');
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/api/app/Http/Middleware/RedirectIfAuthenticated.php:
--------------------------------------------------------------------------------
1 | check()) {
24 | return redirect(RouteServiceProvider::HOME);
25 | }
26 | }
27 |
28 | return $next($request);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/webApp/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue';
2 | import { createI18n } from 'vue-i18n';
3 | import { createPinia } from 'pinia';
4 |
5 | import App from './App.vue';
6 | import router from './router';
7 |
8 | import './scss/app.scss';
9 |
10 | // Import i18n locales
11 | import i18n_en from './i18n/lang-en';
12 | import i18n_fa from './i18n/lang-fa';
13 | import i18n_ar from './i18n/lang-ar';
14 | import i18n_de from './i18n/lang-de';
15 | import i18n_fr from './i18n/lang-fr';
16 | import i18n_tr from './i18n/lang-tr';
17 |
18 | const i18n = createI18n({
19 | legacy: false,
20 | locale: 'en',
21 | fallbackLocale: 'en',
22 | messages: {
23 | en: i18n_en,
24 | fa: i18n_fa,
25 | ar: i18n_ar,
26 | de: i18n_de,
27 | fr: i18n_fr,
28 | tr: i18n_tr,
29 | },
30 | });
31 |
32 | const app = createApp(App);
33 |
34 | app.use(i18n);
35 | app.use(router);
36 | app.use(createPinia());
37 |
38 | app.mount('#app');
--------------------------------------------------------------------------------
/api/config/cors.php:
--------------------------------------------------------------------------------
1 | ['api/*', 'sanctum/csrf-cookie'],
19 |
20 | 'allowed_methods' => ['*'],
21 |
22 | 'allowed_origins' => ['*'],
23 |
24 | 'allowed_origins_patterns' => [],
25 |
26 | 'allowed_headers' => ['*'],
27 |
28 | 'exposed_headers' => [],
29 |
30 | 'max_age' => 0,
31 |
32 | 'supports_credentials' => false,
33 |
34 | ];
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2023 hi@erfanxd.ir
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/api/app/Providers/EventServiceProvider.php:
--------------------------------------------------------------------------------
1 | >
16 | */
17 | protected $listen = [
18 | Registered::class => [
19 | SendEmailVerificationNotification::class,
20 | ],
21 | ];
22 |
23 | /**
24 | * Register any events for your application.
25 | */
26 | public function boot(): void
27 | {
28 | //
29 | }
30 |
31 | /**
32 | * Determine if events and listeners should be automatically discovered.
33 | */
34 | public function shouldDiscoverEvents(): bool
35 | {
36 | return false;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/api/config/services.php:
--------------------------------------------------------------------------------
1 | [
18 | 'domain' => env('MAILGUN_DOMAIN'),
19 | 'secret' => env('MAILGUN_SECRET'),
20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
21 | 'scheme' => 'https',
22 | ],
23 |
24 | 'postmark' => [
25 | 'token' => env('POSTMARK_TOKEN'),
26 | ],
27 |
28 | 'ses' => [
29 | 'key' => env('AWS_ACCESS_KEY_ID'),
30 | 'secret' => env('AWS_SECRET_ACCESS_KEY'),
31 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
32 | ],
33 |
34 | ];
35 |
--------------------------------------------------------------------------------
/api/database/factories/UserFactory.php:
--------------------------------------------------------------------------------
1 |
10 | */
11 | class UserFactory extends Factory
12 | {
13 | /**
14 | * Define the model's default state.
15 | *
16 | * @return array
17 | */
18 | public function definition(): array
19 | {
20 | return [
21 | 'name' => fake()->name(),
22 | 'email' => fake()->unique()->safeEmail(),
23 | 'email_verified_at' => now(),
24 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
25 | 'remember_token' => Str::random(10),
26 | ];
27 | }
28 |
29 | /**
30 | * Indicate that the model's email address should be unverified.
31 | */
32 | public function unverified(): static
33 | {
34 | return $this->state(fn (array $attributes) => [
35 | 'email_verified_at' => null,
36 | ]);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/api/config/view.php:
--------------------------------------------------------------------------------
1 | [
17 | resource_path('views'),
18 | ],
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Compiled View Path
23 | |--------------------------------------------------------------------------
24 | |
25 | | This option determines where all the compiled Blade templates will be
26 | | stored for your application. Typically, this is within the storage
27 | | directory. However, as usual, you are free to change this value.
28 | |
29 | */
30 |
31 | 'compiled' => env(
32 | 'VIEW_COMPILED_PATH',
33 | realpath(storage_path('framework/views'))
34 | ),
35 |
36 | ];
37 |
--------------------------------------------------------------------------------
/api/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | tests/Unit
10 |
11 |
12 | tests/Feature
13 |
14 |
15 |
16 |
17 | app
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | # https://vitepress.dev/reference/default-theme-home-page
3 | layout: home
4 |
5 | hero:
6 | name: "DPXWallet"
7 | text: "Documentations & Setup Guide"
8 | tagline: Feature-Rich demonstration of a dummy Wallet app built in Telegram
9 | image:
10 | src: https://raw.githubusercontent.com/erfanmola/DPXWallet/master/docs/DPXWallet.png
11 | alt: DPXWallet
12 | actions:
13 | - theme: brand
14 | text: View WebApp
15 | link: https://t.me/DPXWalletBot
16 | - theme: alt
17 | text: Getting Started
18 | link: /getting-started
19 | - theme: alt
20 | text: TeleVue
21 | link: https://github.com/erfanmola/TeleVue
22 |
23 | features:
24 | - title: Create / Import wallet
25 | icon: 💳
26 | details: You can create a new wallet or import your existing ones
27 | - title: Send & Receive Coins
28 | icon: 💰
29 | details: You can send coins to other wallets, or receive coins in your wallet
30 | - title: Transactions History
31 | icon: 🌐
32 | details: You can access the history of all of your transactions
33 | - title: Profile & Leagues
34 | icon: 🏆
35 | details: You can view your balance and get placed in a league based on your balance
36 | ---
37 |
38 |
--------------------------------------------------------------------------------
/webApp/src/components/Hint.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/api/app/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | by($request->user()?->id ?: $request->ip());
29 | });
30 |
31 | $this->routes(function () {
32 | Route::middleware('api')
33 | ->prefix('api')
34 | ->group(base_path('routes/api.php'));
35 |
36 | Route::middleware('web')
37 | ->group(base_path('routes/web.php'));
38 | });
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/docs/getting-started.md:
--------------------------------------------------------------------------------
1 | # Getting Started
2 |
3 | DPXWallet is built upon the principles of [Telegram Mini Apps Contest](https://t.me/contest/327). It's open-source, well-documented and explained step by step.
4 |
5 | ## Cloning the project
6 |
7 | At the very first step, we need to clone the DPXWallet's Github repository in order to get started.
8 |
9 | ```bash
10 | git clone https://github.com/erfanmola/DPXWallet.git
11 | ```
12 |
13 | ## Technologies Used
14 |
15 | At this step, We recommend you to read our brief explanation about [Technologies Used](/technologies-used) section in order to get a better understanding of what we are dealing with.
16 |
17 | ## Preparation
18 |
19 | Before diving into the setup process, We need to setup [Environment Variables](/environment-variables).
20 |
21 | ## Setting Up the FrontEnd
22 | You can read our brief explanation about [Setting Up the FrontEnd](/setting-up-frontend) for installing, building and deploying the WebApp.
23 |
24 | ## Setting Up the BackEnd
25 | You can read our brief explanation about [Setting Up the BackEnd](/setting-up-backend) for installing and deploying the Backend API of the WebApp.
26 |
27 | ## TeleVue
28 |
29 | [TeleVue](https://github.com/erfanmola/TeleVue) is a Telegram UI Library for VueJS developed mainly for the purpose of this contest and it has been used in DPXWallet.
30 |
31 | ## License
32 | [MIT](https://github.com/erfanmola/DPXWallet/blob/master/LICENSE)
--------------------------------------------------------------------------------
/webApp/src/scss/_fonts.scss:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "DPXWalletIRANYekanX";
3 | src: url('../assets/fonts/IRANYekanX/woff2/IRANYekanXVF.woff2') format('woff2');
4 | font-weight: normal;
5 | font-display: swap;
6 | }
7 |
8 | @for $i from 1 through 19 {
9 |
10 | @for $j from 1 to 6 {
11 |
12 | .w#{$i * 50}-dots-#{$j} {
13 | font-weight: #{$i * 50};
14 | font-variation-settings: "wght" #{$i * 50}, "dots" #{$j};
15 | }
16 |
17 | }
18 |
19 | }
20 |
21 | @font-face {
22 | font-family: 'DPXWalletIconFonts';
23 | src: url('../assets/fonts/IconFont/icomoon.eot?6ioq8g');
24 | src: url('../assets/fonts/IconFont/icomoon.eot?6ioq8g#iefix') format('embedded-opentype'),
25 | url('../assets/fonts/IconFont/icomoon.ttf?6ioq8g') format('truetype'),
26 | url('../assets/fonts/IconFont/icomoon.woff?6ioq8g') format('woff'),
27 | url('../assets/fonts/IconFont/icomoon.svg?6ioq8g#icomoon') format('svg');
28 | font-weight: normal;
29 | font-style: normal;
30 | font-display: block;
31 | }
32 |
33 | [class^="icon-"], [class*=" icon-"] {
34 | font-family: 'DPXWalletIconFonts' !important;
35 | speak: never;
36 | font-style: normal;
37 | font-weight: normal;
38 | font-variant: normal;
39 | text-transform: none;
40 | line-height: 1;
41 | -webkit-font-smoothing: antialiased;
42 | -moz-osx-font-smoothing: grayscale;
43 | }
44 |
45 | @import "icomoon";
--------------------------------------------------------------------------------
/webApp/src/components/Header.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 | {{ props.title }}
11 |
12 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/webApp/src/scss/_toastify.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Toastify js 1.11.2
3 | * https://github.com/apvarun/toastify-js
4 | * @license MIT licensed
5 | *
6 | * Copyright (C) 2018 Varun A P
7 | */
8 |
9 | .toastify {
10 | padding: 12px 20px;
11 | color: #ffffff;
12 | display: inline-block;
13 | box-shadow: 0 3px 6px -1px rgba(0, 0, 0, 0.12), 0 10px 36px -4px rgba(77, 96, 232, 0.3);
14 | background: -webkit-linear-gradient(315deg, #73a5ff, #5477f5);
15 | background: linear-gradient(135deg, #73a5ff, #5477f5);
16 | position: fixed;
17 | opacity: 0;
18 | transition: all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1);
19 | border-radius: 2px;
20 | cursor: pointer;
21 | text-decoration: none;
22 | max-width: calc(50% - 20px);
23 | z-index: 2147483647;
24 | }
25 |
26 | .toastify.on {
27 | opacity: 1;
28 | }
29 |
30 | .toast-close {
31 | opacity: 0.4;
32 | padding: 0 5px;
33 | }
34 |
35 | .toastify-right {
36 | right: 15px;
37 | }
38 |
39 | .toastify-left {
40 | left: 15px;
41 | }
42 |
43 | .toastify-top {
44 | top: -150px;
45 | }
46 |
47 | .toastify-bottom {
48 | bottom: -150px;
49 | }
50 |
51 | .toastify-rounded {
52 | border-radius: 25px;
53 | }
54 |
55 | .toastify-avatar {
56 | width: 1.5em;
57 | height: 1.5em;
58 | margin: -7px 5px;
59 | border-radius: 2px;
60 | }
61 |
62 | .toastify-center {
63 | margin-left: auto;
64 | margin-right: auto;
65 | left: 0;
66 | right: 0;
67 | max-width: fit-content;
68 | max-width: -moz-fit-content;
69 | }
70 |
71 | @media only screen and (max-width: 360px) {
72 | .toastify-right, .toastify-left {
73 | margin-left: auto;
74 | margin-right: auto;
75 | left: 0;
76 | right: 0;
77 | max-width: fit-content;
78 | }
79 | }
--------------------------------------------------------------------------------
/api/config/hashing.php:
--------------------------------------------------------------------------------
1 | 'bcrypt',
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Bcrypt Options
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may specify the configuration options that should be used when
26 | | passwords are hashed using the Bcrypt algorithm. This will allow you
27 | | to control the amount of time it takes to hash the given password.
28 | |
29 | */
30 |
31 | 'bcrypt' => [
32 | 'rounds' => env('BCRYPT_ROUNDS', 10),
33 | ],
34 |
35 | /*
36 | |--------------------------------------------------------------------------
37 | | Argon Options
38 | |--------------------------------------------------------------------------
39 | |
40 | | Here you may specify the configuration options that should be used when
41 | | passwords are hashed using the Argon algorithm. These will allow you
42 | | to control the amount of time it takes to hash the given password.
43 | |
44 | */
45 |
46 | 'argon' => [
47 | 'memory' => 65536,
48 | 'threads' => 1,
49 | 'time' => 4,
50 | ],
51 |
52 | ];
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # DPXWallet
4 | DPXWallet is a Feature-Rich demonstration of a dummy Wallet app built in Telegram. It's main purpose is for [Telegram Mini App Contest](https://t.me/contest/327)
5 |
6 | ## Telegram WebApp
7 | You can access the DPXWallet WebApp in Telegram using [@DPXWalletBot](https://t.me/DPXWalletBot) or you can directly open [DPXWallet WebApp](https://t.me/DPXWalletBot/app).
8 |
9 | ## Documentation
10 | DPXWallet has a comprehensive [Documentation](https://erfanmola.github.io/DPXWallet/), addressing multiple aspects of the technical development. We recommend you to start from there.
11 |
12 | ### Introduction
13 | - [Introduction](https://erfanmola.github.io/DPXWallet/introduction.html)
14 | - [Getting Started](https://erfanmola.github.io/DPXWallet/getting-started.html)
15 | - [Technologies Used](https://erfanmola.github.io/DPXWallet/technologies-used.html)
16 |
17 | ### Preparation
18 | - [Environment Variables](https://erfanmola.github.io/DPXWallet/environment-variables.html)
19 |
20 | ### FrontEnd
21 | - [Setting Up the FrontEnd](https://erfanmola.github.io/DPXWallet/setting-up-frontend.html)
22 |
23 | ### BackEnd
24 | - [Setting Up the BackEnd](https://erfanmola.github.io/DPXWallet/setting-up-backend.html)
25 |
26 | ### API
27 | - [DPX API Guide](https://erfanmola.github.io/DPXWallet/dpx-api.html)
28 |
29 | ## TeleVue
30 |
31 | [TeleVue](https://github.com/erfanmola/TeleVue) is a Telegram UI Library for VueJS developed mainly for the purpose of this contest and it has been used in DPXWallet.
32 |
33 | ## License
34 | [MIT](https://github.com/erfanmola/DPXWallet/blob/master/LICENSE)
35 |
36 | ## Owner
37 | This repository and [@DPXWalletBot](https://t.me/DPXWalletBot) is owned by Erfan Mola ([@Eyfan](https://t.me/Eyfan)).
--------------------------------------------------------------------------------
/api/bootstrap/app.php:
--------------------------------------------------------------------------------
1 | singleton(
30 | Illuminate\Contracts\Http\Kernel::class,
31 | App\Http\Kernel::class
32 | );
33 |
34 | $app->singleton(
35 | Illuminate\Contracts\Console\Kernel::class,
36 | App\Console\Kernel::class
37 | );
38 |
39 | $app->singleton(
40 | Illuminate\Contracts\Debug\ExceptionHandler::class,
41 | App\Exceptions\Handler::class
42 | );
43 |
44 | /*
45 | |--------------------------------------------------------------------------
46 | | Return The Application
47 | |--------------------------------------------------------------------------
48 | |
49 | | This script returns the application instance. The instance is given to
50 | | the calling script so we can separate the building of the instances
51 | | from the actual running of the application and sending responses.
52 | |
53 | */
54 |
55 | return $app;
56 |
--------------------------------------------------------------------------------
/api/artisan:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | make(Illuminate\Contracts\Console\Kernel::class);
34 |
35 | $status = $kernel->handle(
36 | $input = new Symfony\Component\Console\Input\ArgvInput,
37 | new Symfony\Component\Console\Output\ConsoleOutput
38 | );
39 |
40 | /*
41 | |--------------------------------------------------------------------------
42 | | Shutdown The Application
43 | |--------------------------------------------------------------------------
44 | |
45 | | Once Artisan has finished running, we will fire off the shutdown events
46 | | so that any final work may be done by the application before we shut
47 | | down the process. This is the last thing to happen to the request.
48 | |
49 | */
50 |
51 | $kernel->terminate($input, $status);
52 |
53 | exit($status);
54 |
--------------------------------------------------------------------------------
/api/public/index.php:
--------------------------------------------------------------------------------
1 | make(Kernel::class);
50 |
51 | $response = $kernel->handle(
52 | $request = Request::capture()
53 | )->send();
54 |
55 | $kernel->terminate($request, $response);
56 |
--------------------------------------------------------------------------------
/webApp/src/components/badge.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/webApp/src/router/index.js:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHistory } from 'vue-router';
2 |
3 | import HomeView from '../views/Home.vue';
4 | import SettingsView from '../views/Settings.vue';
5 | import LoginView from '../views/Login.vue';
6 | import WalletView from '../views/Wallet.vue';
7 | import BadgesView from '../views/Badges.vue';
8 | import ReceiveView from '../views/Receive.vue';
9 | import TransferView from '../views/Transfer.vue';
10 | import TransactionsView from '../views/Transactions.vue';
11 | import TransactionView from '../views/Transaction.vue';
12 |
13 | const routes = [
14 | {
15 | path: '/',
16 | name: 'home',
17 | component: HomeView
18 | },
19 | {
20 | path: '/settings',
21 | name: 'settings',
22 | component: SettingsView
23 | },
24 | {
25 | path: '/login',
26 | name: 'login',
27 | component: LoginView
28 | },
29 | {
30 | path: '/wallet',
31 | name: 'wallet',
32 | component: WalletView,
33 | },
34 | {
35 | path: '/wallet/import',
36 | name: 'wallet-import',
37 | component: WalletView,
38 | },
39 | {
40 | path: '/badges',
41 | name: 'badges',
42 | component: BadgesView,
43 | },
44 | {
45 | path: '/receive',
46 | name: 'receive',
47 | component: ReceiveView,
48 | },
49 | {
50 | path: '/transfer/:destination([a-f0-9]{32})?/:amount?',
51 | name: 'transfer',
52 | component: TransferView,
53 | },
54 | {
55 | path: '/transactions',
56 | name: 'transactions',
57 | component: TransactionsView,
58 | },
59 | {
60 | path: '/transaction/:id',
61 | name: 'transaction',
62 | component: TransactionView,
63 | },
64 | ];
65 |
66 | const router = createRouter({
67 | history: createWebHistory(),
68 | routes
69 | });
70 |
71 | export default router;
--------------------------------------------------------------------------------
/docs/.vitepress/config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vitepress'
2 |
3 | // https://vitepress.dev/reference/site-config
4 | export default defineConfig({
5 | base: "/DPXWallet/",
6 | title: "DPXWallet Documentation",
7 | description: "Setup guide & documentations of DPXWallet Telegram WebApp",
8 | themeConfig: {
9 | // https://vitepress.dev/reference/default-theme-config
10 | nav: [
11 | { text: 'Home', link: '/' },
12 | { text: 'Getting Started', link: '/getting-started' },
13 | { text: 'TeleVue', link: 'https://github.com/erfanmola/TeleVue' }
14 | ],
15 |
16 | sidebar: [
17 | {
18 | text: 'DPXWallet',
19 | items: [
20 | { text: 'Introduction', link: '/introduction' },
21 | { text: 'Getting Started', link: '/getting-started' },
22 | { text: 'Technologies Used', link: '/technologies-used' }
23 | ]
24 | },
25 | {
26 | text: 'Preparation',
27 | items: [
28 | { text: 'Environment Variables', link: '/environment-variables' },
29 | ]
30 | },
31 | {
32 | text: 'FrontEnd',
33 | items: [
34 | { text: 'Setting Up FrontEnd', link: '/setting-up-frontend' },
35 | ]
36 | },
37 | {
38 | text: 'BackEnd',
39 | items: [
40 | { text: 'Setting Up BackEnd', link: '/setting-up-backend' },
41 | ]
42 | },
43 | {
44 | text: 'API',
45 | items: [
46 | { text: 'DPX API Guide', link: '/dpx-api' },
47 | { text: 'DPXCLI', link: 'https://github.com/Developix-ir/DPXCLI' }
48 | ]
49 | },
50 | {
51 | text: 'TeleVue',
52 | items: [
53 | { text: 'TeleVue Github', link: 'https://github.com/erfanmola/TeleVue' },
54 | { text: 'TeleVue Documentation', link: 'https://erfanmola.github.io/TeleVue/' },
55 | ]
56 | }
57 | ],
58 |
59 | socialLinks: [
60 | { icon: 'github', link: 'https://github.com/erfanmola/DPXWallet' }
61 | ]
62 | }
63 | })
64 |
--------------------------------------------------------------------------------
/api/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "laravel/laravel",
3 | "type": "project",
4 | "description": "The skeleton application for the Laravel framework.",
5 | "keywords": ["laravel", "framework"],
6 | "license": "MIT",
7 | "require": {
8 | "php": "^8.1",
9 | "guzzlehttp/guzzle": "^7.2",
10 | "laravel/framework": "^10.10",
11 | "laravel/octane": "^2.1",
12 | "laravel/tinker": "^2.8"
13 | },
14 | "require-dev": {
15 | "fakerphp/faker": "^1.9.1",
16 | "laravel/pint": "^1.0",
17 | "laravel/sail": "^1.18",
18 | "mockery/mockery": "^1.4.4",
19 | "nunomaduro/collision": "^7.0",
20 | "phpunit/phpunit": "^10.1",
21 | "spatie/laravel-ignition": "^2.0"
22 | },
23 | "autoload": {
24 | "psr-4": {
25 | "App\\": "app/",
26 | "Database\\Factories\\": "database/factories/",
27 | "Database\\Seeders\\": "database/seeders/"
28 | }
29 | },
30 | "autoload-dev": {
31 | "psr-4": {
32 | "Tests\\": "tests/"
33 | }
34 | },
35 | "scripts": {
36 | "post-autoload-dump": [
37 | "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
38 | "@php artisan package:discover --ansi"
39 | ],
40 | "post-update-cmd": [
41 | "@php artisan vendor:publish --tag=laravel-assets --ansi --force"
42 | ],
43 | "post-root-package-install": [
44 | "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
45 | ],
46 | "post-create-project-cmd": [
47 | "@php artisan key:generate --ansi"
48 | ]
49 | },
50 | "extra": {
51 | "laravel": {
52 | "dont-discover": []
53 | }
54 | },
55 | "config": {
56 | "optimize-autoloader": true,
57 | "preferred-install": "dist",
58 | "sort-packages": true,
59 | "allow-plugins": {
60 | "pestphp/pest-plugin": true,
61 | "php-http/discovery": true
62 | }
63 | },
64 | "minimum-stability": "stable",
65 | "prefer-stable": true
66 | }
67 |
--------------------------------------------------------------------------------
/webApp/src/views/Settings.vue:
--------------------------------------------------------------------------------
1 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | {{ $t('general.language', {}, { locale: localeItem }) }}
34 |
35 |
36 |
37 |
38 |
{{ $t('settings.copyright') }}
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/webApp/src/App.vue:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | Your client is not authorized, please use this WebApp from a valid Telegram Client
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | # Sample workflow for building and deploying a VitePress site to GitHub Pages
2 | #
3 | name: Deploy VitePress site to Pages
4 |
5 | on:
6 | # Runs on pushes targeting the `main` branch. Change this to `master` if you're
7 | # using the `master` branch as the default branch.
8 | push:
9 | branches: [master]
10 |
11 | # Allows you to run this workflow manually from the Actions tab
12 | workflow_dispatch:
13 |
14 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
15 | permissions:
16 | contents: read
17 | pages: write
18 | id-token: write
19 |
20 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
21 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
22 | concurrency:
23 | group: pages
24 | cancel-in-progress: false
25 |
26 | jobs:
27 | # Build job
28 | build:
29 | runs-on: ubuntu-latest
30 | steps:
31 | - name: Checkout
32 | uses: actions/checkout@v3
33 | with:
34 | fetch-depth: 0 # Not needed if lastUpdated is not enabled
35 | # - uses: pnpm/action-setup@v2 # Uncomment this if you're using pnpm
36 | # - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun
37 | - name: Setup Node
38 | uses: actions/setup-node@v3
39 | with:
40 | node-version: 18
41 | cache: npm # or pnpm / yarn
42 | cache-dependency-path: docs/package-lock.json
43 | - name: Setup Pages
44 | uses: actions/configure-pages@v3
45 | - name: Install dependencies
46 | run: npm ci --prefix docs # or pnpm install / yarn install / bun install
47 | - name: Build with VitePress
48 | run: |
49 | npm run docs:build --prefix docs # or pnpm docs:build / yarn docs:build / bun run docs:build
50 | touch docs/.vitepress/dist/.nojekyll
51 | - name: Upload artifact
52 | uses: actions/upload-pages-artifact@v2
53 | with:
54 | path: docs/.vitepress/dist
55 |
56 | # Deployment job
57 | deploy:
58 | environment:
59 | name: github-pages
60 | url: ${{ steps.deployment.outputs.page_url }}
61 | needs: build
62 | runs-on: ubuntu-latest
63 | name: Deploy
64 | steps:
65 | - name: Deploy to GitHub Pages
66 | id: deployment
67 | uses: actions/deploy-pages@v2
--------------------------------------------------------------------------------
/api/config/broadcasting.php:
--------------------------------------------------------------------------------
1 | env('BROADCAST_DRIVER', 'null'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Broadcast Connections
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may define all of the broadcast connections that will be used
26 | | to broadcast events to other systems or over websockets. Samples of
27 | | each available type of connection are provided inside this array.
28 | |
29 | */
30 |
31 | 'connections' => [
32 |
33 | 'pusher' => [
34 | 'driver' => 'pusher',
35 | 'key' => env('PUSHER_APP_KEY'),
36 | 'secret' => env('PUSHER_APP_SECRET'),
37 | 'app_id' => env('PUSHER_APP_ID'),
38 | 'options' => [
39 | 'cluster' => env('PUSHER_APP_CLUSTER'),
40 | 'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',
41 | 'port' => env('PUSHER_PORT', 443),
42 | 'scheme' => env('PUSHER_SCHEME', 'https'),
43 | 'encrypted' => true,
44 | 'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
45 | ],
46 | 'client_options' => [
47 | // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
48 | ],
49 | ],
50 |
51 | 'ably' => [
52 | 'driver' => 'ably',
53 | 'key' => env('ABLY_KEY'),
54 | ],
55 |
56 | 'redis' => [
57 | 'driver' => 'redis',
58 | 'connection' => 'default',
59 | ],
60 |
61 | 'log' => [
62 | 'driver' => 'log',
63 | ],
64 |
65 | 'null' => [
66 | 'driver' => 'null',
67 | ],
68 |
69 | ],
70 |
71 | ];
72 |
--------------------------------------------------------------------------------
/docs/setting-up-backend.md:
--------------------------------------------------------------------------------
1 | # Setting Up the BackEnd
2 |
3 | After reading the [Technologies used in backend](/technologies-used#backend) and [Setting up the FrontEnd](/setting-up-frontend), We are ready to continue the setup, build and deployment process of the DPXWallet's BackEnd.
4 |
5 | We obviously need `PHP` to be installed and some basic knowledge of `Laravel` and experience of deploying Laravel projects.
6 |
7 | ::: info
8 | Basically, Our entire backend is just a Laravel powered API and there are tons of methods and environments to deploy Laravel, I recommend you reading [Deployment of Laravel projects](https://laravel.com/docs/10.x/deployment) in Laravel's official documentations. **You only need to provide the correct [Environment Variables](/environment-variables)**.
9 | :::
10 |
11 | ## General Guide
12 |
13 | After ensuring that our server meets the [Requirements of a Laravel Project](https://laravel.com/docs/10.x/deployment#server-requirements). We have to change our Working Directory to `api` folder, since it's the folder containing our backend code:
14 | ```shell
15 | cd api
16 | ```
17 |
18 | ### Installing Dependencies
19 |
20 | At this step, we need to install our project's dependencies. We use [Composer](https://getcomposer.org/) as our package manager.
21 |
22 | ```shell
23 | composer install
24 | ```
25 |
26 | ### Migrating Database
27 |
28 | Our database structure is stored as Laravel migrations, so we need to run our migrations to create the tables.
29 |
30 | ```shell
31 | php artisan migrate
32 | ```
33 |
34 | :::warning
35 | This step requires correct setup of [Environment Variables](/environment-variables), otherwise you will face errors.
36 | :::
37 |
38 | ### Serving the project
39 |
40 | You can serve the project by running the command below:
41 |
42 | ```shell
43 | php artisan serve
44 | ```
45 |
46 | ::: tip
47 | The project is fully compatible with [Laravel Octane](https://laravel.com/docs/10.x/octane) and we recommend using it.
48 | :::
49 |
50 | ## Final words
51 |
52 | I am not sure that the information provided on this page is sufficent or not, since the backend is just a very basic Laravel project, I don't think it's correct to copy/paste the Laravel Docs here, that's why I believe that you must read Laravel Docs.
53 |
54 | Also it's worth mentioning that **Deploying a Laravel project** is just a `composer install` and `.env` editing and serving, but this could be very difficult task if you are not a PHP developer, so you have to learn Laravel from other sources, not from this guide.
--------------------------------------------------------------------------------
/api/config/filesystems.php:
--------------------------------------------------------------------------------
1 | env('FILESYSTEM_DISK', 'local'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Filesystem Disks
21 | |--------------------------------------------------------------------------
22 | |
23 | | Here you may configure as many filesystem "disks" as you wish, and you
24 | | may even configure multiple disks of the same driver. Defaults have
25 | | been set up for each driver as an example of the required values.
26 | |
27 | | Supported Drivers: "local", "ftp", "sftp", "s3"
28 | |
29 | */
30 |
31 | 'disks' => [
32 |
33 | 'local' => [
34 | 'driver' => 'local',
35 | 'root' => storage_path('app'),
36 | 'throw' => false,
37 | ],
38 |
39 | 'public' => [
40 | 'driver' => 'local',
41 | 'root' => storage_path('app/public'),
42 | 'url' => env('APP_URL').'/storage',
43 | 'visibility' => 'public',
44 | 'throw' => false,
45 | ],
46 |
47 | 's3' => [
48 | 'driver' => 's3',
49 | 'key' => env('AWS_ACCESS_KEY_ID'),
50 | 'secret' => env('AWS_SECRET_ACCESS_KEY'),
51 | 'region' => env('AWS_DEFAULT_REGION'),
52 | 'bucket' => env('AWS_BUCKET'),
53 | 'url' => env('AWS_URL'),
54 | 'endpoint' => env('AWS_ENDPOINT'),
55 | 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
56 | 'throw' => false,
57 | ],
58 |
59 | ],
60 |
61 | /*
62 | |--------------------------------------------------------------------------
63 | | Symbolic Links
64 | |--------------------------------------------------------------------------
65 | |
66 | | Here you may configure the symbolic links that will be created when the
67 | | `storage:link` Artisan command is executed. The array keys should be
68 | | the locations of the links and the values should be their targets.
69 | |
70 | */
71 |
72 | 'links' => [
73 | public_path('storage') => storage_path('app/public'),
74 | ],
75 |
76 | ];
77 |
--------------------------------------------------------------------------------
/docs/setting-up-frontend.md:
--------------------------------------------------------------------------------
1 | # Setting Up the FrontEnd
2 |
3 | After [Cloning the project](/getting-started#cloning-the-project) and reading the [Technologies used in frontend](/technologies-used#frontend), We are ready to continue the setup, build and deployment process of the DPXWallet.
4 |
5 | Firstly, we have to change our Working Directory to `webApp` folder, since it's the folder containing our frontend code:
6 | ```shell
7 | cd webApp
8 | ```
9 |
10 | ## Installing Dependencies
11 |
12 | :::danger
13 | I am very sorry to inform this, But I just accidentally `unpublished` the `@erfanmola/televue@0.1.5` package from npm, there is no way to restore it, sorry for this inconvenience. Please change the `0.1.5` to `0.1.6` in `webApp/package.json` as I republished it, otherwise you will face error when trying `npm install`.
14 | :::
15 |
16 | At this step, we need to install our project's dependencies. We use [NPM](https://www.npmjs.com/) as our package manager, but you can use any other tools (yarn, pnpm, ...).
17 |
18 | ```shell
19 | npm install
20 | ```
21 |
22 | ## Building the WebApp
23 |
24 | At this step, we are going to build our project with NPM. Built files are going to be outputted to `webApp/dist` folder.
25 |
26 | ```shell
27 | npm run build
28 | ```
29 |
30 | :::warning
31 | This step requires correct setup of [Environment Variables](/environment-variables), otherwise you will end up with unusable bundle.
32 | :::
33 |
34 | ## Deploying the WebApp
35 |
36 | ### Custom Server/Host
37 |
38 | After successfully building the project, Our WebApp files are ready to be served at `webApp/dist` directory. You can upload this directory to your desired server or hosting service or any other infrastructure.
39 |
40 | ### Github Pages
41 |
42 | Since our bundle is a bunch of static files, you can use [Github Pages](https://pages.github.com/) for building and hosting the WebApp too.
43 |
44 | ### Cloudflare Pages (Recommended)
45 |
46 | Our recommended way of deploying the WebApp is using [Cloudflare Pages](https://pages.cloudflare.com/), it's basically Github Pages but with extra features and cool stuffs, it supports automatic building and the only thing you need to do is connect your Github repository to you Cloudflare account and deploy your desired repository. It also handles automatic building/deploying of your project as you push to the repository.
47 |
48 | ### Other Infrastructures
49 | Basically you can use any other deployment service as long as they allow you to build your project with Environment Variables and serve static files.
50 |
51 | :::tip
52 | If you are using Automatic Deployment services like Github Pages, Cloudflare Pages or etc, you have to set you Root Path to `webApp`.
53 | :::
--------------------------------------------------------------------------------
/docs/environment-variables.md:
--------------------------------------------------------------------------------
1 | # Environment Variables
2 |
3 | We use environment variables to provide the private data that our webApp needs in order to operate, both in frontend and backend.
4 |
5 | Based on the environment that you use for deploying, You will specify these values.
6 |
7 | ::: tip
8 | If you use Docker or other fancy tools for deploying in a containerized environment, You have to specify these variables at your deployer service, for example [Render](https://render.com) for backend and [Cloudflare Pages](https://pages.cloudflare.com/) for frontend.
9 | :::
10 |
11 | ::: tip
12 | If you deploy manually and oldSchool way, you can copy the `api/.env.example` to `api/.env` and set the values accordingly.
13 | :::
14 |
15 | ## BackEnd
16 |
17 | ## Laravel
18 |
19 | ### `APP_URL`
20 | This variable is Laravel-specific and is used to specify the url that backend is deployed at.
21 |
22 | ### Database
23 | We use a MySQL database which requires you to fill these variables that specify the credentials and informations of the MySQL server and database.
24 |
25 | ```shell
26 | DB_CONNECTION=mysql
27 | DB_HOST=127.0.0.1
28 | DB_PORT=3306
29 | DB_DATABASE=
30 | DB_USERNAME=
31 | DB_PASSWORD=
32 | ```
33 |
34 | ## App
35 |
36 | ### `FEE`
37 | This variable specifies the amount of Fee per transaction. It defaults to `0.2` if not specified.
38 |
39 | ### `FEE_WALLET`
40 | This variable specifies the `wallet` address that the fee of transactions will be transfered to. This is usually the owner of the systems wallet address and can be set at any time (if you don't have a wallet address yet). If not set, transactions will be done with `0` fee.
41 |
42 | ### `TRANSACTIONS_PER_FETCH`
43 | This variable specifies the limit count of transactions per page when requested by clients.
44 |
45 |
46 | ## FrontEnd
47 | :::info
48 | All variables related to frontend are prefixed with `VITE_`.
49 | :::
50 |
51 | ### WebApp
52 |
53 | ### `VITE_APP_URL`
54 | This variable specifies the url of the backend, for frontend, it has to be the same value as `APP_URL` in the backend is.
55 |
56 | ### `VITE_FEE`
57 | This variable specifies the fee of transactions, just like `FEE` does in the backend, it's used for display and pre-calculation purposes on the front end, it has no real effect on the frontend. Default to `0.2` when not specified.
58 |
59 | ### TeleVue
60 | `VITE_HEX_HMAC_SIGNATURE` is an optional value that specifies the HMAC Signature of your bot token, used for client-side validation of the the webApp client by `AuthProvider` of TeleVue. [You can read more about it and how to generate it here](https://erfanmola.github.io/TeleVue/?path=/docs/providers-authprovider--docs#hex_hmac_signature).
61 |
62 | If not specified or empty, DPXWallet ignores the `AuthProvider` of TeleVue.
63 |
64 | ```shell
65 | VITE_HEX_HMAC_SIGNATURE= hmac signature of your bot token
66 | ```
--------------------------------------------------------------------------------
/api/app/Http/Kernel.php:
--------------------------------------------------------------------------------
1 |
15 | */
16 | protected $middleware = [
17 | // \App\Http\Middleware\TrustHosts::class,
18 | \App\Http\Middleware\TrustProxies::class,
19 | \Illuminate\Http\Middleware\HandleCors::class,
20 | \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
21 | \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
22 | \App\Http\Middleware\TrimStrings::class,
23 | \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
24 | ];
25 |
26 | /**
27 | * The application's route middleware groups.
28 | *
29 | * @var array>
30 | */
31 | protected $middlewareGroups = [
32 | 'web' => [
33 | \App\Http\Middleware\EncryptCookies::class,
34 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
35 | \Illuminate\Session\Middleware\StartSession::class,
36 | \Illuminate\View\Middleware\ShareErrorsFromSession::class,
37 | \App\Http\Middleware\VerifyCsrfToken::class,
38 | \Illuminate\Routing\Middleware\SubstituteBindings::class,
39 | ],
40 |
41 | 'api' => [
42 | // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
43 | \Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
44 | \Illuminate\Routing\Middleware\SubstituteBindings::class,
45 | ],
46 | ];
47 |
48 | /**
49 | * The application's middleware aliases.
50 | *
51 | * Aliases may be used instead of class names to conveniently assign middleware to routes and groups.
52 | *
53 | * @var array
54 | */
55 | protected $middlewareAliases = [
56 | 'auth' => \App\Http\Middleware\Authenticate::class,
57 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
58 | 'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
59 | 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
60 | 'can' => \Illuminate\Auth\Middleware\Authorize::class,
61 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
62 | 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
63 | 'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
64 | 'signed' => \App\Http\Middleware\ValidateSignature::class,
65 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
66 | 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
67 | ];
68 | }
69 |
--------------------------------------------------------------------------------
/api/app/Http/Controllers/API.php:
--------------------------------------------------------------------------------
1 | Respond(DPX::CreateWallet());
14 |
15 | }
16 |
17 | public function Transfer(Request $request) {
18 |
19 | $amount = (float)($request->all()['amount'] ?? 0);
20 | $departure = $request->all()['departure'] ?? '';
21 | $destination = $request->all()['destination'] ?? '';
22 | $secret = $request->all()['secret'] ?? '';
23 |
24 | return DPX::Transfer($departure, $destination, $amount, $secret);
25 |
26 | }
27 |
28 | public function Verify(Request $request) {
29 |
30 | $wallet = $request->all()['wallet'] ?? '';
31 | $secret = $request->all()['secret'] ?? '';
32 |
33 | $verify = DPX::Verify($wallet, $secret);
34 |
35 | return $verify ? API::Respond(true) : API::Error('invalid-credentials', true, 'Provided credentials are invalid');
36 |
37 | }
38 |
39 | public function Revoke(Request $request) {
40 |
41 | $wallet = $request->all()['wallet'] ?? '';
42 | $secret = $request->all()['secret'] ?? '';
43 |
44 | $revoke = DPX::RevokeSecret($wallet, $secret);
45 |
46 | return $revoke ? API::Respond($revoke) : API::Error('invalid-credentials', true, 'Provided credentials are invalid');
47 |
48 | }
49 |
50 | public function Balance(Request $request) {
51 |
52 | return DPX::GetBalance($request->route('wallet'));
53 |
54 | }
55 |
56 | public function Transactions(Request $request) {
57 |
58 | $offset = (int)($request->all()['offset'] ?? 0);
59 | $departure = $request->all()['departure'] ?? null;
60 | $destination = $request->all()['destination'] ?? null;
61 |
62 | if ($departure && !(preg_match('/' . config('regex.md5') . '/', $departure))) {
63 |
64 | $departure = null;
65 |
66 | }
67 |
68 | if ($destination && !(preg_match('/' . config('regex.md5') . '/', $destination))) {
69 |
70 | $destination = null;
71 |
72 | }
73 |
74 | return DPX::GetTransactions($offset, $departure, $destination);
75 |
76 | }
77 |
78 | public function Transaction(Request $request) {
79 |
80 | return DPX::GetTransaction($request->route('id'));
81 |
82 | }
83 |
84 | public function Invalid() {
85 |
86 | return $this->Error('unsupported-action', true, 'Method is not allowed');
87 |
88 | }
89 |
90 | public static function Respond($data, $status = 'success', $json_encode = true) {
91 |
92 | $response = [ 'status' => $status, 'result' => $data ];
93 |
94 | return $json_encode ? response()->json($response) : $response;
95 |
96 | }
97 |
98 | public static function Error($error, $info = null) {
99 |
100 | return [
101 | 'status' => 'error',
102 | 'error' => $error,
103 | 'info' => $info
104 | ];
105 |
106 | }
107 |
108 | }
--------------------------------------------------------------------------------
/docs/technologies-used.md:
--------------------------------------------------------------------------------
1 | # Technologies Used
2 | In this section, we are going to describe every technology used in both frontend and backend of the project. We are going to explain the usage of each tool in the DPXWallet.
3 |
4 | ## FrontEnd
5 | Our aim in the frontend side of the project is to provide a modern development experience while keeping the project understandable and maintainable. That's why we chose the technologies and tools below.
6 |
7 | ### Vite
8 | We scaffolded our project using the [Vite](https://vitejs.dev/). It's blazingly fast compared to it's competitors, just like comparing Telegram to it's rivals. (What was the name? Wat Sap or something?)
9 |
10 | ### Sass
11 | We styled our project using the SCSS format of the [Sass](https://sass-lang.com/). It's just a prefernce, but most people do prefer SCSS since it's just regular CSS syntax with superpowers. We know that Tailwind thingy exists, but nah, we don't pollute markup with article-long class names.
12 |
13 | ### VueJS
14 | VueJS is our **#1** choice of web frameworks. You ask the reason why? Cause the sky is high, also elephants can't fly. How can you just not like the cool [VueJS](https://vuejs.org/) with it's Composition API? But jokes aside, any framework could have been used, all those Reacty and Angulary and Svelty guys are ok to use. Using VueJS is just a personal choice of the developer.
15 |
16 | #### `vue-router`
17 | We use [Vue Router](https://router.vuejs.org/) as our routing system in the SPA.
18 |
19 | #### `vue-i18n`
20 | We use [Vue i18n](https://vue-i18n.intlify.dev/) as our i18n provider for multi-language setup.
21 |
22 | ### `pinia`
23 | We use [Pinia](https://pinia.vuejs.org/) as our state manager.
24 |
25 | ### `toastify-js`
26 | We use [toastify-js](https://apvarun.github.io/toastify-js/) to show our toast messages.
27 |
28 | ### `qr-code-styling`
29 | We use [qr-code-styling package](https://www.npmjs.com/package/qr-code-styling) to generate our fancy QR Codes.
30 |
31 | ### TeleVue
32 | We developed an exclusive Telegram UI Library for VueJS, just for the purpose of this WebApp and Telegram Mini App Contest. If you are both a Telegram Enjoyer and VueJS's fiancé, then you should try [TeleVue](https://github.com/erfanmola/TeleVue) for you next TWA (Telegram Web App), I know they call it MiniApps, but they are wrong, yeah Telegram, you are wrong.
33 |
34 | ### i18n
35 | We use the i18n standard for defining our locales and making DPXWallet multilingual.
36 |
37 | ::: tip
38 | We are welcoming translators to help us translate the DPXWallet to different languages, you can start from `webApp/src/i18n` directory.
39 | :::
40 |
41 | ::: info
42 | The package used for i18n in Vue is [explained here](#vue-i18n).
43 | :::
44 |
45 | ### TWA
46 |
47 | We use [@twa-dev/sdk](https://github.com/twa-dev/SDK) as a replacement for the legacy `telegram-web-app.js`. Telegram web dudes are a bunch of C++ developers familiar with HTML/CSS, they use JQuery and Bootstrap from the early 80's and they don't provide a modular solution nor a package for their Javascripts, that's why we use this as package a replacement.
48 |
49 | ## BackEnd
50 | Our aim for the backend side of the project is to provide a basic CRUD-like API without making it complex.
51 |
52 | ### Laravel (PHP)
53 | We use [Laravel](https://laravel.com/) as our backend API, it's completely hooked-up and compatible with [Laravel Octane](https://laravel.com/docs/10.x/octane) to be used with [OpenSwoole](https://openswoole.com/) or [Roadrunner](https://roadrunner.dev/) for the most efficency and performance.
54 |
55 | ### MySQL
56 | We use [MySQL](https://www.mysql.com/) as our database backend, but since we have migration files, we are not limited to MySQL, so other options like SQLite could be used too.
--------------------------------------------------------------------------------
/api/config/cache.php:
--------------------------------------------------------------------------------
1 | env('CACHE_DRIVER', 'file'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Cache Stores
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may define all of the cache "stores" for your application as
26 | | well as their drivers. You may even define multiple stores for the
27 | | same cache driver to group types of items stored in your caches.
28 | |
29 | | Supported drivers: "apc", "array", "database", "file",
30 | | "memcached", "redis", "dynamodb", "octane", "null"
31 | |
32 | */
33 |
34 | 'stores' => [
35 |
36 | 'apc' => [
37 | 'driver' => 'apc',
38 | ],
39 |
40 | 'array' => [
41 | 'driver' => 'array',
42 | 'serialize' => false,
43 | ],
44 |
45 | 'database' => [
46 | 'driver' => 'database',
47 | 'table' => 'cache',
48 | 'connection' => null,
49 | 'lock_connection' => null,
50 | ],
51 |
52 | 'file' => [
53 | 'driver' => 'file',
54 | 'path' => storage_path('framework/cache/data'),
55 | 'lock_path' => storage_path('framework/cache/data'),
56 | ],
57 |
58 | 'memcached' => [
59 | 'driver' => 'memcached',
60 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
61 | 'sasl' => [
62 | env('MEMCACHED_USERNAME'),
63 | env('MEMCACHED_PASSWORD'),
64 | ],
65 | 'options' => [
66 | // Memcached::OPT_CONNECT_TIMEOUT => 2000,
67 | ],
68 | 'servers' => [
69 | [
70 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'),
71 | 'port' => env('MEMCACHED_PORT', 11211),
72 | 'weight' => 100,
73 | ],
74 | ],
75 | ],
76 |
77 | 'redis' => [
78 | 'driver' => 'redis',
79 | 'connection' => 'cache',
80 | 'lock_connection' => 'default',
81 | ],
82 |
83 | 'dynamodb' => [
84 | 'driver' => 'dynamodb',
85 | 'key' => env('AWS_ACCESS_KEY_ID'),
86 | 'secret' => env('AWS_SECRET_ACCESS_KEY'),
87 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
88 | 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
89 | 'endpoint' => env('DYNAMODB_ENDPOINT'),
90 | ],
91 |
92 | 'octane' => [
93 | 'driver' => 'octane',
94 | ],
95 |
96 | ],
97 |
98 | /*
99 | |--------------------------------------------------------------------------
100 | | Cache Key Prefix
101 | |--------------------------------------------------------------------------
102 | |
103 | | When utilizing the APC, database, memcached, Redis, or DynamoDB cache
104 | | stores there might be other applications using the same cache. For
105 | | that reason, you may prefix every cache key to avoid collisions.
106 | |
107 | */
108 |
109 | 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'),
110 |
111 | ];
112 |
--------------------------------------------------------------------------------
/api/config/queue.php:
--------------------------------------------------------------------------------
1 | env('QUEUE_CONNECTION', 'sync'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Queue Connections
21 | |--------------------------------------------------------------------------
22 | |
23 | | Here you may configure the connection information for each server that
24 | | is used by your application. A default configuration has been added
25 | | for each back-end shipped with Laravel. You are free to add more.
26 | |
27 | | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
28 | |
29 | */
30 |
31 | 'connections' => [
32 |
33 | 'sync' => [
34 | 'driver' => 'sync',
35 | ],
36 |
37 | 'database' => [
38 | 'driver' => 'database',
39 | 'table' => 'jobs',
40 | 'queue' => 'default',
41 | 'retry_after' => 90,
42 | 'after_commit' => false,
43 | ],
44 |
45 | 'beanstalkd' => [
46 | 'driver' => 'beanstalkd',
47 | 'host' => 'localhost',
48 | 'queue' => 'default',
49 | 'retry_after' => 90,
50 | 'block_for' => 0,
51 | 'after_commit' => false,
52 | ],
53 |
54 | 'sqs' => [
55 | 'driver' => 'sqs',
56 | 'key' => env('AWS_ACCESS_KEY_ID'),
57 | 'secret' => env('AWS_SECRET_ACCESS_KEY'),
58 | 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
59 | 'queue' => env('SQS_QUEUE', 'default'),
60 | 'suffix' => env('SQS_SUFFIX'),
61 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
62 | 'after_commit' => false,
63 | ],
64 |
65 | 'redis' => [
66 | 'driver' => 'redis',
67 | 'connection' => 'default',
68 | 'queue' => env('REDIS_QUEUE', 'default'),
69 | 'retry_after' => 90,
70 | 'block_for' => null,
71 | 'after_commit' => false,
72 | ],
73 |
74 | ],
75 |
76 | /*
77 | |--------------------------------------------------------------------------
78 | | Job Batching
79 | |--------------------------------------------------------------------------
80 | |
81 | | The following options configure the database and table that store job
82 | | batching information. These options can be updated to any database
83 | | connection and table which has been defined by your application.
84 | |
85 | */
86 |
87 | 'batching' => [
88 | 'database' => env('DB_CONNECTION', 'mysql'),
89 | 'table' => 'job_batches',
90 | ],
91 |
92 | /*
93 | |--------------------------------------------------------------------------
94 | | Failed Queue Jobs
95 | |--------------------------------------------------------------------------
96 | |
97 | | These options configure the behavior of failed queue job logging so you
98 | | can control which database and table are used to store the jobs that
99 | | have failed. You may change them to any database / table you wish.
100 | |
101 | */
102 |
103 | 'failed' => [
104 | 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
105 | 'database' => env('DB_CONNECTION', 'mysql'),
106 | 'table' => 'failed_jobs',
107 | ],
108 |
109 | ];
110 |
--------------------------------------------------------------------------------
/api/config/mail.php:
--------------------------------------------------------------------------------
1 | env('MAIL_MAILER', 'smtp'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Mailer Configurations
21 | |--------------------------------------------------------------------------
22 | |
23 | | Here you may configure all of the mailers used by your application plus
24 | | their respective settings. Several examples have been configured for
25 | | you and you are free to add your own as your application requires.
26 | |
27 | | Laravel supports a variety of mail "transport" drivers to be used while
28 | | sending an e-mail. You will specify which one you are using for your
29 | | mailers below. You are free to add additional mailers as required.
30 | |
31 | | Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2",
32 | | "postmark", "log", "array", "failover"
33 | |
34 | */
35 |
36 | 'mailers' => [
37 | 'smtp' => [
38 | 'transport' => 'smtp',
39 | 'url' => env('MAIL_URL'),
40 | 'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
41 | 'port' => env('MAIL_PORT', 587),
42 | 'encryption' => env('MAIL_ENCRYPTION', 'tls'),
43 | 'username' => env('MAIL_USERNAME'),
44 | 'password' => env('MAIL_PASSWORD'),
45 | 'timeout' => null,
46 | 'local_domain' => env('MAIL_EHLO_DOMAIN'),
47 | ],
48 |
49 | 'ses' => [
50 | 'transport' => 'ses',
51 | ],
52 |
53 | 'mailgun' => [
54 | 'transport' => 'mailgun',
55 | // 'client' => [
56 | // 'timeout' => 5,
57 | // ],
58 | ],
59 |
60 | 'postmark' => [
61 | 'transport' => 'postmark',
62 | // 'client' => [
63 | // 'timeout' => 5,
64 | // ],
65 | ],
66 |
67 | 'sendmail' => [
68 | 'transport' => 'sendmail',
69 | 'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),
70 | ],
71 |
72 | 'log' => [
73 | 'transport' => 'log',
74 | 'channel' => env('MAIL_LOG_CHANNEL'),
75 | ],
76 |
77 | 'array' => [
78 | 'transport' => 'array',
79 | ],
80 |
81 | 'failover' => [
82 | 'transport' => 'failover',
83 | 'mailers' => [
84 | 'smtp',
85 | 'log',
86 | ],
87 | ],
88 | ],
89 |
90 | /*
91 | |--------------------------------------------------------------------------
92 | | Global "From" Address
93 | |--------------------------------------------------------------------------
94 | |
95 | | You may wish for all e-mails sent by your application to be sent from
96 | | the same address. Here, you may specify a name and address that is
97 | | used globally for all e-mails that are sent by your application.
98 | |
99 | */
100 |
101 | 'from' => [
102 | 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
103 | 'name' => env('MAIL_FROM_NAME', 'Example'),
104 | ],
105 |
106 | /*
107 | |--------------------------------------------------------------------------
108 | | Markdown Mail Settings
109 | |--------------------------------------------------------------------------
110 | |
111 | | If you are using Markdown based email rendering, you may configure your
112 | | theme and component paths here, allowing you to customize the design
113 | | of the emails. Or, you may simply stick with the Laravel defaults!
114 | |
115 | */
116 |
117 | 'markdown' => [
118 | 'theme' => 'default',
119 |
120 | 'paths' => [
121 | resource_path('views/vendor/mail'),
122 | ],
123 | ],
124 |
125 | ];
126 |
--------------------------------------------------------------------------------
/api/config/auth.php:
--------------------------------------------------------------------------------
1 | [
17 | 'guard' => 'web',
18 | 'passwords' => 'users',
19 | ],
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | Authentication Guards
24 | |--------------------------------------------------------------------------
25 | |
26 | | Next, you may define every authentication guard for your application.
27 | | Of course, a great default configuration has been defined for you
28 | | here which uses session storage and the Eloquent user provider.
29 | |
30 | | All authentication drivers have a user provider. This defines how the
31 | | users are actually retrieved out of your database or other storage
32 | | mechanisms used by this application to persist your user's data.
33 | |
34 | | Supported: "session"
35 | |
36 | */
37 |
38 | 'guards' => [
39 | 'web' => [
40 | 'driver' => 'session',
41 | 'provider' => 'users',
42 | ],
43 | ],
44 |
45 | /*
46 | |--------------------------------------------------------------------------
47 | | User Providers
48 | |--------------------------------------------------------------------------
49 | |
50 | | All authentication drivers have a user provider. This defines how the
51 | | users are actually retrieved out of your database or other storage
52 | | mechanisms used by this application to persist your user's data.
53 | |
54 | | If you have multiple user tables or models you may configure multiple
55 | | sources which represent each model / table. These sources may then
56 | | be assigned to any extra authentication guards you have defined.
57 | |
58 | | Supported: "database", "eloquent"
59 | |
60 | */
61 |
62 | 'providers' => [
63 | 'users' => [
64 | 'driver' => 'eloquent',
65 | 'model' => App\Models\User::class,
66 | ],
67 |
68 | // 'users' => [
69 | // 'driver' => 'database',
70 | // 'table' => 'users',
71 | // ],
72 | ],
73 |
74 | /*
75 | |--------------------------------------------------------------------------
76 | | Resetting Passwords
77 | |--------------------------------------------------------------------------
78 | |
79 | | You may specify multiple password reset configurations if you have more
80 | | than one user table or model in the application and you want to have
81 | | separate password reset settings based on the specific user types.
82 | |
83 | | The expiry time is the number of minutes that each reset token will be
84 | | considered valid. This security feature keeps tokens short-lived so
85 | | they have less time to be guessed. You may change this as needed.
86 | |
87 | | The throttle setting is the number of seconds a user must wait before
88 | | generating more password reset tokens. This prevents the user from
89 | | quickly generating a very large amount of password reset tokens.
90 | |
91 | */
92 |
93 | 'passwords' => [
94 | 'users' => [
95 | 'provider' => 'users',
96 | 'table' => 'password_reset_tokens',
97 | 'expire' => 60,
98 | 'throttle' => 60,
99 | ],
100 | ],
101 |
102 | /*
103 | |--------------------------------------------------------------------------
104 | | Password Confirmation Timeout
105 | |--------------------------------------------------------------------------
106 | |
107 | | Here you may define the amount of seconds before a password confirmation
108 | | times out and the user is prompted to re-enter their password via the
109 | | confirmation screen. By default, the timeout lasts for three hours.
110 | |
111 | */
112 |
113 | 'password_timeout' => 10800,
114 |
115 | ];
116 |
--------------------------------------------------------------------------------
/webApp/src/assets/images/credit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/api/config/logging.php:
--------------------------------------------------------------------------------
1 | env('LOG_CHANNEL', 'stack'),
22 |
23 | /*
24 | |--------------------------------------------------------------------------
25 | | Deprecations Log Channel
26 | |--------------------------------------------------------------------------
27 | |
28 | | This option controls the log channel that should be used to log warnings
29 | | regarding deprecated PHP and library features. This allows you to get
30 | | your application ready for upcoming major versions of dependencies.
31 | |
32 | */
33 |
34 | 'deprecations' => [
35 | 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
36 | 'trace' => false,
37 | ],
38 |
39 | /*
40 | |--------------------------------------------------------------------------
41 | | Log Channels
42 | |--------------------------------------------------------------------------
43 | |
44 | | Here you may configure the log channels for your application. Out of
45 | | the box, Laravel uses the Monolog PHP logging library. This gives
46 | | you a variety of powerful log handlers / formatters to utilize.
47 | |
48 | | Available Drivers: "single", "daily", "slack", "syslog",
49 | | "errorlog", "monolog",
50 | | "custom", "stack"
51 | |
52 | */
53 |
54 | 'channels' => [
55 | 'stack' => [
56 | 'driver' => 'stack',
57 | 'channels' => ['single'],
58 | 'ignore_exceptions' => false,
59 | ],
60 |
61 | 'single' => [
62 | 'driver' => 'single',
63 | 'path' => storage_path('logs/laravel.log'),
64 | 'level' => env('LOG_LEVEL', 'debug'),
65 | 'replace_placeholders' => true,
66 | ],
67 |
68 | 'daily' => [
69 | 'driver' => 'daily',
70 | 'path' => storage_path('logs/laravel.log'),
71 | 'level' => env('LOG_LEVEL', 'debug'),
72 | 'days' => 14,
73 | 'replace_placeholders' => true,
74 | ],
75 |
76 | 'slack' => [
77 | 'driver' => 'slack',
78 | 'url' => env('LOG_SLACK_WEBHOOK_URL'),
79 | 'username' => 'Laravel Log',
80 | 'emoji' => ':boom:',
81 | 'level' => env('LOG_LEVEL', 'critical'),
82 | 'replace_placeholders' => true,
83 | ],
84 |
85 | 'papertrail' => [
86 | 'driver' => 'monolog',
87 | 'level' => env('LOG_LEVEL', 'debug'),
88 | 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),
89 | 'handler_with' => [
90 | 'host' => env('PAPERTRAIL_URL'),
91 | 'port' => env('PAPERTRAIL_PORT'),
92 | 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
93 | ],
94 | 'processors' => [PsrLogMessageProcessor::class],
95 | ],
96 |
97 | 'stderr' => [
98 | 'driver' => 'monolog',
99 | 'level' => env('LOG_LEVEL', 'debug'),
100 | 'handler' => StreamHandler::class,
101 | 'formatter' => env('LOG_STDERR_FORMATTER'),
102 | 'with' => [
103 | 'stream' => 'php://stderr',
104 | ],
105 | 'processors' => [PsrLogMessageProcessor::class],
106 | ],
107 |
108 | 'syslog' => [
109 | 'driver' => 'syslog',
110 | 'level' => env('LOG_LEVEL', 'debug'),
111 | 'facility' => LOG_USER,
112 | 'replace_placeholders' => true,
113 | ],
114 |
115 | 'errorlog' => [
116 | 'driver' => 'errorlog',
117 | 'level' => env('LOG_LEVEL', 'debug'),
118 | 'replace_placeholders' => true,
119 | ],
120 |
121 | 'null' => [
122 | 'driver' => 'monolog',
123 | 'handler' => NullHandler::class,
124 | ],
125 |
126 | 'emergency' => [
127 | 'path' => storage_path('logs/laravel.log'),
128 | ],
129 | ],
130 |
131 | ];
132 |
--------------------------------------------------------------------------------
/docs/dpx-api.md:
--------------------------------------------------------------------------------
1 | # 💎 DPX API
2 | DPX API is an application programming interface for interacting with the DPX System
3 |
4 | ## 🔰 Endpoint
5 | The endpoint of DPX API is accessible at https://dpx.developix.ir/api. If deployed on a custom server, it could be accessed at `ADDRESS/api`.
6 |
7 | ## ⚙️ Supported Methods
8 | Generally speaking, the API accepts `GET` or `POST` http methods based on the action you are requesting, some actions accept both methods that are specified below, but no action accepts any other method than `POST` and `GET`.
9 |
10 | **⚠️ Please note that the `POST` method parameters must be in the format of `Form Data`.**
11 |
12 | ## ✨ Methods
13 |
14 | ### 💠 Balance
15 | **Description:** Retrieves the balance of the given wallet
16 | **Path:** `/balance`
17 | **Supported Methods:** `GET`
18 | **Return:** `Balance (Float)`
19 | **Params:** `/balance/{wallet}`
20 |
21 | ### 💠 Transaction
22 | **Description:** Retrieves the information of the given TransactionID
23 | **Path:** `/transaction`
24 | **Supported Methods:** `GET`
25 | **Return:** `Transaction Object`
26 | **Params:** `/transaction/{transactionId}`
27 |
28 | ### 💠 Transactions
29 | **Description:** Retrieves the transactions with given criteria (maximum of 256 items)
30 | **Path:** `/transactions`
31 | **Supported Methods:** `GET`, `POST`
32 | **Return:** `Array of Transaction Objects`
33 | | Field | Type | Required | Description |
34 | |-------------|--------|----------|----------------------------------|
35 | | offset | int | Optional | Specifies the offset |
36 | | departure | string | Optional | Specifies the departure wallet |
37 | | destination | string | Optional | Specifies the destination wallet |
38 |
39 | ### 💠 Transfer
40 | **Description:** Transfers the specified amount from departure wallet to destination wallet
41 | **Path:** `/transfer`
42 | **Supported Methods:** `POST`
43 | **Return:** `Transaction Object`
44 | | Field | Type | Required | Description |
45 | |-------------|--------|----------|----------------------------------------------|
46 | | amount | float | Required | Specifies the amount |
47 | | departure | string | Required | Specifies the departure wallet |
48 | | secret | string | Required | Specifies the secret of the departure wallet |
49 | | destination | string | Required | Specifies the destination wallet |
50 |
51 | ### 💠 Verify
52 | **Description:** Verifies if the given credentials are valid and transfer can be done with given credentials
53 | **Path:** `/verify`
54 | **Supported Methods:** `POST`
55 | **Return:** `Validity (Boolean)`
56 | | Field | Type | Required | Description |
57 | |-------------|--------|----------|------------------------------------|
58 | | wallet | string | Required | Specifies the wallet |
59 | | secret | string | Required | Specifies the secret of the wallet |
60 |
61 | ### 💠 Generate
62 | **Description:** Generates a new wallet
63 | **Path:** `/generate`
64 | **Supported Methods:** `POST`
65 | **Return:** `Wallet & Secret (JSON Object)`
66 |
67 | ### 💠 Revoke
68 | **Description:** Revokes the secret of the given wallet
69 | **Path:** `/revoke`
70 | **Supported Methods:** `POST`
71 | **Return:** `New Secret (String)`
72 | | Field | Type | Required | Description |
73 | |-------------|--------|----------|------------------------------------|
74 | | wallet | string | Required | Specifies the wallet |
75 | | secret | string | Required | Specifies the secret of the wallet |
76 |
77 | ## 🧩 Object Types
78 |
79 | ### 💠 Transaction Object
80 | **Description:** Table below describes a `transaction object`
81 | | Field | Type | Description |
82 | |-------------|--------|--------------------------------------|
83 | | transaction | string | Specifies the transaction id |
84 | | departure | string | Specifies the departure wallet |
85 | | destination | string | Specifies the destination wallet |
86 | | amount | float | Specifies the amount |
87 | | fee | float | Specifies the fee |
88 | | timestamp | int | Specifies the timestamp |
89 |
90 | ## 🏳️ Response Types
91 | Generally, you would receive one of the two following JSON-Serialized responses, a Success or a Failure
92 |
93 | ### ✅ Success
94 | ```json
95 | {
96 | "status": "success",
97 | "result": RETURN_VALUE
98 | }
99 | ```
100 |
101 | ### ❌ Failed
102 | ```json
103 | {
104 | "status": "error",
105 | "error": "error-code",
106 | "info": "Error description in English"
107 | }
108 | ```
--------------------------------------------------------------------------------
/webApp/src/i18n/lang-ar.js:
--------------------------------------------------------------------------------
1 | const i18n_ar = {
2 | general: {
3 | title: 'محفظة DPX',
4 | language: 'العربية',
5 | yes: 'نعم',
6 | no: 'لا',
7 | },
8 | login: {
9 | title: "مرحبًا بك في محفظة DPX",
10 | description: "للبدء، يجب عليك إنشاء محفظة جديدة أو استيراد محفظة موجودة إذا كانت لديك بالفعل.",
11 | buttons: {
12 | import: "استيراد المحفظة",
13 | create: "إنشاء محفظة"
14 | },
15 | toast: {
16 | wallet_created: 'تم إنشاء المحفظة بنجاح'
17 | }
18 | },
19 | settings: {
20 | language: {
21 | title: 'اللغة',
22 | description: 'اختر لغتك المفضلة',
23 | },
24 | copyright: 'تطوير بواسطة عرفان مولا باستخدام TeleVue',
25 | },
26 | wallet: {
27 | title: {
28 | wallet: 'المحفظة',
29 | import: 'استيراد المحفظة',
30 | },
31 | fields: {
32 | wallet: 'عنوان المحفظة',
33 | secret: 'عبارة سرية',
34 | },
35 | import_wallet: 'استيراد المحفظة',
36 | save_wallet: 'حفظ المحفظة',
37 | hint: 'في هذا القسم، يمكنك إدخال معلومات المحفظة الخاصة بك. كل من عنوان المحفظة والعبارة السرية تتكون من 32 حرفًا. يمكنك مسحها إذا كنت تمتلك رموز الاستجابة السريعة (QR codes).',
38 | revoke_secret: 'إلغاء العبارة السرية',
39 | clear_session: 'مسح المحفظة من هذا الجهاز',
40 | scan_wallet: 'مسح عنوان المحفظة بواسطة رمز الاستجابة السريعة',
41 | scan_secret: 'مسح قيمة العبارة السرية بواسطة رمز الاستجابة السريعة',
42 | toast: {
43 | wallet_saved: 'تم حفظ المحفظة بنجاح',
44 | wallet_imported: 'تم استيراد المحفظة بنجاح',
45 | secret_revoked: 'تم إلغاء العبارة السرية بنجاح والحفظ',
46 | },
47 | prompt: {
48 | revoke_secret: {
49 | title: 'إلغاء العبارة السرية',
50 | text: 'هل تريد إلغاء العبارة السرية لمحفظتك؟',
51 | },
52 | clear_session: {
53 | title: 'مسح المحفظة',
54 | text: 'هل تريد مسح هذه المحفظة من جهازك؟',
55 | },
56 | }
57 | },
58 | home: {
59 | balance: 'الرصيد',
60 | receive: 'استقبال',
61 | send: 'إرسال',
62 | },
63 | badges: {
64 | leagues: 'الدوريات',
65 | ranks: {
66 | tier_1: 'برونز',
67 | tier_2: 'فضي',
68 | tier_3: 'ذهبي',
69 | tier_4: 'بلاتيني',
70 | tier_5: 'الماس',
71 | tier_6: 'غامض',
72 | tier_7: 'بطل',
73 | tier_8: 'أسطورة',
74 | }
75 | },
76 | receive: {
77 | set: 'تعيين',
78 | amount: 'المبلغ (اختياري)',
79 | receive_amount: 'المبلغ المستلم (DPX)',
80 | hint: 'يمكنك نسخ ومشاركة عنوان محفظتك بالنقر فوق العنوان. يمكنك أيضًا مشاركة رمز الاستجابة السريعة الخاص بمحفظتك.',
81 | toast: {
82 | wallet_copied: 'تم نسخ عنوان المحفظة إلى الحافظة',
83 | }
84 | },
85 | transfer: {
86 | title: 'التحويل',
87 | fields: {
88 | departure: 'المحفظة المرسلة',
89 | destination: 'المحفظة المستلمة',
90 | amount: 'المبلغ',
91 | transfer_amount: 'مبلغ التحويل (DPX)'
92 | },
93 | request_transfer: 'طلب التحويل',
94 | toast: {
95 | success: 'تمت العملية بنجاح'
96 | },
97 | prompt: {
98 | verify_transfer: {
99 | title: 'تأكيد التحويل',
100 | text: 'أنت على وشك نقل {amount} DPX برسوم قدرها {fee} DPX إلى {destination}. هل ترغب في المتابعة؟',
101 | },
102 | }
103 | },
104 | api: {
105 | errors: {
106 | 'invalid-credentials': 'بيانات الاعتماد المقدمة غير صالحة',
107 | 'invalid-departure': 'المحفظة المرسلة غير صالحة',
108 | 'invalid-destination': 'المحفظة المستلمة غير صالحة',
109 | 'invalid-secret-format': 'صيغة العبارة السرية غير صالحة',
110 | 'invalid-amount': 'المبلغ غير صالح',
111 | 'same-departure-destination': 'المحفظة المرسلة والمستلمة هما نفسهما',
112 | 'locked-departure': 'المحفظة المرسلة مغلقة',
113 | 'locked-destination': 'المحفظة المستلمة مغلقة',
114 | 'invalid-wallet': 'المحفظة غير صالحة',
115 | 'invalid-secret': 'العبارة السرية غير صالحة',
116 | 'insufficient-balance': 'الرصيد غير كافي',
117 | 'invalid-transaction': 'العملية غير صالحة',
118 | }
119 | },
120 | transactions: {
121 | title: 'المعاملات',
122 | transaction: 'المعاملة',
123 | sent: 'تم الإرسال',
124 | received: 'تم الاستلام',
125 | no_transactions: 'لم يتم العثور على أي معاملات'
126 | },
127 | transaction: {
128 | title: 'المعاملة',
129 | info: 'التفاصيل',
130 | fields: {
131 | id: 'المعرف',
132 | departure: 'المرسل',
133 | destination: 'المستلم',
134 | amount: 'المبلغ',
135 | fee: 'الرسوم',
136 | date: 'التاريخ',
137 | }
138 | },
139 | };
140 |
141 | export default i18n_ar;
142 |
--------------------------------------------------------------------------------
/webApp/src/i18n/lang-en.js:
--------------------------------------------------------------------------------
1 | const i18n_en = {
2 | general: {
3 | title: 'DPX Wallet',
4 | language: 'English',
5 | yes: 'Yes',
6 | no: 'No',
7 | },
8 | login: {
9 | title: "Welcome to DPX Wallet",
10 | description: "To get started, you need to create a new wallet or import an existing wallet if you already have one.",
11 | buttons: {
12 | import: "Import Wallet",
13 | create: "Create Wallet"
14 | },
15 | toast: {
16 | wallet_created: 'Wallet created successfully'
17 | },
18 | },
19 | settings: {
20 | language: {
21 | title: 'Language',
22 | description: 'Set your prefered language',
23 | },
24 | copyright: 'Developed by Erfan Mola using TeleVue',
25 | },
26 | wallet: {
27 | title: {
28 | wallet: 'Wallet',
29 | import: 'Import Wallet',
30 | },
31 | fields: {
32 | wallet: 'Wallet Address',
33 | secret: 'Secret Phrase',
34 | },
35 | import_wallet: 'Import Wallet',
36 | save_wallet: 'Save Wallet',
37 | hint: 'In this section, you can enter your wallet information. Both wallet address and secret phrase are 32 characters long. You can scan them if you have QR codes.',
38 | revoke_secret: 'Revoke Secret Phrase',
39 | clear_session: 'Clear Wallet from this Device',
40 | scan_wallet: 'Scan Wallet QR Address',
41 | scan_secret: 'Scan Secret Phrase QR Value',
42 | toast: {
43 | wallet_saved: 'Wallet successfully saved',
44 | wallet_imported: 'Wallet successfully imported',
45 | secret_revoked: 'Secret phrase successfully revoked and saved',
46 | },
47 | prompt: {
48 | revoke_secret: {
49 | title: 'Revoke Secret Phrase',
50 | text: 'Do you want to revoke your wallet\'s secret phrase?',
51 | },
52 | clear_session: {
53 | title: 'Clear Wallet',
54 | text: 'Do you want to clear this wallet from your device?',
55 | },
56 | }
57 | },
58 | home: {
59 | balance: 'Balance',
60 | receive: 'Receive',
61 | send: 'Send',
62 | },
63 | badges: {
64 | leagues: 'Leagues',
65 | ranks: {
66 | tier_1: 'Bronze',
67 | tier_2: 'Silver',
68 | tier_3: 'Gold',
69 | tier_4: 'Platinum',
70 | tier_5: 'Diamond',
71 | tier_6: 'Mystery',
72 | tier_7: 'Champion',
73 | tier_8: 'Legend',
74 | }
75 | },
76 | receive: {
77 | set: 'Set',
78 | amount: 'Amount (Optional)',
79 | receive_amount: 'Receive Amount (DPX)',
80 | hint: 'You can copy and share your wallet address by clicking on the address. You can also share your wallet QRCode.',
81 | toast: {
82 | wallet_copied: 'Wallet address is copied to clipboard',
83 | }
84 | },
85 | transfer: {
86 | title: 'Transfer',
87 | fields: {
88 | departure: 'Departure Wallet',
89 | destination: 'Destination Wallet',
90 | amount: 'Amount',
91 | transfer_amount: 'Transfer Amount (DPX)'
92 | },
93 | request_transfer: 'Request Transfer',
94 | toast: {
95 | success: 'Transaction was successful'
96 | },
97 | prompt: {
98 | verify_transfer: {
99 | title: 'Verify Transfer',
100 | text: 'You are transfering {amount} DPX with {fee} DPX fee to {destination}. Do you want to proceed?',
101 | },
102 | }
103 | },
104 | api: {
105 | errors: {
106 | 'invalid-credentials': 'Provided credentials are invalid',
107 | 'invalid-departure': 'Departure wallet is invalid',
108 | 'invalid-destination': 'Destination wallet is invalid',
109 | 'invalid-secret-format': 'Secret phrase format is invalid',
110 | 'invalid-amount': 'Amount is invalid',
111 | 'same-departure-destination': 'Departure and Destination are same',
112 | 'locked-departure': 'Departure wallet is locked',
113 | 'locked-destination': 'Destination wallet is locked',
114 | 'invalid-wallet': 'Wallet is invalid',
115 | 'invalid-secret': 'Secret phrase is invalid',
116 | 'insufficient-balance': 'Balance is not sufficent',
117 | 'invalid-transaction': 'Transaction is invalid',
118 | }
119 | },
120 | transactions: {
121 | title: 'Transactions',
122 | transaction: 'Transaction',
123 | sent: 'Sent',
124 | received: 'Received',
125 | no_transactions: 'No transactions found'
126 | },
127 | transaction: {
128 | title: 'Transaction',
129 | info: 'Details',
130 | fields: {
131 | id: 'Id',
132 | departure: 'Departure',
133 | destination: 'Destination',
134 | amount: 'Amount',
135 | fee: 'Fee',
136 | date: 'Date',
137 | }
138 | },
139 | };
140 |
141 | export default i18n_en;
--------------------------------------------------------------------------------
/webApp/src/i18n/lang-fa.js:
--------------------------------------------------------------------------------
1 | const i18n_fa = {
2 | general: {
3 | title: 'کیف پول DPX',
4 | language: 'فارسی',
5 | yes: 'بله',
6 | no: 'خیر',
7 | },
8 | login: {
9 | title: 'به کیف پول DPX خوش آمدید',
10 | description: 'برای شروع لازم است که یک کیف پول جدید ایجاد کنید یا اگر از قبل کیف پول دارید، میتوانید آنرا وارد کنید',
11 | buttons: {
12 | import: 'وارد کردن کیف پول',
13 | create: 'ایجاد کیف پول',
14 | },
15 | toast: {
16 | wallet_created: 'کیف پول با موفقیت ایجاد شد'
17 | }
18 | },
19 | settings: {
20 | language: {
21 | title: 'زبان',
22 | description: 'زبان مورد نظر خود را تنظیم کنید',
23 | },
24 | copyright: 'توسعه یافته توسط عرفان مولا با استفاده از TeleVue',
25 | },
26 | wallet: {
27 | title: {
28 | wallet: 'کیف پول',
29 | import: 'وارد کردن کیف پول',
30 | },
31 | fields: {
32 | wallet: 'آدرس کیف پول',
33 | secret: 'عبارت محرمانه',
34 | },
35 | import_wallet: 'افزودن کیف پول',
36 | save_wallet: 'ذخیره کیف پول',
37 | hint: 'از این بخش میتوانید کیف پول خود را وارد کنید، کیف پول و عبارت محرمانه هر دو متشکل از 32 کاراکتر میباشند، میتوانید در صورت داشتن QRCode آنها را اسکن نمایید.',
38 | revoke_secret: 'بازنشانی عبارت محرمانه',
39 | clear_session: 'پاک کردن کیف پول از این دستگاه',
40 | scan_wallet: 'آدرس QR کیف پول را اسکن نمایید',
41 | scan_secret: 'مقدار QR عبارت محرمانه را اسکن نمایید',
42 | toast: {
43 | wallet_saved: 'کیف پول با موفقیت ذخیره شد',
44 | wallet_imported: 'کیف پول با موفقیت وارد شد',
45 | secret_revoked: 'عبارت محرمانه با موفقیت بازنشانی و ذخیره شد',
46 | },
47 | prompt: {
48 | revoke_secret: {
49 | title: 'بازنشانی عبارت محرمانه',
50 | text: 'آیا قصد دارید عبارت محرمانه کیف پولتان بازنشانی شود؟',
51 | },
52 | clear_session: {
53 | title: 'پاک کردن کیف پول',
54 | text: 'آیا قصد دارید این کیف پول را از دستگاه خود پاک کنید؟',
55 | },
56 | }
57 | },
58 | home: {
59 | balance: 'موجودی',
60 | receive: 'دریافت',
61 | send: 'ارسال',
62 | },
63 | badges: {
64 | leagues: 'لیگها',
65 | ranks: {
66 | tier_1: 'برنز',
67 | tier_2: 'نقرهای',
68 | tier_3: 'طلایی',
69 | tier_4: 'پلاتینیوم',
70 | tier_5: 'الماس',
71 | tier_6: 'مرموز',
72 | tier_7: 'قهرمان',
73 | tier_8: 'اسطوره',
74 | }
75 | },
76 | receive: {
77 | set: 'تنظیم',
78 | amount: 'مقدار (اختیاری)',
79 | receive_amount: 'مقدار دریافتی (DPX)',
80 | hint: 'شما میتوانید با کلیک روی آدرس، آن را کپی کرده و به اشتراک بگذارید. همچنین میتوانید کد QR کیف پول خود را به اشتراک بگذارید.',
81 | toast: {
82 | wallet_copied: 'آدرس کیف پول به کلیپبورد کپی شد',
83 | }
84 | },
85 | transfer: {
86 | title: 'انتقال',
87 | fields: {
88 | departure: 'کیف پول مبدا',
89 | destination: 'کیف پول مقصد',
90 | amount: 'مقدار',
91 | transfer_amount: 'مقدار انتقالی (DPX)'
92 | },
93 | request_transfer: 'درخواست انتقال',
94 | toast: {
95 | success: 'تراکنش با موفقیت انجام شد'
96 | },
97 | prompt: {
98 | verify_transfer: {
99 | title: 'تأیید انتقال',
100 | text: 'شما در حال انتقال {amount} DPX با کارمزد {fee} DPX به {destination} هستید. آیا میخواهید ادامه دهید؟',
101 | },
102 | }
103 | },
104 | api: {
105 | errors: {
106 | 'invalid-credentials': 'اطلاعات ورودی نامعتبر هستند',
107 | 'invalid-departure': 'کیف پول مبدا نامعتبر است',
108 | 'invalid-destination': 'کیف پول مقصد نامعتبر است',
109 | 'invalid-secret-format': 'فرمت عبارت محرمانه نامعتبر است',
110 | 'invalid-amount': 'مقدار نامعتبر است',
111 | 'same-departure-destination': 'کیف پول مبدا و مقصد یکسان هستند',
112 | 'locked-departure': 'کیف پول مبدا قفل شده است',
113 | 'locked-destination': 'کیف پول مقصد قفل شده است',
114 | 'invalid-wallet': 'کیف پول نامعتبر است',
115 | 'invalid-secret': 'عبارت محرمانه نامعتبر است',
116 | 'insufficient-balance': 'موجودی کافی نیست',
117 | 'invalid-transaction': 'تراکنش نامعتبر است',
118 | }
119 | },
120 | transactions: {
121 | title: 'تراکنشها',
122 | transaction: 'تراکنش',
123 | sent: 'ارسال شد',
124 | received: 'دریافت شد',
125 | no_transactions: 'تراکنشی یافت نشد'
126 | },
127 | transaction: {
128 | title: 'تراکنش',
129 | info: 'جزئیات',
130 | fields: {
131 | id: 'شناسه',
132 | departure: 'مبدأ',
133 | destination: 'مقصد',
134 | amount: 'مقدار',
135 | fee: 'کارمزد',
136 | date: 'تاریخ',
137 | }
138 | },
139 | };
140 |
141 | export default i18n_fa;
142 |
--------------------------------------------------------------------------------
/webApp/src/i18n/lang-tr.js:
--------------------------------------------------------------------------------
1 | const i18n_tr = {
2 | general: {
3 | title: 'DPX Cüzdan',
4 | language: 'Türkçe',
5 | yes: 'Evet',
6 | no: 'Hayır',
7 | },
8 | login: {
9 | title: "DPX Cüzdan'a Hoş Geldiniz",
10 | description: "Başlamak için yeni bir cüzdan oluşturmanız veya zaten bir cüzdanınız varsa bunu içe aktarmanız gerekmektedir.",
11 | buttons: {
12 | import: "Cüzdanı İçe Aktar",
13 | create: "Cüzdan Oluştur"
14 | },
15 | toast: {
16 | wallet_created: 'Cüzdan başarıyla oluşturuldu'
17 | }
18 | },
19 | settings: {
20 | language: {
21 | title: 'Dil',
22 | description: 'Tercih ettiğiniz dili ayarlayın',
23 | },
24 | copyright: 'TeleVue kullanılarak geliştirilmiştir, Erfan Mola tarafından',
25 | },
26 | wallet: {
27 | title: {
28 | wallet: 'Cüzdan',
29 | import: 'Cüzdanı İçe Aktar',
30 | },
31 | fields: {
32 | wallet: 'Cüzdan Adresi',
33 | secret: 'Gizli Cümle',
34 | },
35 | import_wallet: 'Cüzdanı İçe Aktar',
36 | save_wallet: 'Cüzdanı Kaydet',
37 | hint: 'Bu bölümde cüzdan bilgilerinizi girebilirsiniz. Hem cüzdan adresi hem de gizli cümle 32 karakterden oluşur. QR kodlarınız varsa tarayabilirsiniz.',
38 | revoke_secret: 'Gizli Cümleyi İptal Et',
39 | clear_session: 'Bu Cihazdan Cüzdanı Temizle',
40 | scan_wallet: 'Cüzdan QR Adresini Tarayın',
41 | scan_secret: 'Gizli Cümle QR Değerini Tarayın',
42 | toast: {
43 | wallet_saved: 'Cüzdan başarıyla kaydedildi',
44 | wallet_imported: 'Cüzdan başarıyla içe aktarıldı',
45 | secret_revoked: 'Gizli cümle başarıyla iptal edildi ve kaydedildi',
46 | },
47 | prompt: {
48 | revoke_secret: {
49 | title: 'Gizli Cümleyi İptal Et',
50 | text: 'Cüzdanınızın gizli cümlesini iptal etmek istiyor musunuz?',
51 | },
52 | clear_session: {
53 | title: 'Cüzdanı Temizle',
54 | text: 'Bu cüzdanı cihazınızdan temizlemek istiyor musunuz?',
55 | },
56 | }
57 | },
58 | home: {
59 | balance: 'Bakiye',
60 | receive: 'Al',
61 | send: 'Gönder',
62 | },
63 | badges: {
64 | leagues: 'Ligler',
65 | ranks: {
66 | tier_1: 'Bronz',
67 | tier_2: 'Gümüş',
68 | tier_3: 'Altın',
69 | tier_4: 'Platin',
70 | tier_5: 'Elmas',
71 | tier_6: 'Gizem',
72 | tier_7: 'Şampiyon',
73 | tier_8: 'Efsane',
74 | }
75 | },
76 | receive: {
77 | set: 'Ayarla',
78 | amount: 'Miktar (İsteğe Bağlı)',
79 | receive_amount: 'Alınan Miktar (DPX)',
80 | hint: 'Adrese tıklayarak cüzdan adresinizi kopyalayabilir ve paylaşabilirsiniz. Ayrıca cüzdan QR kodunuzu da paylaşabilirsiniz.',
81 | toast: {
82 | wallet_copied: 'Cüzdan adresi panoya kopyalandı',
83 | }
84 | },
85 | transfer: {
86 | title: 'Transfer',
87 | fields: {
88 | departure: 'Gönderen Cüzdan',
89 | destination: 'Alıcı Cüzdan',
90 | amount: 'Miktar',
91 | transfer_amount: 'Transfer Miktarı (DPX)'
92 | },
93 | request_transfer: 'Transfer Talebi',
94 | toast: {
95 | success: 'İşlem başarıyla gerçekleştirildi'
96 | },
97 | prompt: {
98 | verify_transfer: {
99 | title: 'Transferi Onayla',
100 | text: '{amount} DPX ve {fee} DPX ücret ile {destination} adresine transfer yapmak üzeresiniz. Devam etmek istiyor musunuz?',
101 | },
102 | }
103 | },
104 | api: {
105 | errors: {
106 | 'invalid-credentials': 'Sağlanan kimlik bilgileri geçersiz',
107 | 'invalid-departure': 'Gönderen cüzdan geçersiz',
108 | 'invalid-destination': 'Alıcı cüzdan geçersiz',
109 | 'invalid-secret-format': 'Gizli cümle formatı geçersiz',
110 | 'invalid-amount': 'Miktar geçersiz',
111 | 'same-departure-destination': 'Gönderen ve Alıcı aynı',
112 | 'locked-departure': 'Gönderen cüzdan kilitli',
113 | 'locked-destination': 'Alıcı cüzdan kilitli',
114 | 'invalid-wallet': 'Cüzdan geçersiz',
115 | 'invalid-secret': 'Gizli cümle geçersiz',
116 | 'insufficient-balance': 'Bakiye yetersiz',
117 | 'invalid-transaction': 'İşlem geçersiz',
118 | }
119 | },
120 | transactions: {
121 | title: 'İşlemler',
122 | transaction: 'İşlem',
123 | sent: 'Gönderildi',
124 | received: 'Alındı',
125 | no_transactions: 'Hiç işlem bulunamadı'
126 | },
127 | transaction: {
128 | title: 'İşlem',
129 | info: 'Detaylar',
130 | fields: {
131 | id: 'Kimlik',
132 | departure: 'Gönderen',
133 | destination: 'Alıcı',
134 | amount: 'Miktar',
135 | fee: 'Ücret',
136 | date: 'Tarih',
137 | }
138 | },
139 | };
140 |
141 | export default i18n_tr;
142 |
--------------------------------------------------------------------------------
/webApp/src/i18n/lang-de.js:
--------------------------------------------------------------------------------
1 | const i18n_de = {
2 | general: {
3 | title: 'DPX Brieftasche',
4 | language: 'Deutsch',
5 | yes: 'Ja',
6 | no: 'Nein',
7 | },
8 | login: {
9 | title: "Willkommen bei DPX Wallet",
10 | description: "Um loszulegen, müssen Sie eine neue Brieftasche erstellen oder eine vorhandene Brieftasche importieren, wenn Sie bereits eine haben.",
11 | buttons: {
12 | import: "Brieftasche importieren",
13 | create: "Brieftasche erstellen"
14 | },
15 | toast: {
16 | wallet_created: 'Brieftasche erfolgreich erstellt'
17 | }
18 | },
19 | settings: {
20 | language: {
21 | title: 'Sprache',
22 | description: 'Setzen Sie Ihre bevorzugte Sprache',
23 | },
24 | copyright: 'Entwickelt von Erfan Mola mit TeleVue',
25 | },
26 | wallet: {
27 | title: {
28 | wallet: 'Brieftasche',
29 | import: 'Brieftasche importieren',
30 | },
31 | fields: {
32 | wallet: 'Brieftaschenadresse',
33 | secret: 'Geheime Phrase',
34 | },
35 | import_wallet: 'Brieftasche importieren',
36 | save_wallet: 'Brieftasche speichern',
37 | hint: 'In diesem Abschnitt können Sie Ihre Brieftascheninformationen eingeben. Sowohl die Brieftaschenadresse als auch die geheime Phrase bestehen aus 32 Zeichen. Sie können sie scannen, wenn Sie QR-Codes haben.',
38 | revoke_secret: 'Geheime Phrase widerrufen',
39 | clear_session: 'Brieftasche von diesem Gerät löschen',
40 | scan_wallet: 'QR-Code der Brieftaschenadresse scannen',
41 | scan_secret: 'QR-Wert der geheimen Phrase scannen',
42 | toast: {
43 | wallet_saved: 'Brieftasche erfolgreich gespeichert',
44 | wallet_imported: 'Brieftasche erfolgreich importiert',
45 | secret_revoked: 'Geheime Phrase erfolgreich widerrufen und gespeichert',
46 | },
47 | prompt: {
48 | revoke_secret: {
49 | title: 'Geheime Phrase widerrufen',
50 | text: 'Möchten Sie die geheime Phrase Ihrer Brieftasche widerrufen?',
51 | },
52 | clear_session: {
53 | title: 'Brieftasche löschen',
54 | text: 'Möchten Sie diese Brieftasche von Ihrem Gerät löschen?',
55 | },
56 | }
57 | },
58 | home: {
59 | balance: 'Kontostand',
60 | receive: 'Empfangen',
61 | send: 'Senden',
62 | },
63 | badges: {
64 | leagues: 'Ligen',
65 | ranks: {
66 | tier_1: 'Bronze',
67 | tier_2: 'Silber',
68 | tier_3: 'Gold',
69 | tier_4: 'Platin',
70 | tier_5: 'Diamant',
71 | tier_6: 'Mysterium',
72 | tier_7: 'Champion',
73 | tier_8: 'Legende',
74 | }
75 | },
76 | receive: {
77 | set: 'Einstellen',
78 | amount: 'Betrag (Optional)',
79 | receive_amount: 'Erhaltener Betrag (DPX)',
80 | hint: 'Sie können Ihre Brieftaschenadresse kopieren und teilen, indem Sie auf die Adresse klicken. Sie können auch Ihren Brieftaschen-QR-Code teilen.',
81 | toast: {
82 | wallet_copied: 'Brieftaschenadresse wurde in die Zwischenablage kopiert',
83 | }
84 | },
85 | transfer: {
86 | title: 'Überweisung',
87 | fields: {
88 | departure: 'Abgangswallet',
89 | destination: 'Zielwallet',
90 | amount: 'Betrag',
91 | transfer_amount: 'Überweisungsbetrag (DPX)'
92 | },
93 | request_transfer: 'Überweisung anfordern',
94 | toast: {
95 | success: 'Die Transaktion war erfolgreich'
96 | },
97 | prompt: {
98 | verify_transfer: {
99 | title: 'Überweisung bestätigen',
100 | text: 'Sie überweisen {amount} DPX mit einer Gebühr von {fee} DPX an {destination}. Möchten Sie fortfahren?',
101 | },
102 | }
103 | },
104 | api: {
105 | errors: {
106 | 'invalid-credentials': 'Die bereitgestellten Anmeldedaten sind ungültig',
107 | 'invalid-departure': 'Abgangswallet ist ungültig',
108 | 'invalid-destination': 'Zielwallet ist ungültig',
109 | 'invalid-secret-format': 'Das Format des geheimen Satzes ist ungültig',
110 | 'invalid-amount': 'Betrag ist ungültig',
111 | 'same-departure-destination': 'Abgangs- und Zielwallet sind identisch',
112 | 'locked-departure': 'Abgangswallet ist gesperrt',
113 | 'locked-destination': 'Zielwallet ist gesperrt',
114 | 'invalid-wallet': 'Wallet ist ungültig',
115 | 'invalid-secret': 'Geheimer Satz ist ungültig',
116 | 'insufficient-balance': 'Guthaben ist nicht ausreichend',
117 | 'invalid-transaction': 'Transaktion ist ungültig',
118 | }
119 | },
120 | transactions: {
121 | title: 'Transaktionen',
122 | transaction: 'Transaktion',
123 | sent: 'Gesendet',
124 | received: 'Empfangen',
125 | no_transactions: 'Keine Transaktionen gefunden'
126 | },
127 | transaction: {
128 | title: 'Transaktion',
129 | info: 'Details',
130 | fields: {
131 | id: 'ID',
132 | departure: 'Absender',
133 | destination: 'Empfänger',
134 | amount: 'Betrag',
135 | fee: 'Gebühr',
136 | date: 'Datum',
137 | }
138 | },
139 | };
140 |
141 | export default i18n_de;
142 |
--------------------------------------------------------------------------------
/webApp/src/i18n/lang-fr.js:
--------------------------------------------------------------------------------
1 | const i18n_fr = {
2 | general: {
3 | title: 'Portefeuille DPX',
4 | language: 'Français',
5 | yes: 'Oui',
6 | no: 'Non',
7 | },
8 | login: {
9 | title: "Bienvenue sur DPX Wallet",
10 | description: "Pour commencer, vous devez créer un nouveau portefeuille ou importer un portefeuille existant si vous en avez déjà un.",
11 | buttons: {
12 | import: "Importer le portefeuille",
13 | create: "Créer un portefeuille"
14 | },
15 | toast: {
16 | wallet_created: 'Portefeuille créé avec succès'
17 | }
18 | },
19 | settings: {
20 | language: {
21 | title: 'Langue',
22 | description: 'Définissez votre langue préférée',
23 | },
24 | copyright: 'Développé par Erfan Mola en utilisant TeleVue',
25 | },
26 | wallet: {
27 | title: {
28 | wallet: 'Portefeuille',
29 | import: 'Importer le Portefeuille',
30 | },
31 | fields: {
32 | wallet: 'Adresse du Portefeuille',
33 | secret: 'Phrase Secrète',
34 | },
35 | import_wallet: 'Importer le Portefeuille',
36 | save_wallet: 'Enregistrer le Portefeuille',
37 | hint: 'Dans cette section, vous pouvez entrer les informations de votre portefeuille. L\'adresse du portefeuille et la phrase secrète sont toutes deux composées de 32 caractères. Vous pouvez les scanner si vous avez des codes QR.',
38 | revoke_secret: 'Révoquer la Phrase Secrète',
39 | clear_session: 'Effacer le Portefeuille de cet Appareil',
40 | scan_wallet: 'Scanner l\'Adresse QR du Portefeuille',
41 | scan_secret: 'Scanner la Valeur QR de la Phrase Secrète',
42 | toast: {
43 | wallet_saved: 'Portefeuille enregistré avec succès',
44 | wallet_imported: 'Portefeuille importé avec succès',
45 | secret_revoked: 'Phrase secrète révoquée avec succès et enregistrée',
46 | },
47 | prompt: {
48 | revoke_secret: {
49 | title: 'Révoquer la Phrase Secrète',
50 | text: 'Voulez-vous révoquer la phrase secrète de votre portefeuille?',
51 | },
52 | clear_session: {
53 | title: 'Effacer le Portefeuille',
54 | text: 'Voulez-vous effacer ce portefeuille de votre appareil?',
55 | },
56 | }
57 | },
58 | home: {
59 | balance: 'Solde',
60 | receive: 'Recevoir',
61 | send: 'Envoyer',
62 | },
63 | badges: {
64 | leagues: 'Ligues',
65 | ranks: {
66 | tier_1: 'Bronze',
67 | tier_2: 'Argent',
68 | tier_3: 'Or',
69 | tier_4: 'Platine',
70 | tier_5: 'Diamant',
71 | tier_6: 'Mystère',
72 | tier_7: 'Champion',
73 | tier_8: 'Légende',
74 | }
75 | },
76 | receive: {
77 | set: 'Définir',
78 | amount: 'Montant (Optionnel)',
79 | receive_amount: 'Montant Reçu (DPX)',
80 | hint: 'Vous pouvez copier et partager votre adresse de portefeuille en cliquant sur l\'adresse. Vous pouvez également partager votre QR Code de portefeuille.',
81 | toast: {
82 | wallet_copied: 'Adresse du portefeuille copiée dans le presse-papiers',
83 | }
84 | },
85 | transfer: {
86 | title: 'Transfert',
87 | fields: {
88 | departure: 'Portefeuille de Départ',
89 | destination: 'Portefeuille de Destination',
90 | amount: 'Montant',
91 | transfer_amount: 'Montant du Transfert (DPX)'
92 | },
93 | request_transfer: 'Demander le Transfert',
94 | toast: {
95 | success: 'La transaction a réussi'
96 | },
97 | prompt: {
98 | verify_transfer: {
99 | title: 'Vérifier le Transfert',
100 | text: 'Vous transférez {amount} DPX avec des frais de {fee} DPX vers {destination}. Voulez-vous continuer ?',
101 | },
102 | }
103 | },
104 | api: {
105 | errors: {
106 | 'invalid-credentials': 'Les identifiants fournis ne sont pas valides',
107 | 'invalid-departure': 'Le portefeuille de départ n\'est pas valide',
108 | 'invalid-destination': 'Le portefeuille de destination n\'est pas valide',
109 | 'invalid-secret-format': 'Le format de la phrase secrète n\'est pas valide',
110 | 'invalid-amount': 'Le montant n\'est pas valide',
111 | 'same-departure-destination': 'Le portefeuille de départ et de destination sont identiques',
112 | 'locked-departure': 'Le portefeuille de départ est verrouillé',
113 | 'locked-destination': 'Le portefeuille de destination est verrouillé',
114 | 'invalid-wallet': 'Le portefeuille n\'est pas valide',
115 | 'invalid-secret': 'La phrase secrète n\'est pas valide',
116 | 'insufficient-balance': 'Le solde n\'est pas suffisant',
117 | 'invalid-transaction': 'La transaction n\'est pas valide',
118 | }
119 | },
120 | transactions: {
121 | title: 'Transactions',
122 | transaction: 'Transaction',
123 | sent: 'Envoyé',
124 | received: 'Reçu',
125 | no_transactions: 'Aucune transaction trouvée'
126 | },
127 | transaction: {
128 | title: 'Transaction',
129 | info: 'Détails',
130 | fields: {
131 | id: 'ID',
132 | departure: 'Départ',
133 | destination: 'Destination',
134 | amount: 'Montant',
135 | fee: 'Frais',
136 | date: 'Date',
137 | }
138 | },
139 | };
140 |
141 | export default i18n_fr;
142 |
--------------------------------------------------------------------------------
/api/config/database.php:
--------------------------------------------------------------------------------
1 | env('DB_CONNECTION', 'mysql'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Database Connections
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here are each of the database connections setup for your application.
26 | | Of course, examples of configuring each database platform that is
27 | | supported by Laravel is shown below to make development simple.
28 | |
29 | |
30 | | All database work in Laravel is done through the PHP PDO facilities
31 | | so make sure you have the driver for your particular database of
32 | | choice installed on your machine before you begin development.
33 | |
34 | */
35 |
36 | 'connections' => [
37 |
38 | 'sqlite' => [
39 | 'driver' => 'sqlite',
40 | 'url' => env('DATABASE_URL'),
41 | 'database' => env('DB_DATABASE', database_path('database.sqlite')),
42 | 'prefix' => '',
43 | 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
44 | ],
45 |
46 | 'mysql' => [
47 | 'driver' => 'mysql',
48 | 'url' => env('DATABASE_URL'),
49 | 'host' => env('DB_HOST', '127.0.0.1'),
50 | 'port' => env('DB_PORT', '3306'),
51 | 'database' => env('DB_DATABASE', 'forge'),
52 | 'username' => env('DB_USERNAME', 'forge'),
53 | 'password' => env('DB_PASSWORD', ''),
54 | 'unix_socket' => env('DB_SOCKET', ''),
55 | 'charset' => 'utf8mb4',
56 | 'collation' => 'utf8mb4_unicode_ci',
57 | 'prefix' => '',
58 | 'prefix_indexes' => true,
59 | 'strict' => true,
60 | 'engine' => null,
61 | 'options' => extension_loaded('pdo_mysql') ? array_filter([
62 | PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
63 | ]) : [],
64 | ],
65 |
66 | 'pgsql' => [
67 | 'driver' => 'pgsql',
68 | 'url' => env('DATABASE_URL'),
69 | 'host' => env('DB_HOST', '127.0.0.1'),
70 | 'port' => env('DB_PORT', '5432'),
71 | 'database' => env('DB_DATABASE', 'forge'),
72 | 'username' => env('DB_USERNAME', 'forge'),
73 | 'password' => env('DB_PASSWORD', ''),
74 | 'charset' => 'utf8',
75 | 'prefix' => '',
76 | 'prefix_indexes' => true,
77 | 'search_path' => 'public',
78 | 'sslmode' => 'prefer',
79 | ],
80 |
81 | 'sqlsrv' => [
82 | 'driver' => 'sqlsrv',
83 | 'url' => env('DATABASE_URL'),
84 | 'host' => env('DB_HOST', 'localhost'),
85 | 'port' => env('DB_PORT', '1433'),
86 | 'database' => env('DB_DATABASE', 'forge'),
87 | 'username' => env('DB_USERNAME', 'forge'),
88 | 'password' => env('DB_PASSWORD', ''),
89 | 'charset' => 'utf8',
90 | 'prefix' => '',
91 | 'prefix_indexes' => true,
92 | // 'encrypt' => env('DB_ENCRYPT', 'yes'),
93 | // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
94 | ],
95 |
96 | ],
97 |
98 | /*
99 | |--------------------------------------------------------------------------
100 | | Migration Repository Table
101 | |--------------------------------------------------------------------------
102 | |
103 | | This table keeps track of all the migrations that have already run for
104 | | your application. Using this information, we can determine which of
105 | | the migrations on disk haven't actually been run in the database.
106 | |
107 | */
108 |
109 | 'migrations' => 'migrations',
110 |
111 | /*
112 | |--------------------------------------------------------------------------
113 | | Redis Databases
114 | |--------------------------------------------------------------------------
115 | |
116 | | Redis is an open source, fast, and advanced key-value store that also
117 | | provides a richer body of commands than a typical key-value system
118 | | such as APC or Memcached. Laravel makes it easy to dig right in.
119 | |
120 | */
121 |
122 | 'redis' => [
123 |
124 | 'client' => env('REDIS_CLIENT', 'phpredis'),
125 |
126 | 'options' => [
127 | 'cluster' => env('REDIS_CLUSTER', 'redis'),
128 | 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
129 | ],
130 |
131 | 'default' => [
132 | 'url' => env('REDIS_URL'),
133 | 'host' => env('REDIS_HOST', '127.0.0.1'),
134 | 'username' => env('REDIS_USERNAME'),
135 | 'password' => env('REDIS_PASSWORD'),
136 | 'port' => env('REDIS_PORT', '6379'),
137 | 'database' => env('REDIS_DB', '0'),
138 | ],
139 |
140 | 'cache' => [
141 | 'url' => env('REDIS_URL'),
142 | 'host' => env('REDIS_HOST', '127.0.0.1'),
143 | 'username' => env('REDIS_USERNAME'),
144 | 'password' => env('REDIS_PASSWORD'),
145 | 'port' => env('REDIS_PORT', '6379'),
146 | 'database' => env('REDIS_CACHE_DB', '1'),
147 | ],
148 |
149 | ],
150 |
151 | ];
152 |
--------------------------------------------------------------------------------
/webApp/src/views/Transactions.vue:
--------------------------------------------------------------------------------
1 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
69 |
70 |
{{ $t('transactions.no_transactions') }}
71 |
72 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/webApp/src/views/Login.vue:
--------------------------------------------------------------------------------
1 |
64 |
65 |
66 |
67 |
81 |
82 |
83 |
84 |
85 |
86 | {{ $t('login.title') }}
87 | {{ $t('login.description') }}
88 |
89 |
90 | - {{ $t('login.buttons.import') }}
91 | - {{ $t('login.buttons.create') }}
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/webApp/src/views/Transaction.vue:
--------------------------------------------------------------------------------
1 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | {{ $t('transaction.info') }}
74 |
75 |
76 | - {{ $t('transaction.fields.id') }}:{{ transaction.transaction }}
77 | - {{ $t('transaction.fields.departure') }}:{{ transaction.departure }}
78 | - {{ $t('transaction.fields.destination') }}:{{ transaction.destination }}
79 | - {{ $t('transaction.fields.amount') }}:{{ transaction.amount }}
80 | - {{ $t('transaction.fields.fee') }}:{{ transaction.fee }}
81 | - {{ $t('transaction.fields.date') }}:{{ new Date(transaction.timestamp * 1000).toLocaleTimeString() }} {{ new Date(transaction.timestamp * 1000).toLocaleDateString() }}
82 |
83 |
84 |
85 |
86 |
87 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/webApp/src/views/Badges.vue:
--------------------------------------------------------------------------------
1 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | -
48 |
49 |
{{ i18nLocale.t(`badges.ranks.tier_${ rank.rank }`) }}
50 | {{ rank.min }}
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/webApp/src/views/Transfer.vue:
--------------------------------------------------------------------------------
1 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
133 |
134 |
142 |
143 |
150 |
151 |
152 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/webApp/src/utils/index.js:
--------------------------------------------------------------------------------
1 | import Toastify from 'toastify-js';
2 | import WebApp from '@twa-dev/sdk';
3 |
4 | let Audios = {};
5 |
6 | const Utils = {
7 |
8 | // Wrapper for Toastify function
9 | Toast: (text, duration = 2000) => {
10 | Toastify({text: text, duration: duration, gravity: 'top', position: 'left', style: {background: 'var(--tg-theme-text-color)', color: 'var(--tg-theme-bg-color)'}}).showToast();
11 | },
12 |
13 | // Send request to DPX API & return reponse
14 | DPXSendRequest: async (endpoint = '/', data = [], method = 'POST', i18n = null) => {
15 |
16 | const FD = new FormData();
17 |
18 | for (const [key, value] of Object.entries(data)) {
19 |
20 | FD.append(key, value);
21 |
22 | }
23 |
24 | try {
25 |
26 | var endpoint_url = `${ import.meta.env.VITE_APP_URL.toString().replace(/\/+$/, '') }/api`;
27 |
28 | let data = { 'method': method };
29 |
30 | if (method === 'POST') {
31 |
32 | data['body'] = FD;
33 |
34 | }
35 |
36 | var request = await fetch(`${ endpoint_url }${ endpoint }`, data);
37 |
38 | var result = await request.json();
39 |
40 | } catch(Exception) {
41 |
42 | result = { status: 'error' };
43 |
44 | }
45 |
46 | if (result.status !== 'success') {
47 |
48 | if ('info' in result) {
49 |
50 | if (i18n) {
51 |
52 | Utils.Toast(i18n.t(`api.errors.${ result.error }`));
53 |
54 | }else{
55 |
56 | Utils.Toast(result.info);
57 |
58 | }
59 |
60 |
61 | }else{
62 |
63 | Utils.Toast("Error");
64 |
65 | }
66 |
67 | return null;
68 |
69 | }else{
70 |
71 | return result;
72 |
73 | }
74 |
75 | },
76 |
77 | // Preload audio file
78 | PreLoadAudio: (name) => {
79 |
80 | if (Audios[name] === undefined) {
81 |
82 | Audios[name] = new Audio(`${import.meta.env.BASE_URL}assets/sounds/${ name }`);
83 |
84 | }
85 |
86 | },
87 |
88 | // Play an audio file
89 | PlayAudio: (name) => {
90 |
91 | Audios[name].play();
92 |
93 | },
94 |
95 | // a prefered way of showing Telegram WebApp prompts and handling it's callback
96 | Prompt: (title = null, text, options) => {
97 |
98 | if (WebApp.isVersionAtLeast('6.2')) {
99 |
100 | WebApp.HapticFeedback.notificationOccurred('warning');
101 |
102 | let buttons = [];
103 |
104 | options.forEach((option, key) => {
105 |
106 | let id = Math.random().toString(36).slice(2, 7);
107 | options[key]['id'] = id;
108 |
109 | buttons.push({
110 | id: id,
111 | type: option.type,
112 | text: option.text
113 | });
114 |
115 | });
116 |
117 | WebApp.showPopup({
118 | title: title,
119 | message: text,
120 | buttons: buttons
121 | });
122 |
123 | let OnPopupClosedHanlder = (data) => {
124 |
125 | options.forEach((option) => {
126 |
127 | if (option.id === data['button_id']) {
128 |
129 | option.event();
130 |
131 | }
132 |
133 | });
134 |
135 | WebApp.offEvent('popupClosed', OnPopupClosedHanlder);
136 |
137 | };
138 |
139 | WebApp.onEvent('popupClosed', OnPopupClosedHanlder);
140 |
141 | }else{
142 |
143 | Utils.Toast('Unsupported');
144 |
145 | }
146 |
147 | },
148 |
149 | // Scan QRCode if supported
150 | ScanQRCode: (text, onReceive) => {
151 |
152 | if (WebApp.isVersionAtLeast('6.4')) {
153 |
154 | WebApp.HapticFeedback.notificationOccurred('warning');
155 |
156 | WebApp.showScanQrPopup({
157 | text: text,
158 | });
159 |
160 | let OnQRTextReceivedHanlder = (data) => {
161 |
162 | if (onReceive(data)) {
163 |
164 | WebApp.offEvent('qrTextReceived', OnQRTextReceivedHanlder);
165 | WebApp.closeScanQrPopup();
166 |
167 | }
168 |
169 | };
170 |
171 | WebApp.onEvent('qrTextReceived', OnQRTextReceivedHanlder);
172 |
173 | }else{
174 |
175 | Utils.Toast('Unsupported');
176 |
177 | }
178 |
179 | },
180 |
181 | // Hide keyboard when user clicks enter
182 | hideKeyboardOnEnter: (event) => { if (event.keyCode === 13) { event.target.blur(); } },
183 |
184 | // Copy text to clipboard
185 | copyTextToClipboard: (text) => {
186 |
187 | if (!navigator.clipboard) {
188 |
189 | var textArea = document.createElement("textarea");
190 | textArea.value = text;
191 |
192 | textArea.style.top = "0";
193 | textArea.style.left = "0";
194 | textArea.style.position = "fixed";
195 |
196 | document.body.appendChild(textArea);
197 | textArea.focus();
198 | textArea.select();
199 |
200 | try {
201 | var successful = document.execCommand('copy');
202 | var msg = successful ? 'successful' : 'unsuccessful';
203 | } catch (err) {
204 |
205 | }
206 |
207 | document.body.removeChild(textArea);
208 |
209 | return;
210 |
211 | }
212 |
213 | navigator.clipboard.writeText(text);
214 |
215 | },
216 |
217 | // Get wallet/secret from LocalStorage
218 | GetWallet(param = null) {
219 |
220 | let info = window.localStorage.getItem(`wallet_user_${ WebApp.initDataUnsafe.user.id }`);
221 |
222 | if (info) {
223 |
224 | if (param) {
225 |
226 | return JSON.parse(info)[param];
227 |
228 | }else{
229 |
230 | return JSON.parse(info);
231 |
232 | }
233 |
234 | }else{
235 |
236 | return null;
237 |
238 | }
239 |
240 | },
241 |
242 | // Set wallet/secret to LocalStorage
243 | SetWallet(wallet = null, secret = null) {
244 |
245 | if (wallet === null) {
246 |
247 | wallet = Utils.GetWallet('wallet');
248 |
249 | }else if (secret === null) {
250 |
251 | secret = Utils.GetWallet('secret');
252 |
253 | }
254 |
255 | window.localStorage.setItem(`wallet_user_${ WebApp.initDataUnsafe.user.id }`, JSON.stringify({
256 | wallet: wallet,
257 | secret: secret,
258 | }))
259 |
260 | },
261 |
262 | // a hacky trick to fix mispositioning of UI elements when keyboard opens
263 | HandleInputFocus: () => {
264 |
265 | window.scrollTo(0, 0);
266 | document.body.scrollTop = 0;
267 |
268 | }
269 |
270 | };
271 |
272 | export default Utils;
--------------------------------------------------------------------------------
/api/config/app.php:
--------------------------------------------------------------------------------
1 | env('APP_NAME', 'Laravel'),
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | Application Environment
24 | |--------------------------------------------------------------------------
25 | |
26 | | This value determines the "environment" your application is currently
27 | | running in. This may determine how you prefer to configure various
28 | | services the application utilizes. Set this in your ".env" file.
29 | |
30 | */
31 |
32 | 'env' => env('APP_ENV', 'production'),
33 |
34 | /*
35 | |--------------------------------------------------------------------------
36 | | Application Debug Mode
37 | |--------------------------------------------------------------------------
38 | |
39 | | When your application is in debug mode, detailed error messages with
40 | | stack traces will be shown on every error that occurs within your
41 | | application. If disabled, a simple generic error page is shown.
42 | |
43 | */
44 |
45 | 'debug' => (bool) env('APP_DEBUG', false),
46 |
47 | /*
48 | |--------------------------------------------------------------------------
49 | | Application URL
50 | |--------------------------------------------------------------------------
51 | |
52 | | This URL is used by the console to properly generate URLs when using
53 | | the Artisan command line tool. You should set this to the root of
54 | | your application so that it is used when running Artisan tasks.
55 | |
56 | */
57 |
58 | 'url' => env('APP_URL', 'http://localhost'),
59 |
60 | 'asset_url' => env('ASSET_URL'),
61 |
62 | /*
63 | |--------------------------------------------------------------------------
64 | | Application Timezone
65 | |--------------------------------------------------------------------------
66 | |
67 | | Here you may specify the default timezone for your application, which
68 | | will be used by the PHP date and date-time functions. We have gone
69 | | ahead and set this to a sensible default for you out of the box.
70 | |
71 | */
72 |
73 | 'timezone' => 'UTC',
74 |
75 | /*
76 | |--------------------------------------------------------------------------
77 | | Application Locale Configuration
78 | |--------------------------------------------------------------------------
79 | |
80 | | The application locale determines the default locale that will be used
81 | | by the translation service provider. You are free to set this value
82 | | to any of the locales which will be supported by the application.
83 | |
84 | */
85 |
86 | 'locale' => 'en',
87 |
88 | /*
89 | |--------------------------------------------------------------------------
90 | | Application Fallback Locale
91 | |--------------------------------------------------------------------------
92 | |
93 | | The fallback locale determines the locale to use when the current one
94 | | is not available. You may change the value to correspond to any of
95 | | the language folders that are provided through your application.
96 | |
97 | */
98 |
99 | 'fallback_locale' => 'en',
100 |
101 | /*
102 | |--------------------------------------------------------------------------
103 | | Faker Locale
104 | |--------------------------------------------------------------------------
105 | |
106 | | This locale will be used by the Faker PHP library when generating fake
107 | | data for your database seeds. For example, this will be used to get
108 | | localized telephone numbers, street address information and more.
109 | |
110 | */
111 |
112 | 'faker_locale' => 'en_US',
113 |
114 | /*
115 | |--------------------------------------------------------------------------
116 | | Encryption Key
117 | |--------------------------------------------------------------------------
118 | |
119 | | This key is used by the Illuminate encrypter service and should be set
120 | | to a random, 32 character string, otherwise these encrypted strings
121 | | will not be safe. Please do this before deploying an application!
122 | |
123 | */
124 |
125 | 'key' => env('APP_KEY'),
126 |
127 | 'cipher' => 'AES-256-CBC',
128 |
129 | /*
130 | |--------------------------------------------------------------------------
131 | | Maintenance Mode Driver
132 | |--------------------------------------------------------------------------
133 | |
134 | | These configuration options determine the driver used to determine and
135 | | manage Laravel's "maintenance mode" status. The "cache" driver will
136 | | allow maintenance mode to be controlled across multiple machines.
137 | |
138 | | Supported drivers: "file", "cache"
139 | |
140 | */
141 |
142 | 'maintenance' => [
143 | 'driver' => 'file',
144 | // 'store' => 'redis',
145 | ],
146 |
147 | /*
148 | |--------------------------------------------------------------------------
149 | | Autoloaded Service Providers
150 | |--------------------------------------------------------------------------
151 | |
152 | | The service providers listed here will be automatically loaded on the
153 | | request to your application. Feel free to add your own services to
154 | | this array to grant expanded functionality to your applications.
155 | |
156 | */
157 |
158 | 'providers' => ServiceProvider::defaultProviders()->merge([
159 | /*
160 | * Package Service Providers...
161 | */
162 |
163 | /*
164 | * Application Service Providers...
165 | */
166 | App\Providers\AppServiceProvider::class,
167 | App\Providers\AuthServiceProvider::class,
168 | // App\Providers\BroadcastServiceProvider::class,
169 | App\Providers\EventServiceProvider::class,
170 | App\Providers\RouteServiceProvider::class,
171 | ])->toArray(),
172 |
173 | /*
174 | |--------------------------------------------------------------------------
175 | | Class Aliases
176 | |--------------------------------------------------------------------------
177 | |
178 | | This array of class aliases will be registered when this application
179 | | is started. However, feel free to register as many as you wish as
180 | | the aliases are "lazy" loaded so they don't hinder performance.
181 | |
182 | */
183 |
184 | 'aliases' => Facade::defaultAliases()->merge([
185 | // 'Example' => App\Facades\Example::class,
186 | ])->toArray(),
187 |
188 | ];
189 |
--------------------------------------------------------------------------------
/webApp/src/views/Receive.vue:
--------------------------------------------------------------------------------
1 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
{{ wallet }}
107 |
108 |
109 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | {{ $t('receive.hint') }}
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------