├── .dockerignore ├── .env.example ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── bug_report_mobile.md │ ├── bug_report_web.md │ └── new-feature.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── ci.yaml │ ├── dmw_test.yaml │ └── e2e.yaml ├── .gitignore ├── .gitmodules ├── .pyre_configuration ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── backend ├── .env.example ├── Dockerfile ├── MANIFEST.in ├── Pipfile ├── Pipfile.lock ├── README.md ├── context │ ├── __init__.py │ ├── config.py │ ├── context.py │ └── stubs │ │ ├── __init__.py │ │ └── custody.py ├── diem_utils │ ├── __init__.py │ ├── _version.py │ ├── custody.py │ ├── precise_amount.py │ ├── sdks │ │ ├── __init__.py │ │ └── liquidity.py │ ├── types │ │ ├── __init__.py │ │ ├── currencies.py │ │ └── liquidity │ │ │ ├── __init__.py │ │ │ ├── currency.py │ │ │ ├── errors.py │ │ │ ├── lp.py │ │ │ ├── quote.py │ │ │ ├── settlement.py │ │ │ └── trade.py │ └── vasp.py ├── offchain │ ├── __init__.py │ ├── action.py │ ├── client.py │ ├── command.py │ ├── error.py │ ├── funds_pull_pre_approval_command.py │ ├── funds_pull_pre_approval_command_state.py │ ├── http_header.py │ ├── http_server.py │ ├── jws.py │ ├── payment_command.py │ ├── payment_state.py │ ├── state.py │ └── types │ │ ├── __init__.py │ │ ├── cid.py │ │ ├── command_types.py │ │ ├── fund_pull_pre_approval_types.py │ │ ├── p2m_payment_types.py │ │ └── p2p_payment_types.py ├── pubsub │ ├── __init__.py │ ├── __main__.py │ ├── client.py │ └── types.py ├── run_pubsub.sh ├── run_web.sh ├── run_worker.sh ├── setup.py ├── test.sh ├── tests │ ├── README.md │ ├── __init__.py │ ├── conftest.py │ ├── context_tests │ │ ├── test_config.py │ │ ├── test_context.py │ │ └── test_custody.py │ ├── e2e_tests │ │ ├── __init__.py │ │ ├── double │ │ │ ├── __init__.py │ │ │ ├── test_p2m_payments.py │ │ │ └── test_p2p_payments.py │ │ └── single │ │ │ ├── __init__.py │ │ │ └── test_init.py │ ├── mw_drw_proxy │ │ ├── README.md │ │ ├── __init__.py │ │ ├── helpers.py │ │ └── proxy.py │ ├── offchain_tests │ │ ├── test_deserialize.py │ │ └── test_offchain_state.py │ ├── pubsub_tests │ │ ├── __init__.py │ │ └── test_client.py │ ├── setup.py │ ├── wallet_tests │ │ ├── __init__.py │ │ ├── client_sdk_mocks.py │ │ ├── conftest.py │ │ ├── liquidity │ │ │ ├── __init__.py │ │ │ ├── client │ │ │ │ ├── __init__.py │ │ │ │ └── test_client.py │ │ │ ├── test_amount.py │ │ │ └── test_utils.py │ │ ├── resources │ │ │ ├── __init__.py │ │ │ └── seeds │ │ │ │ ├── __init__.py │ │ │ │ ├── add_funds_seeder.py │ │ │ │ ├── balances_seeder.py │ │ │ │ ├── convert_seeder.py │ │ │ │ ├── one_approved_user.py │ │ │ │ ├── one_funds_pull_pre_approval.py │ │ │ │ ├── one_p2m_payment_seeder.py │ │ │ │ ├── one_p2p_payment_seeder.py │ │ │ │ ├── one_user_multiple_transactions.py │ │ │ │ ├── one_user_seeder.py │ │ │ │ ├── one_user_with_one_order.py │ │ │ │ ├── prototypes.py │ │ │ │ └── withdraw_funds_seeder.py │ │ ├── services │ │ │ ├── __init__.py │ │ │ ├── fx │ │ │ │ ├── __init__.py │ │ │ │ └── test_fx.py │ │ │ ├── offchain │ │ │ │ ├── test_fppa_process_inbound_request.py │ │ │ │ ├── test_fund_pull_pre_approval.py │ │ │ │ ├── test_offchain.py │ │ │ │ ├── test_p2m_payment.py │ │ │ │ ├── test_p2m_payment_as_receiver.py │ │ │ │ └── test_p2p_payment.py │ │ │ ├── system │ │ │ │ ├── test_add_incoming_transaction_from_blockchain.py │ │ │ │ ├── test_add_outgoing_transaction_from_blockchain.py │ │ │ │ ├── test_calculate_lrw_balance.py │ │ │ │ ├── test_remove_incoming_transaction_from_db.py │ │ │ │ ├── test_remove_outgoing_transaction_from_db.py │ │ │ │ ├── test_subaddreses_from_metadata.py │ │ │ │ ├── test_sync_multiple_transactions.py │ │ │ │ ├── test_sync_transaction_method.py │ │ │ │ ├── test_sync_until_specific_version.py │ │ │ │ ├── test_sync_when_no_data_in_blockchain.py │ │ │ │ ├── test_sync_with_empty_db.py │ │ │ │ └── utils.py │ │ │ ├── test_account.py │ │ │ ├── test_order.py │ │ │ ├── test_transaction.py │ │ │ ├── test_user.py │ │ │ └── test_validation_tool.py │ │ ├── storage │ │ │ ├── __init__.py │ │ │ ├── test_fund_pull_pre_approval.py │ │ │ ├── test_order.py │ │ │ ├── test_transaction.py │ │ │ └── test_user.py │ │ ├── test_risk.py │ │ └── test_security.py │ └── webapp_tests │ │ ├── __init__.py │ │ ├── conftest.py │ │ └── routes │ │ ├── test_account.py │ │ ├── test_admin.py │ │ ├── test_cico.py │ │ ├── test_fund_pull_pre_approval.py │ │ ├── test_p2m_payment.py │ │ ├── test_p2p_payment.py │ │ ├── test_rates.py │ │ ├── test_user.py │ │ └── test_validation_tool.py ├── wallet │ ├── __init__.py │ ├── background_tasks │ │ ├── __init__.py │ │ ├── background.py │ │ └── utils.py │ ├── config.py │ ├── logging.py │ ├── security.py │ ├── services │ │ ├── __init__.py │ │ ├── account.py │ │ ├── fx │ │ │ ├── __init__.py │ │ │ └── fx.py │ │ ├── inventory.py │ │ ├── kyc.py │ │ ├── log.py │ │ ├── offchain │ │ │ ├── __init__.py │ │ │ ├── fund_pull_pre_approval.py │ │ │ ├── fund_pull_pre_approval_sm.py │ │ │ ├── offchain.py │ │ │ ├── p2m_payment.py │ │ │ ├── p2m_payment_as_receiver.py │ │ │ ├── p2p_payment.py │ │ │ ├── p2p_payment_as_receiver.py │ │ │ └── utils.py │ │ ├── order.py │ │ ├── risk.py │ │ ├── system.py │ │ ├── transaction.py │ │ ├── user.py │ │ └── validation_tool.py │ ├── storage │ │ ├── __init__.py │ │ ├── account.py │ │ ├── funds_pull_pre_approval_command.py │ │ ├── logs.py │ │ ├── models.py │ │ ├── order.py │ │ ├── p2m_payment.py │ │ ├── p2p_payment.py │ │ ├── setup.py │ │ ├── token.py │ │ ├── transaction.py │ │ └── user.py │ └── types.py └── webapp │ ├── __init__.py │ ├── debug.py │ ├── errors.py │ ├── openapi.yaml │ ├── routes │ ├── __init__.py │ ├── account.py │ ├── admin.py │ ├── cico.py │ ├── offchain │ │ ├── funds_pull_pre_approval.py │ │ ├── main_offchain.py │ │ ├── p2m_payment.py │ │ └── p2p_payment.py │ ├── strict_schema_view.py │ ├── system.py │ ├── user.py │ └── validation_tool.py │ ├── schemas.py │ ├── static │ └── favicon.ico │ ├── swagger.py │ └── templates │ └── execution_logs.html ├── docker ├── debug.docker-compose.yaml ├── dev.docker-compose.yaml ├── docker-compose.yaml ├── e2e.docker-compose.yaml ├── pg │ ├── Dockerfile │ └── init.d │ │ └── backend.sh └── static.docker-compose.yaml ├── format.sh ├── frontend ├── .dockerignore ├── .env.example ├── .gitignore ├── Dockerfile ├── README.md ├── package.json ├── public │ ├── favicon.png │ ├── index.html │ └── robots.txt ├── src │ ├── App.tsx │ ├── assets │ │ ├── fonts │ │ │ └── freesans │ │ │ │ ├── FreeSans.woff │ │ │ │ ├── FreeSansBold.woff │ │ │ │ ├── FreeSansBoldOblique.woff │ │ │ │ ├── FreeSansOblique.woff │ │ │ │ └── style.css │ │ ├── img │ │ │ ├── close.svg │ │ │ ├── currency-circle-libra-eur.svg │ │ │ ├── currency-circle-libra-gbp.svg │ │ │ ├── currency-circle-libra-usd.svg │ │ │ ├── currency-circle-libra.svg │ │ │ ├── gears.svg │ │ │ ├── logo.svg │ │ │ └── qr.svg │ │ └── scss │ │ │ ├── _credit-cards.scss │ │ │ ├── _variables.scss │ │ │ └── main.scss │ ├── components │ │ ├── Actions.tsx │ │ ├── Balance.tsx │ │ ├── BalancesList.tsx │ │ ├── Breadcrumbs.tsx │ │ ├── CloseButton.tsx │ │ ├── ConfirmationModal.tsx │ │ ├── ExampleSectionWarning.tsx │ │ ├── ExplorerLink.tsx │ │ ├── Feedback.tsx │ │ ├── FundsPullPreApproval │ │ │ ├── ApprovalDetails.tsx │ │ │ ├── ApproveModal.tsx │ │ │ ├── FundsPullPreApproval.tsx │ │ │ ├── FundsPullPreApprovalsList.tsx │ │ │ ├── RejectModal.tsx │ │ │ └── RevokeModal.tsx │ │ ├── Header.tsx │ │ ├── LegalDisclaimer.tsx │ │ ├── Messages │ │ │ ├── ErrorMessage.tsx │ │ │ ├── InfoMessage.tsx │ │ │ └── SuccessMessage.tsx │ │ ├── PaymentConfirmation.tsx │ │ ├── PaymentConfirmationModal.tsx │ │ ├── ReceiveModal.tsx │ │ ├── Send │ │ │ ├── SendForm.tsx │ │ │ ├── SendModal.tsx │ │ │ ├── SendReview.tsx │ │ │ └── interfaces.ts │ │ ├── Settings │ │ │ ├── BackAccountForm.tsx │ │ │ ├── CreditCardForm.tsx │ │ │ ├── PaymentMethodsForm.tsx │ │ │ └── PreferencesForm.tsx │ │ ├── SettlementDetails.tsx │ │ ├── SignedUpMessage.tsx │ │ ├── TestnetWarning.tsx │ │ ├── TotalBalance.tsx │ │ ├── TransactionModal.tsx │ │ ├── TransactionsList.tsx │ │ ├── Transfer │ │ │ ├── Convert.tsx │ │ │ ├── ConvertForm.tsx │ │ │ ├── ConvertReview.tsx │ │ │ ├── Deposit.tsx │ │ │ ├── DepositForm.tsx │ │ │ ├── DepositReview.tsx │ │ │ ├── Withdraw.tsx │ │ │ ├── WithdrawForm.tsx │ │ │ ├── WithdrawReview.tsx │ │ │ └── interfaces.ts │ │ ├── TransferModal.tsx │ │ ├── UsersList.tsx │ │ ├── VerifyLoader.tsx │ │ ├── VerifyingMessage.tsx │ │ ├── WalletLoader.tsx │ │ ├── admin │ │ │ └── NewAdmin.tsx │ │ ├── datetime-picker │ │ │ └── index.tsx │ │ └── select │ │ │ └── index.tsx │ ├── contexts │ │ ├── app.ts │ │ └── appInitialState.ts │ ├── i18n.ts │ ├── index.tsx │ ├── interfaces │ │ ├── account.ts │ │ ├── approval.ts │ │ ├── blockchain.ts │ │ ├── cico.ts │ │ ├── currencies.ts │ │ ├── payment_details.ts │ │ ├── settings.ts │ │ ├── settlement.ts │ │ ├── system.ts │ │ ├── transaction.ts │ │ └── user.ts │ ├── locales │ │ ├── en │ │ │ ├── admin.json │ │ │ ├── auth.json │ │ │ ├── funds_pull_pre_approval.json │ │ │ ├── index.ts │ │ │ ├── layout.json │ │ │ ├── legal.json │ │ │ ├── payment.json │ │ │ ├── receive.json │ │ │ ├── send.json │ │ │ ├── settings.json │ │ │ ├── transaction.json │ │ │ ├── transfer.json │ │ │ ├── validations.json │ │ │ └── verify.json │ │ ├── es │ │ │ ├── admin.json │ │ │ ├── auth.json │ │ │ ├── funds_pull_pre_approval.json │ │ │ ├── index.ts │ │ │ ├── layout.json │ │ │ ├── payment.json │ │ │ ├── receive.json │ │ │ ├── send.json │ │ │ ├── settings.json │ │ │ ├── transaction.json │ │ │ ├── transfer.json │ │ │ ├── validations.json │ │ │ └── verify.json │ │ └── index.ts │ ├── pages │ │ ├── Account.tsx │ │ ├── ForgotPassword.tsx │ │ ├── FundsPullPreApprovals.tsx │ │ ├── Home.tsx │ │ ├── ResetPassword.tsx │ │ ├── Settings.tsx │ │ ├── Signin.tsx │ │ ├── Signup.tsx │ │ ├── Transactions.tsx │ │ ├── Verify.tsx │ │ ├── VerifySteps │ │ │ ├── Step1Identity.tsx │ │ │ ├── Step2Country.tsx │ │ │ ├── Step3Address.tsx │ │ │ ├── Step4Document.tsx │ │ │ ├── Step5DefaultCurrency.tsx │ │ │ └── interfaces.ts │ │ └── admin │ │ │ ├── Admins.tsx │ │ │ ├── Home.tsx │ │ │ ├── Liquidity.tsx │ │ │ └── Users.tsx │ ├── react-app-env.d.ts │ ├── services │ │ ├── backendClient.test.ts │ │ ├── backendClient.ts │ │ ├── errors.ts │ │ └── sessionStorage.ts │ ├── tests │ │ └── stubs.ts │ └── utils │ │ ├── amount-precision.ts │ │ ├── amountPrecision.test.ts │ │ ├── auth-routes.tsx │ │ ├── class-names.ts │ │ ├── dropdown-options.ts │ │ ├── payment-params.ts │ │ └── paymentParams.test.ts ├── tsconfig.json └── yarn.lock ├── gateway ├── Dockerfile ├── nginx.conf ├── nginx.debug.conf ├── nginx.dev.conf └── nginx.static.conf ├── helm └── reference-wallet │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── backend-deployment.yaml │ ├── backend-service.yaml │ ├── frontend-deployment.yaml │ ├── frontend-service.yaml │ ├── ingress.yaml │ ├── peripherals-deployment.yaml │ ├── peripherals-service.yaml │ ├── serviceaccount.yaml │ └── volumes.yaml │ └── values.yaml ├── mobile ├── .buckconfig ├── .dockerignore ├── .env.example ├── .eslintrc.js ├── .gitattributes ├── .gitignore ├── .prettierrc.js ├── .watchmanconfig ├── README.md ├── __tests__ │ └── App-test.tsx ├── android │ ├── Dockerfile │ ├── Gemfile │ ├── Gemfile.lock │ ├── app │ │ ├── _BUCK │ │ ├── build.gradle │ │ ├── build_defs.bzl │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── lrw │ │ │ │ └── ReactNativeFlipper.java │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── assets │ │ │ └── fonts │ │ │ │ ├── AntDesign.ttf │ │ │ │ ├── Entypo.ttf │ │ │ │ ├── EvilIcons.ttf │ │ │ │ ├── Feather.ttf │ │ │ │ ├── FontAwesome.ttf │ │ │ │ ├── FontAwesome5_Brands.ttf │ │ │ │ ├── FontAwesome5_Regular.ttf │ │ │ │ ├── FontAwesome5_Solid.ttf │ │ │ │ ├── Fontisto.ttf │ │ │ │ ├── Foundation.ttf │ │ │ │ ├── FreeSans-Bold.ttf │ │ │ │ ├── FreeSans-Regular.ttf │ │ │ │ ├── Ionicons.ttf │ │ │ │ ├── MaterialCommunityIcons.ttf │ │ │ │ ├── MaterialIcons.ttf │ │ │ │ ├── Octicons.ttf │ │ │ │ ├── SimpleLineIcons.ttf │ │ │ │ └── Zocial.ttf │ │ │ ├── java │ │ │ └── com │ │ │ │ └── lrw │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── fastlane │ │ ├── Appfile │ │ ├── Fastfile │ │ └── README.md │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── publish.sh │ └── settings.gradle ├── app.json ├── babel.config.js ├── index.js ├── ios │ ├── Gemfile │ ├── LRW.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── LRW-tvOS.xcscheme │ │ │ └── LRW.xcscheme │ ├── LRW.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── LRW │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Base.lproj │ │ │ └── LaunchScreen.xib │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── 1024.png │ │ │ │ ├── 120-1.png │ │ │ │ ├── 120.png │ │ │ │ ├── 180.png │ │ │ │ ├── 40.png │ │ │ │ ├── 58.png │ │ │ │ ├── 60.png │ │ │ │ ├── 80.png │ │ │ │ ├── 87.png │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── icons │ │ │ ├── 1024.png │ │ │ ├── 120.png │ │ │ ├── 180.png │ │ │ ├── 40.png │ │ │ ├── 58.png │ │ │ ├── 60.png │ │ │ ├── 80.png │ │ │ └── 87.png │ │ └── main.m │ ├── Podfile │ ├── Podfile.lock │ ├── fastlane │ │ ├── Appfile │ │ ├── Fastfile │ │ ├── Matchfile │ │ └── README.md │ └── publish.sh ├── metro.config.js ├── package.json ├── react-native.config.js ├── src │ ├── assets │ │ ├── back-arrow.svg │ │ ├── chevron.svg │ │ ├── fonts │ │ │ └── freesans │ │ │ │ ├── FreeSans-Bold.ttf │ │ │ │ └── FreeSans-Regular.ttf │ │ ├── gears.svg │ │ ├── logo.png │ │ ├── logo.svg │ │ └── scan-qr.svg │ ├── components │ │ ├── AppHeader.tsx │ │ ├── BalancesList.tsx │ │ ├── CurrencyBalance.tsx │ │ ├── DatePicker.tsx │ │ ├── ExampleSectionWarning.tsx │ │ ├── ExplorerLink.tsx │ │ ├── InputErrorMessage.tsx │ │ ├── LegalDisclaimer.tsx │ │ ├── Messages │ │ │ ├── ErrorMessage.tsx │ │ │ └── InfoMessage.tsx │ │ ├── NetworkIndicator.tsx │ │ ├── PaymentMethodsForm.tsx │ │ ├── PreferencesForm.tsx │ │ ├── ScreenLayout.tsx │ │ ├── Select.tsx │ │ ├── TestnetWarning.tsx │ │ ├── TotalBalance.tsx │ │ ├── TransactionsList.tsx │ │ └── VerifyingMessage.tsx │ ├── contexts │ │ ├── account.tsx │ │ ├── rates.tsx │ │ └── user.tsx │ ├── currencies.ts │ ├── i18n.ts │ ├── interfaces │ │ ├── account.ts │ │ ├── blockchain.ts │ │ ├── cico.ts │ │ ├── currencies.ts │ │ ├── transaction.ts │ │ └── user.ts │ ├── locales │ │ ├── en │ │ │ ├── auth.json │ │ │ ├── index.ts │ │ │ ├── layout.json │ │ │ ├── legal.json │ │ │ ├── receive.json │ │ │ ├── send.json │ │ │ ├── settings.json │ │ │ ├── transaction.json │ │ │ ├── transfer.json │ │ │ ├── validations.json │ │ │ └── verify.json │ │ ├── es │ │ │ ├── auth.json │ │ │ ├── index.ts │ │ │ ├── layout.json │ │ │ ├── receive.json │ │ │ ├── send.json │ │ │ ├── settings.json │ │ │ ├── transaction.json │ │ │ ├── transfer.json │ │ │ ├── validations.json │ │ │ └── verify.json │ │ └── index.ts │ ├── screens │ │ ├── Account.tsx │ │ ├── AddBankAccount.tsx │ │ ├── AddCreditCard.tsx │ │ ├── ConnectionError.tsx │ │ ├── ForgotPassword.tsx │ │ ├── Home.tsx │ │ ├── Receive.tsx │ │ ├── ResetPassword.tsx │ │ ├── Send │ │ │ ├── Send.tsx │ │ │ ├── SendReview.tsx │ │ │ └── SendScanQR.tsx │ │ ├── Settings.tsx │ │ ├── SignIn.tsx │ │ ├── SignUp.tsx │ │ ├── SingleTransaction.tsx │ │ ├── Transactions.tsx │ │ ├── Transfer.tsx │ │ ├── Transfer │ │ │ ├── Convert.tsx │ │ │ ├── ConvertReview.tsx │ │ │ ├── Deposit.tsx │ │ │ ├── DepositReview.tsx │ │ │ ├── Withdraw.tsx │ │ │ └── WithdrawReview.tsx │ │ ├── Verify.tsx │ │ └── VerifySteps │ │ │ ├── Step1Identity.tsx │ │ │ ├── Step2Country.tsx │ │ │ ├── Step3Address.tsx │ │ │ ├── Step4Document.tsx │ │ │ ├── Step5DefaultCurrency.tsx │ │ │ └── interfaces.ts │ ├── services │ │ ├── backendClient.ts │ │ ├── errors.ts │ │ └── sessionStorage.ts │ ├── styles.ts │ └── utils │ │ ├── amount-precision.ts │ │ ├── amountPrecision.test.ts │ │ ├── dropdown-options.ts │ │ └── shorten-address.ts ├── tsconfig.json └── yarn.lock ├── scripts ├── README.md ├── compile_frontend.sh ├── funcs.sh ├── generate_i18n.py ├── install-git-hooks.sh ├── lrw.sh ├── pre-commit ├── run_dmw_test.sh ├── set_copyright_headers.py ├── set_env.py └── wait_for_server_ready.sh ├── vasp-validator ├── .env.example ├── .flake8 ├── Pipfile ├── Pipfile.lock ├── README.md ├── lint.sh ├── pytest.ini ├── setup.py ├── src │ └── vasp_validator │ │ ├── __init__.py │ │ ├── models.py │ │ ├── models_fppa.py │ │ ├── reference_wallet_proxy.py │ │ ├── tests │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── plugin.py │ │ ├── test_charge_payment_command.py │ │ ├── test_funds_pull_preapproval.py │ │ ├── test_p2m.py │ │ ├── test_tx_no_travel_rule.py │ │ ├── test_tx_with_travel_rule_success.py │ │ └── vasp_proxy_hook.py │ │ ├── validator_client.py │ │ └── vasp_proxy.py ├── test.sh └── tests │ ├── __init__.py │ ├── conftest.py │ ├── test_vasp_proxy_hook.py │ └── vasp_proxy_testee.py └── wait.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | # All the hidden files and directories 2 | **/.* 3 | 4 | # Not needed for the backend 5 | docker 6 | frontend 7 | gateway 8 | scripts 9 | helm/ 10 | 11 | requirements.txt 12 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Env file for docker-compose proejct name. 2 | 3 | COMPOSE_PROJECT_NAME=lrw -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B \U0001F5C4 Backend Bug report" 3 | about: Create a bug report to help improve the Diem Reference Wallet Backend 4 | title: "[Bug]" 5 | labels: bug, backend 6 | assignees: '' 7 | 8 | --- 9 | 10 | # 🐛 Bug 11 | 12 | If you're looking to report an issue with the Diem Core project go to https://github.com/libra/libra 13 | 14 | 17 | 18 | ## Steps to reproduce 19 | 20 | 21 | 22 | ** Error message or problem ** 23 | ``` 24 | // Paste the output here 25 | ``` 26 | 27 | ## Expected Behavior 28 | 29 | 30 | 31 | ## System information 32 | 33 | **Please complete the following information:** 34 | - 35 | 36 | 37 | ## Additional context 38 | 39 | 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report_mobile.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B \U0001F4F1 Mobile App Bug report" 3 | about: Create a bug report to help improve the Diem Reference Wallet Mobile App 4 | title: "[Bug]" 5 | labels: bug, mobile 6 | assignees: '' 7 | 8 | --- 9 | 10 | # 🐛 Bug 11 | 12 | If you're looking to report an issue with the Diem Core project go to https://github.com/libra/libra 13 | 14 | 17 | 18 | ## Steps to reproduce 19 | 20 | 21 | 22 | ** Error message or problem ** 23 | ``` 24 | // Paste the output here 25 | ``` 26 | 27 | ## Expected Behavior 28 | 29 | 30 | 31 | ## System information 32 | 33 | **Please complete the following information:** 34 | - 35 | - 36 | 37 | 38 | ## Additional context 39 | 40 | 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report_web.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B \U0001F4BB Web Client Bug report" 3 | about: Create a bug report to help improve the Diem Reference Web Client 4 | title: "[Bug]" 5 | labels: bug, web 6 | assignees: '' 7 | 8 | --- 9 | 10 | # 🐛 Bug 11 | 12 | If you're looking to report an issue with the Diem Core project go to https://github.com/libra/libra 13 | 14 | 17 | 18 | ## Steps to reproduce 19 | 20 | 21 | 22 | ** Error message or problem ** 23 | ``` 24 | // Paste the output here 25 | ``` 26 | 27 | ## Expected Behavior 28 | 29 | 30 | 31 | ## System information 32 | 33 | **Please complete the following information:** 34 | - 35 | - 36 | 37 | 38 | ## Additional context 39 | 40 | 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new-feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U00002728 New Feature Request" 3 | about: Suggest a new feature for Reference Wallet 4 | title: "[feature-request]" 5 | labels: feature-request 6 | assignees: '' 7 | 8 | --- 9 | 10 | # New Feature Request Description 11 | 12 | 13 | 14 | ## Why would this be useful? 15 | 16 | 17 | 18 | ## Additional context 19 | 20 | 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Motivation 6 | 7 | (Write your motivation for proposed changes here.) 8 | 9 | ### Have you read the [Contributing Guidelines on pull requests](https://github.com/libra/libra-wallet/blob/master/CONTRIBUTING.md#pull-requests)? 10 | 11 | (Write your answer here.) 12 | 13 | ## Test Plan 14 | 15 | (Share your test plan here. If you changed code, please provide us with clear instructions for verifying that your changes work.) 16 | 17 | ## Related PRs 18 | 19 | (If your PR adds or changes functionality, please take time to update the docs at https://github.com/libra/website, and link to your PR here.) 20 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | - develop 8 | push: 9 | branches: 10 | - master 11 | - develop 12 | 13 | jobs: 14 | build: 15 | 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | python-version: [3.7] 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v1 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | - name: Install pipenv 28 | run: | 29 | pip install --upgrade pipenv 30 | - name: Fetch liquidity submodule 31 | run: | 32 | git submodule update --init --recursive 33 | - name: Install dependencies for backend 34 | run: | 35 | cd backend && pipenv install --dev 36 | cd ../liquidity && pipenv install --dev 37 | cd .. 38 | - name: Setup env 39 | run: | 40 | ./scripts/lrw.sh setup_environment 41 | - name: Test with pytest 42 | run: | 43 | ./scripts/lrw.sh watch_test 44 | - name: Compile frontend 45 | run: | 46 | ./scripts/compile_frontend.sh 47 | -------------------------------------------------------------------------------- /.github/workflows/dmw_test.yaml: -------------------------------------------------------------------------------- 1 | name: DMW Test 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | - develop 8 | push: 9 | branches: 10 | - master 11 | - develop 12 | 13 | jobs: 14 | build: 15 | 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | python-version: [3.7] 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v1 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | - name: Install pipenv 28 | run: pip install --upgrade pipenv 29 | - name: Fetch liquidity submodule 30 | run: git submodule update --init --recursive 31 | - name: Setup Environment 32 | run: | 33 | VASP_BASE_URL=http://localhost:8080 ./scripts/lrw.sh setup_environment false 34 | - name: Launch tests against it 35 | run: ./scripts/run_dmw_test.sh 36 | - name: Save results 37 | uses: actions/upload-artifact@v2 38 | if: ${{ always() }} 39 | with: 40 | name: test-output 41 | path: | 42 | output 43 | -------------------------------------------------------------------------------- /.github/workflows/e2e.yaml: -------------------------------------------------------------------------------- 1 | name: E2E Test 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | - develop 8 | push: 9 | branches: 10 | - master 11 | - develop 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | strategy: 17 | matrix: 18 | python-version: [3.7] 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | - name: Set up Python ${{ matrix.python-version }} 23 | uses: actions/setup-python@v1 24 | with: 25 | python-version: ${{ matrix.python-version }} 26 | - name: Check kill switch 27 | id: check_ks 28 | run: | 29 | if [ -z "${{ secrets.KILL_SWITCH_E2E_TEST }}" ]; then 30 | echo "::set-output name=should_run::false"; 31 | else 32 | echo "::set-output name=should_run::true"; 33 | fi; 34 | - name: Install pipenv 35 | run: | 36 | pip install --upgrade pipenv 37 | - name: run e2e tests 38 | if: steps.check_ks.outputs.should_run == 'true' 39 | run: | 40 | make setup-env e2e 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | .idea/ 3 | /**/__pycache__ 4 | /.pyre 5 | /.eggs 6 | dump.rdb 7 | *.egg-info 8 | *flask_session 9 | **/.DS_Store 10 | e2e.vars 11 | single.vars 12 | double.vars 13 | build 14 | # Frontend build artifacts 15 | /gateway/tmp 16 | 17 | # pyenv local version 18 | .python-version 19 | 20 | */fastlane/report.xml 21 | */fastlane/Preview.html 22 | */fastlane/screenshots 23 | 24 | # dotenv 25 | .env* 26 | !.env.example 27 | 28 | # Bundle artifact 29 | *.jsbundle 30 | 31 | # CocoaPods 32 | /ios/Pods/ 33 | 34 | backend/.eggs/ 35 | backend/pyproject.toml 36 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "liquidity"] 2 | path = liquidity 3 | url = https://github.com/diem/liquidity-emulator.git 4 | -------------------------------------------------------------------------------- /.pyre_configuration: -------------------------------------------------------------------------------- 1 | { 2 | "source_directories": [ 3 | "backend/" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | The project has adopted a Code of Conduct that we expect project participants to adhere to. Please [read the full text](https://developers.libra.org/docs/policies/code-of-conduct) so that you can understand what actions will and will not be tolerated. 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to pubsub-proxy 2 | 3 | This project welcomes contributions. 4 | 5 | ## Contributor License Agreement 6 | 7 | For pull request to be accepted by any Diem projects, a CLA must be signed. 8 | You will only need to do this once to work on any of Diem's open source 9 | projects. 10 | 11 | When submitting a PR, the diem-github-bot will check your comment for a valid CLA. If one is not found, then you will need to submit an Individual CLA for yourself or a Corporate CLA for your company. 12 | 13 | ## Submitting Issues and Feature Requests 14 | 15 | The Diem Reference Wallet uses [GitHub issues](https://github.com/diem/reference-wallet/issues) to track bugs and feature requests. Please include necessary information and instructions to reproduce your issue or describe your use case. 16 | 17 | ## Other Ways to Provide Feedback 18 | 19 | You can also submit product or design feedback while on the demo web and mobile wallet by selecting [Feedback]. 20 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policies and Procedures 2 | 3 | Please see Diem's 4 | [security policies](https://developers.libra.org/docs/policies/security) and 5 | procedures for reporting vulnerabilities. 6 | -------------------------------------------------------------------------------- /backend/.env.example: -------------------------------------------------------------------------------- 1 | GW_PORT=8080 2 | WALLET_CUSTODY_ACCOUNT_NAME=wallet 3 | CUSTODY_PRIVATE_KEYS={"${WALLET_CUSTODY_ACCOUNT_NAME}":""} 4 | VASP_ADDR= 5 | LIQUIDITY_SERVICE_HOST=liquidity 6 | LIQUIDITY_SERVICE_PORT=5000 7 | -------------------------------------------------------------------------------- /backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7-slim 2 | 3 | WORKDIR /wallet 4 | 5 | RUN apt-get update && apt-get install -y gcc git 6 | RUN apt-get install -y curl netcat 7 | RUN pip install pipenv 8 | 9 | COPY wait.sh / 10 | COPY backend/ . 11 | 12 | RUN pipenv install --deploy --system 13 | -------------------------------------------------------------------------------- /backend/MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include src *.html 2 | 3 | -------------------------------------------------------------------------------- /backend/context/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import typing 5 | from .context import from_config, from_env, for_local_dev, generate, Context 6 | 7 | 8 | # a global variable for storing shared instance, use get / set to access 9 | _context: typing.Optional[Context] = None 10 | 11 | 12 | def set(ctx: typing.Optional[Context]) -> None: 13 | global _context 14 | _context = ctx 15 | 16 | 17 | def get() -> Context: 18 | global _context 19 | if _context is None: 20 | raise ValueError("global context is not initialized") 21 | return typing.cast(Context, _context) 22 | -------------------------------------------------------------------------------- /backend/context/stubs/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from . import custody 5 | -------------------------------------------------------------------------------- /backend/diem_utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from ._version import get_versions 5 | 6 | __version__ = get_versions()["version"] 7 | del get_versions 8 | -------------------------------------------------------------------------------- /backend/diem_utils/sdks/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/diem_utils/types/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/diem_utils/types/currencies.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import typing 5 | from enum import Enum 6 | 7 | 8 | class DiemCurrency(str, Enum): 9 | XUS = "XUS" 10 | 11 | 12 | class FiatCurrency(str, Enum): 13 | USD = "USD" 14 | EUR = "EUR" 15 | GBP = "GBP" 16 | CHF = "CHF" 17 | CAD = "CAD" 18 | AUD = "AUD" 19 | NZD = "NZD" 20 | JPY = "JPY" 21 | 22 | 23 | Currencies = typing.Union[FiatCurrency, DiemCurrency] 24 | 25 | DEFAULT_DIEM_CURRENCY = DiemCurrency.XUS.value 26 | -------------------------------------------------------------------------------- /backend/diem_utils/types/liquidity/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/diem_utils/types/liquidity/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | class TradeError(Exception): 6 | pass 7 | 8 | 9 | class AlreadySettled(Exception): 10 | pass 11 | -------------------------------------------------------------------------------- /backend/diem_utils/types/liquidity/lp.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from dataclasses import dataclass 5 | from typing import Type 6 | 7 | from dataclasses_json import dataclass_json 8 | 9 | from .currency import CurrencyPairs 10 | 11 | 12 | @dataclass_json 13 | @dataclass 14 | class LPDetails: 15 | sub_address: str 16 | vasp: str 17 | IBAN_number: str 18 | -------------------------------------------------------------------------------- /backend/diem_utils/types/liquidity/quote.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from dataclasses import dataclass 5 | from datetime import datetime 6 | from typing import NewType 7 | from uuid import UUID 8 | 9 | from dataclasses_json import dataclass_json 10 | 11 | from .currency import CurrencyPair 12 | 13 | QuoteId = NewType("QuoteId", UUID) 14 | 15 | 16 | @dataclass_json 17 | @dataclass 18 | class Rate: 19 | pair: CurrencyPair 20 | rate: int 21 | 22 | 23 | @dataclass_json 24 | @dataclass 25 | class QuoteData: 26 | quote_id: QuoteId 27 | rate: Rate 28 | expires_at: datetime 29 | amount: int 30 | -------------------------------------------------------------------------------- /backend/diem_utils/types/liquidity/settlement.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import uuid 5 | from dataclasses import dataclass 6 | from enum import Enum 7 | from typing import NewType 8 | 9 | from dataclasses_json import dataclass_json 10 | 11 | from .currency import Currency 12 | 13 | DebtId = NewType("DebtId", uuid.UUID) 14 | 15 | 16 | @dataclass_json 17 | @dataclass 18 | class DebtData: 19 | debt_id: DebtId 20 | currency: Currency 21 | amount: int # Positive value - Wallet owes LP, negative value - LP owes Wallet 22 | -------------------------------------------------------------------------------- /backend/diem_utils/types/liquidity/trade.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from dataclasses import dataclass 5 | from enum import Enum 6 | from typing import NewType, Optional 7 | from uuid import UUID 8 | 9 | from dataclasses_json import dataclass_json 10 | 11 | from .currency import CurrencyPair 12 | from .quote import QuoteData 13 | 14 | 15 | class Direction(str, Enum): 16 | Buy = "Buy" 17 | Sell = "Sell" 18 | 19 | 20 | TradeId = NewType("TradeId", UUID) 21 | 22 | 23 | @dataclass_json 24 | @dataclass 25 | class AddressSequence: 26 | address: str 27 | sequence: int 28 | 29 | 30 | class TradeStatus(str, Enum): 31 | Pending = "Pending" 32 | Complete = "Complete" 33 | Consolidated = "Consolidated" 34 | 35 | 36 | @dataclass_json 37 | @dataclass 38 | class TradeData: 39 | trade_id: TradeId 40 | direction: Direction 41 | pair: CurrencyPair 42 | amount: float 43 | status: TradeStatus 44 | quote: QuoteData 45 | tx_version: Optional[int] = None 46 | -------------------------------------------------------------------------------- /backend/offchain/action.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | from enum import Enum 6 | 7 | 8 | class Action(Enum): 9 | EVALUATE_KYC_DATA = "evaluate_kyc_data" 10 | REVIEW_KYC_DATA = "review_kyc_data" 11 | CLEAR_SOFT_MATCH = "clear_soft_match" 12 | SUBMIT_TXN = "submit_transaction" 13 | -------------------------------------------------------------------------------- /backend/offchain/command.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from abc import ABC, abstractmethod 5 | from .action import Action 6 | from .types import CommandRequestObject 7 | 8 | import typing 9 | 10 | 11 | class Command(ABC): 12 | @abstractmethod 13 | def id(self) -> str: 14 | """Returns cid of command object""" 15 | 16 | def command_type(self) -> str: 17 | ... 18 | 19 | @abstractmethod 20 | def is_inbound(self) -> bool: 21 | ... 22 | 23 | @abstractmethod 24 | def follow_up_action(self) -> typing.Optional[Action]: 25 | ... 26 | 27 | @abstractmethod 28 | def reference_id(self) -> str: 29 | ... 30 | 31 | @abstractmethod 32 | def new_request(self) -> CommandRequestObject: 33 | ... 34 | 35 | @abstractmethod 36 | def validate(self, prior: typing.Optional["Command"]) -> None: 37 | ... 38 | 39 | @abstractmethod 40 | def my_address(self) -> str: 41 | """Returns my account identifier used for sending command request""" 42 | ... 43 | 44 | @abstractmethod 45 | def counterparty_address(self) -> str: 46 | """Returns the counterparty account identifier that receives the command request""" 47 | ... 48 | -------------------------------------------------------------------------------- /backend/offchain/error.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from .types import ( 5 | OffChainErrorType, 6 | OffChainErrorObject, 7 | ) 8 | 9 | import typing 10 | 11 | 12 | class Error(Exception): 13 | obj: OffChainErrorObject 14 | 15 | def __init__(self, obj: OffChainErrorObject) -> None: 16 | super(Exception, self).__init__(obj) 17 | self.obj = obj 18 | 19 | 20 | def command_error(code: str, message: str, field: typing.Optional[str] = None) -> Error: 21 | return Error( 22 | obj=OffChainErrorObject( 23 | type=OffChainErrorType.command_error, 24 | code=code, 25 | field=field, 26 | message=message, 27 | ) 28 | ) 29 | 30 | 31 | def protocol_error( 32 | code: str, message: str, field: typing.Optional[str] = None 33 | ) -> Error: 34 | return Error( 35 | obj=OffChainErrorObject( 36 | type=OffChainErrorType.protocol_error, 37 | code=code, 38 | field=field, 39 | message=message, 40 | ) 41 | ) 42 | -------------------------------------------------------------------------------- /backend/offchain/funds_pull_pre_approval_command_state.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import typing 5 | 6 | from .types import FundPullPreApprovalStatus 7 | 8 | Status = str 9 | 10 | _transitions: typing.Dict[Status, typing.List[Status]] = { 11 | FundPullPreApprovalStatus.pending: [ 12 | FundPullPreApprovalStatus.pending, 13 | FundPullPreApprovalStatus.valid, 14 | FundPullPreApprovalStatus.rejected, 15 | FundPullPreApprovalStatus.closed, 16 | ], 17 | FundPullPreApprovalStatus.valid: [ 18 | FundPullPreApprovalStatus.valid, 19 | FundPullPreApprovalStatus.closed, 20 | ], 21 | FundPullPreApprovalStatus.rejected: [ 22 | FundPullPreApprovalStatus.rejected, 23 | ], 24 | FundPullPreApprovalStatus.closed: [ 25 | FundPullPreApprovalStatus.closed, 26 | ], 27 | } 28 | 29 | _initial_states: typing.List[Status] = [ 30 | FundPullPreApprovalStatus.pending, 31 | FundPullPreApprovalStatus.valid, 32 | FundPullPreApprovalStatus.rejected, 33 | ] 34 | 35 | 36 | def is_valid_transition(current_status: Status, next_status: Status) -> bool: 37 | return next_status in _transitions[current_status] 38 | 39 | 40 | def is_valid_initial_status(status: Status) -> bool: 41 | return status in _initial_states 42 | -------------------------------------------------------------------------------- /backend/offchain/http_header.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | X_REQUEST_ID: str = "X-REQUEST-ID" 5 | X_REQUEST_SENDER_ADDRESS: str = "X-REQUEST-SENDER-ADDRESS" 6 | -------------------------------------------------------------------------------- /backend/offchain/types/cid.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | 3 | 4 | def generate_cid() -> str: 5 | return str(uuid.uuid4()) 6 | -------------------------------------------------------------------------------- /backend/pubsub/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import os 5 | 6 | VASP_ADDR = os.getenv("VASP_ADDR") 7 | JSON_RPC_URL = os.getenv("JSON_RPC_URL") 8 | 9 | DEFL_CONFIG = { 10 | "diem_node_uri": JSON_RPC_URL, 11 | "sync_interval_ms": 1000, 12 | "progress_file_path": "/tmp/pubsub_progress", 13 | "accounts": [VASP_ADDR], 14 | } 15 | -------------------------------------------------------------------------------- /backend/pubsub/__main__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import argparse 5 | import json 6 | import sys 7 | 8 | from pubsub import DEFL_CONFIG, VASP_ADDR 9 | from pubsub.client import LRWPubSubClient 10 | 11 | 12 | parser = argparse.ArgumentParser( 13 | description="Pubsub CLI tool. Takes in pubsub config file or VASP_ADDR environment variable" 14 | ) 15 | parser.add_argument("-f", "--file", type=str, help="LRW pubsub config file path") 16 | args = parser.parse_args() 17 | 18 | if args.file: 19 | try: 20 | with open(args.file) as f: 21 | conf = json.load(f) 22 | except: 23 | print("Missing or invalid config file, exiting...") 24 | sys.exit(1) 25 | else: # load in by env var 26 | if not VASP_ADDR: 27 | print("Missing VASP_ADDR environment variable, exiting...") 28 | sys.exit(1) 29 | conf = DEFL_CONFIG 30 | 31 | print(conf) 32 | 33 | client = LRWPubSubClient(conf) 34 | client.start() 35 | -------------------------------------------------------------------------------- /backend/run_pubsub.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | python3 -m pubsub 7 | -------------------------------------------------------------------------------- /backend/run_web.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | export FLASK_ENV=${COMPOSE_ENV:-development} 7 | export FLASK_APP="webapp:init()" 8 | 9 | pipenv run flask run --host 0.0.0.0 --port ${WALLET_PORT:-5000} --no-reload 10 | -------------------------------------------------------------------------------- /backend/run_worker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | PROCS=${PROCS:-2} 7 | THREADS=${THREADS:-2} 8 | 9 | if [ -z "${PROCS##*[!0-9]*}" ] || [ -z "${THREADS##*[!0-9]*}" ]; then 10 | echo "PROCS and THREADS env vars should be integers" 11 | exit 1 12 | fi 13 | 14 | dramatiq wallet -p $PROCS -t $THREADS --verbose --watch . "$@" 15 | -------------------------------------------------------------------------------- /backend/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from setuptools import setup, find_packages 5 | 6 | setup( 7 | name="diem-sample-wallet", 8 | version="0.1.0", 9 | description="Sample custodial wallet implementation", 10 | python_requires=">=3.5", 11 | packages=find_packages(), 12 | tests_require=["pytest", "pytest-runner"], 13 | package_dir={"": "."}, 14 | setup_requires=["pytest-runner"], 15 | ) 16 | -------------------------------------------------------------------------------- /backend/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xv 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 7 | 8 | set -euo pipefail 9 | 10 | # pipenv run black --check $DIR 11 | 12 | # NOTE: 13 | # each of these test modules need to be run independently due to how they 14 | # instantiate dramatiq and other test dependencies in conftest.py 15 | pipenv run python3 $DIR/setup.py pytest --addopts="$DIR/tests/wallet_tests $@" 16 | pipenv run python3 $DIR/setup.py pytest --addopts="$DIR/tests/webapp_tests $@" 17 | pipenv run python3 $DIR/setup.py pytest --addopts="$DIR/tests/pubsub_tests $@" 18 | pipenv run python3 $DIR/setup.py pytest --addopts="$DIR/tests/context_tests $@" 19 | -------------------------------------------------------------------------------- /backend/tests/README.md: -------------------------------------------------------------------------------- 1 | # tests 2 | 3 | Tests exist in a separate package because of dramatiq broker instantiation when one does `import wallet` for the first time 4 | -------------------------------------------------------------------------------- /backend/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/tests/e2e_tests/double/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/tests/e2e_tests/single/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/tests/e2e_tests/single/test_init.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import json 5 | import random 6 | 7 | import requests 8 | from tests.e2e_tests import LRW_WEB_1 9 | 10 | 11 | def test_init() -> None: 12 | # just test that the webapp works 13 | res = requests.get(f"{LRW_WEB_1}/api/execution_logs") 14 | assert res.ok 15 | 16 | 17 | def test_create_account() -> None: 18 | num = random.randint(0, 1000) 19 | payload = {"username": f"fakeuser{num}", "password": "fakepassword"} 20 | res = requests.post(f"{LRW_WEB_1}/api/user", json=payload) 21 | assert res.ok 22 | token = res.text.strip('"') 23 | headers = {"Authorization": f"Bearer {token}"} 24 | users_res = requests.get(f"{LRW_WEB_1}/api/user", headers=headers) 25 | assert users_res.ok 26 | user = json.loads(users_res.text) 27 | assert user.get("username") == payload.get("username") 28 | -------------------------------------------------------------------------------- /backend/tests/mw_drw_proxy/README.md: -------------------------------------------------------------------------------- 1 | # MiniWallet <=> Reference Wallet Proxy 2 | 3 | This will run a proxy which allows the DMW test suite to communicate with DRW. 4 | 5 | For example, when the DRW requests to set up a user, the proxy registers a user, updates their information with KYC, 6 | and deposits any initial test balances that the DMW required, before returning an identifier for that user which DMW 7 | will reuse in future calls. 8 | 9 | 10 | ### Usage: 11 | (from inside the venv) 12 | ``` 13 | DRW_URL_PREFIX=http://reference_wallet:8080 MW_DRW_PROXY_PORT=3130 pipenv run python3 tests/mw_drw_proxy/proxy.py 14 | ``` 15 | This will launch the proxy server on `http://localhost:3130`, and will proxy the requests to an instance of 16 | DRW running at `http://reference_wallet:8080` -------------------------------------------------------------------------------- /backend/tests/mw_drw_proxy/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/tests/offchain_tests/test_deserialize.py: -------------------------------------------------------------------------------- 1 | from diem import LocalAccount 2 | from offchain import CommandResponseObject, jws, CommandResponseStatus 3 | 4 | 5 | def test_serialize_deserialize(): 6 | account = LocalAccount.generate() 7 | response = CommandResponseObject( 8 | status=CommandResponseStatus.success, 9 | cid="3185027f05746f5526683a38fdb5de98", 10 | ) 11 | ret = jws.serialize(response, account.private_key.sign) 12 | 13 | resp = jws.deserialize( 14 | ret, 15 | CommandResponseObject, 16 | account.private_key.public_key().verify, 17 | ) 18 | assert resp == response 19 | -------------------------------------------------------------------------------- /backend/tests/pubsub_tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | ASSOC_ADDRESS: str = "0000000000000000000000000a550c18" 5 | ASSOC_AUTHKEY: str = "3126dc954143b1282565e8829cd8cdfdc179db444f64b406dee28015fce7f392" 6 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/liquidity/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/liquidity/client/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/liquidity/client/test_client.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # import pytest 5 | # 6 | # from diem_utils.types.liquidity.currency import CurrencyPair, Currency 7 | # from liquidity.fx import fixed_rates 8 | # from wallet.lp_client import LpClient 9 | # 10 | # 11 | # def test_get_quote_for_supported_currency_pair(liquidity_provider_session): 12 | # pair = CurrencyPair(Currency.XUS, Currency.USD) 13 | # quote = LpClient().get_quote(pair, 1) 14 | # 15 | # assert quote.rate.rate == fixed_rates[str(pair)] 16 | # assert quote.rate.pair == pair 17 | # 18 | # 19 | # def test_get_quote_unsupported_currency_pair(liquidity_provider_session): 20 | # with pytest.raises(LookupError): 21 | # pair = CurrencyPair(Currency.CHF, Currency.USD) 22 | # LpClient().get_quote(pair, 1) 23 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/liquidity/test_amount.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from diem_utils.precise_amount import Amount 7 | 8 | ONE_DIEM = Amount().deserialize(1000000) 9 | TWO_DIEM = Amount().deserialize(2000000) 10 | TENTH_MILLIDIEM = Amount().deserialize(100) 11 | MAX_PRECISION_DIEM = Amount().deserialize(10000000000000000009) 12 | 13 | 14 | class TestAmount: 15 | def test_mul(self): 16 | x: Amount = ONE_DIEM * ONE_DIEM 17 | assert str(x) == "1.000000" 18 | assert x.serialize() == 1000000 19 | 20 | x: Amount = TENTH_MILLIDIEM * TWO_DIEM 21 | assert str(x) == "0.000200" 22 | assert x.serialize() == 200 23 | 24 | x: Amount = MAX_PRECISION_DIEM * TWO_DIEM 25 | assert str(x) == "20000000000000.000018" 26 | assert x.serialize() == 20000000000000000018 27 | 28 | def test_div(self): 29 | x: Amount = ONE_DIEM / ONE_DIEM 30 | assert str(x) == "1.000000" 31 | assert x.serialize() == 1000000 32 | 33 | x: Amount = ONE_DIEM / TWO_DIEM 34 | assert str(x) == "0.500000" 35 | assert x.serialize() == 500000 36 | 37 | x: Amount = MAX_PRECISION_DIEM / TWO_DIEM 38 | assert str(x) == "5000000000000.000004" 39 | assert x.serialize() == 5000000000000000004 40 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/liquidity/test_utils.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from diem_utils.types.liquidity.currency import CurrencyPairs, CurrencyPair 7 | 8 | 9 | def test_is_not_diem_to_diem(): 10 | pair = CurrencyPairs.XUS_USD.value 11 | 12 | assert CurrencyPair.is_diem_to_diem(pair) is False 13 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/resources/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/resources/seeds/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/resources/seeds/one_approved_user.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from diem_utils.types.currencies import FiatCurrency 7 | from wallet.storage import ( 8 | User, 9 | RegistrationStatus, 10 | Account, 11 | ) 12 | 13 | 14 | class OneApprovedUser: 15 | username = "test-user" 16 | 17 | @staticmethod 18 | def run(db_session): 19 | user = User( 20 | username=OneApprovedUser.username, 21 | registration_status=RegistrationStatus.Approved, 22 | selected_fiat_currency=FiatCurrency.USD, 23 | selected_language="en", 24 | password_salt="123", 25 | password_hash="deadbeef", 26 | account=Account(name="fake_account_seed"), 27 | ) 28 | 29 | db_session.add(user) 30 | db_session.commit() 31 | 32 | return user.id 33 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/resources/seeds/one_p2m_payment_seeder.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from diem_utils.types.currencies import DiemCurrency 4 | from wallet.services.offchain.p2m_payment import P2MPaymentStatus 5 | from wallet.storage.models import Payment as PaymentModel 6 | 7 | 8 | class OneP2MPaymentSeeder: 9 | @staticmethod 10 | def run( 11 | db_session, vasp_address, reference_id, action="charge", amount=100_000_000 12 | ): 13 | db_session.add( 14 | PaymentModel( 15 | vasp_address=vasp_address, 16 | reference_id=reference_id, 17 | merchant_name="Bond & Gurki Pet Store", 18 | action=action, 19 | currency=DiemCurrency.XUS, 20 | amount=amount, 21 | expiration=datetime(2021, 5, 17), 22 | description="description", 23 | status=P2MPaymentStatus.READY_FOR_USER, 24 | ) 25 | ) 26 | 27 | db_session.commit() 28 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/resources/seeds/one_user_multiple_transactions.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from copy import deepcopy 7 | 8 | from wallet.storage import Account 9 | from . import prototypes 10 | 11 | 12 | class OneUserMultipleTransactions: 13 | tx1_currency = "XUS" 14 | tx2_currency = "XUS" 15 | total_txs = 2 16 | username = prototypes.username 17 | 18 | @staticmethod 19 | def run(db_session): 20 | user = deepcopy(prototypes.user) 21 | user.account = Account(name="fake_account_seed") 22 | db_session.add(user) 23 | db_session.commit() 24 | db_session.refresh(user) 25 | 26 | tx1 = deepcopy(prototypes.tx) 27 | tx2 = deepcopy(prototypes.tx) 28 | 29 | tx1.source_id = user.account_id 30 | tx1.sequence = 1 31 | tx1.currency = OneUserMultipleTransactions.tx1_currency 32 | 33 | tx2.destination_id = user.account_id 34 | tx2.sequence = tx1.sequence + 1 35 | tx2.currency = OneUserMultipleTransactions.tx2_currency 36 | user.account.sent_transactions.append(tx1) 37 | user.account.received_transactions.append(tx2) 38 | 39 | db_session.add(user) 40 | db_session.add(tx1) 41 | db_session.add(tx2) 42 | 43 | db_session.commit() 44 | 45 | return tx1, tx2, user 46 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/resources/seeds/one_user_with_one_order.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from copy import deepcopy 7 | from . import prototypes 8 | 9 | 10 | class OneUserWithOneOrder: 11 | username = prototypes.username 12 | 13 | @staticmethod 14 | def run(db_session): 15 | user = deepcopy(prototypes.user) 16 | order = deepcopy(prototypes.order) 17 | 18 | user.orders.append(order) 19 | 20 | db_session.add(order) 21 | db_session.add(user) 22 | 23 | db_session.commit() 24 | 25 | return user.id, order.id 26 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/services/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/services/fx/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/services/fx/test_fx.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import pytest 7 | 8 | from diem_utils.types.liquidity.currency import CurrencyPairs, Currency 9 | from wallet.services.fx.fx import get_rate 10 | 11 | rates = { 12 | str(CurrencyPairs.XUS_USD.value): 1000000, 13 | str(CurrencyPairs.EUR_XUS.value): 1080000, 14 | str(CurrencyPairs.XUS_JPY.value): 107500000, 15 | str(CurrencyPairs.XUS_CHF.value): 980000, 16 | str(CurrencyPairs.GBP_XUS.value): 1230000, 17 | str(CurrencyPairs.XUS_CAD.value): 1410000, 18 | str(CurrencyPairs.AUD_XUS.value): 640000, 19 | str(CurrencyPairs.NZD_XUS.value): 600000, 20 | } 21 | 22 | 23 | def test_get_rate_direct_conversion_matching_currencies(): 24 | rate = get_rate(Currency.XUS, Currency.USD).serialize() 25 | 26 | assert rate == 1000000 27 | 28 | 29 | def test_get_rate_direct_conversion_odd_currencies(): 30 | rate = get_rate(Currency.EUR, Currency.XUS).serialize() 31 | 32 | assert rate == 1080000 33 | 34 | 35 | def test_get_rate_non_exist_conversion(): 36 | with pytest.raises(LookupError): 37 | get_rate(Currency.CHF, Currency.NZD).serialize() 38 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/services/system/test_subaddreses_from_metadata.py: -------------------------------------------------------------------------------- 1 | from diem import diem_types, txnmetadata as metadata 2 | 3 | from wallet.services.system import subaddreses_from_metadata 4 | 5 | 6 | def test_general_metadata(): 7 | expected_r = bytes.fromhex("1122334455667788") 8 | expected_s = bytes.fromhex("1122334455667789") 9 | 10 | both_set_meta = metadata.general_metadata(expected_s, expected_r).hex() 11 | r, s = subaddreses_from_metadata(both_set_meta) 12 | assert r == expected_r.hex() 13 | assert s == expected_s.hex() 14 | 15 | both_empty_meta = metadata.general_metadata().hex() 16 | r, s = subaddreses_from_metadata(both_empty_meta) 17 | assert r is None 18 | assert s is None 19 | 20 | only_r_meta = metadata.general_metadata(to_subaddress=expected_r).hex() 21 | r, s = subaddreses_from_metadata(only_r_meta) 22 | assert r == expected_r.hex() 23 | assert s is None 24 | 25 | only_s_meta = metadata.general_metadata(from_subaddress=expected_s).hex() 26 | r, s = subaddreses_from_metadata(only_s_meta) 27 | assert r is None 28 | assert s == expected_s.hex() 29 | 30 | 31 | def test_refund_metadata(): 32 | meta = metadata.refund_metadata( 33 | original_transaction_version=1, 34 | reason=diem_types.RefundReason__InvalidSubaddress(), 35 | ).hex() 36 | r, s = subaddreses_from_metadata(meta) 37 | assert r is None 38 | assert s is None 39 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/services/system/test_sync_transaction_method.py: -------------------------------------------------------------------------------- 1 | from tests.wallet_tests.services.system.utils import ( 2 | add_incoming_transaction_to_blockchain, 3 | check_number_of_transactions, 4 | ) 5 | from tests.wallet_tests.services.system.utils import ( 6 | setup_inventory_with_initial_transaction, 7 | ) 8 | from wallet.services.account import generate_sub_address 9 | from wallet.services.system import sync_transaction 10 | from wallet.storage import Transaction 11 | 12 | OTHER_ADDRESS_1 = "257e50b131150fdb56aeab4ebe4ec2b9" 13 | SUB_ADDRESS_1 = "8e298f642d08d1af" 14 | 15 | 16 | def test_sync_transaction(patch_blockchain) -> None: 17 | setup_inventory_with_initial_transaction( 18 | patch_blockchain, 1000, mock_blockchain_initial_balance=1000 19 | ) 20 | 21 | ADDED_VERSION = 2 22 | transaction = add_incoming_transaction_to_blockchain( 23 | patch_blockchain, generate_sub_address(), 100, OTHER_ADDRESS_1, 2, ADDED_VERSION 24 | ) 25 | 26 | check_number_of_transactions(1) 27 | 28 | sync_transaction(transaction) 29 | 30 | check_number_of_transactions(2) 31 | 32 | assert ( 33 | Transaction.query.filter_by(blockchain_version=ADDED_VERSION).first() 34 | is not None 35 | ) 36 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/services/test_account.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from tests.wallet_tests.resources.seeds.one_user_seeder import OneUser 7 | from wallet.services import account as account_service 8 | from wallet.storage import db_session, User 9 | 10 | 11 | def test_account_viewable_by_same_user(): 12 | account_name = "test_account" 13 | user = OneUser.run(db_session, account_name=account_name) 14 | 15 | assert account_service.is_user_allowed_for_account( 16 | account_name=account_name, user=user 17 | ) 18 | 19 | 20 | def test_account_not_viewable_by_other_user(): 21 | account_name1 = "test_account" 22 | user = OneUser.run(db_session, account_name=account_name1, username="user1") 23 | 24 | account_name2 = "test_account2" 25 | user2 = OneUser.run(db_session, account_name=account_name2, username="user2") 26 | 27 | assert not account_service.is_user_allowed_for_account( 28 | account_name=account_name1, user=user2 29 | ) 30 | 31 | 32 | def test_account_viewable_by_admin(): 33 | account_name = "test_account" 34 | user = User(id=1, is_admin=True) 35 | 36 | assert account_service.is_user_allowed_for_account( 37 | account_name=account_name, user=user 38 | ) 39 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/storage/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/storage/test_fund_pull_pre_approval.py: -------------------------------------------------------------------------------- 1 | from tests.wallet_tests.resources.seeds.one_funds_pull_pre_approval import ( 2 | OneFundsPullPreApproval, 3 | ) 4 | from wallet.services.offchain.fund_pull_pre_approval_sm import Role 5 | from wallet.storage import ( 6 | db_session, 7 | get_command_by_id, 8 | update_command, 9 | ) 10 | 11 | FUNDS_PULL_PRE_APPROVAL_ID = "5fc49fa0-5f2a-4faa-b391-ac1652c57e4d" 12 | 13 | 14 | def test_update_at(random_bech32_address, my_user): 15 | OneFundsPullPreApproval.run( 16 | db_session=db_session, 17 | account_id=my_user.account_id, 18 | address=random_bech32_address, 19 | biller_address=my_user.address, 20 | funds_pull_pre_approval_id=FUNDS_PULL_PRE_APPROVAL_ID, 21 | status="pending", 22 | role=Role.PAYEE, 23 | ) 24 | 25 | command = get_command_by_id(FUNDS_PULL_PRE_APPROVAL_ID) 26 | 27 | created_at = command.created_at 28 | updated_at = command.updated_at 29 | 30 | command.status = "valid" 31 | 32 | update_command(command) 33 | 34 | updated_command = get_command_by_id(FUNDS_PULL_PRE_APPROVAL_ID) 35 | 36 | assert updated_command.updated_at != updated_at 37 | assert updated_command.updated_at > updated_at 38 | assert updated_command.created_at == created_at 39 | assert updated_command.status == "valid" 40 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/storage/test_order.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from uuid import UUID 7 | 8 | from tests.wallet_tests.resources.seeds.one_user_with_one_order import ( 9 | OneUserWithOneOrder, 10 | ) 11 | from wallet.storage import db_session, get_order, update_order 12 | from wallet.types import ( 13 | OrderStatus, 14 | OrderId, 15 | ) 16 | 17 | 18 | def test_get_order(clean_db: None) -> None: 19 | user_id, order_id = OneUserWithOneOrder().run(db_session) 20 | 21 | order = get_order(OrderId(UUID(order_id))) 22 | 23 | assert order 24 | 25 | 26 | def test_update_order(clean_db: None) -> None: 27 | user_id, order_id = OneUserWithOneOrder().run(db_session) 28 | 29 | update_order(OrderId(UUID(order_id)), order_status=OrderStatus.FailedCredit) 30 | 31 | order = get_order(order_id) 32 | 33 | assert order.order_status == OrderStatus.FailedCredit.value 34 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/storage/test_user.py: -------------------------------------------------------------------------------- 1 | from wallet import storage 2 | from wallet.types import RegistrationStatus 3 | from tests.wallet_tests.resources.seeds.one_user_seeder import OneUser 4 | from wallet.storage import db_session 5 | from diem_utils.types.currencies import DiemCurrency 6 | from datetime import datetime 7 | 8 | 9 | def test_update_user_password_reset_token_expiration(): 10 | user = OneUser.run( 11 | db_session, account_amount=100_000_000_000, account_currency=DiemCurrency.XUS 12 | ) 13 | now = datetime.now() 14 | updated_user = storage.update_user( 15 | user_id=user.id, password_reset_token_expiration=now 16 | ) 17 | assert updated_user.password_reset_token_expiration == now 18 | 19 | 20 | def test_create_user() -> None: 21 | username = "fake_username" 22 | password_hash = "fake_hash" 23 | salt = "fake_salt" 24 | user_id = storage.add_user( 25 | username=username, 26 | password_hash=password_hash, 27 | salt=salt, 28 | registration_status=RegistrationStatus.Pending, 29 | ) 30 | 31 | storage_user = storage.get_user(username=username) 32 | assert storage_user 33 | assert storage_user.id == user_id 34 | -------------------------------------------------------------------------------- /backend/tests/wallet_tests/test_risk.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from wallet.services import risk 7 | 8 | 9 | def test_risk() -> None: 10 | user_id = 1 11 | assert risk.risk_check(user_id, 1) 12 | assert risk.risk_check(user_id, 1000000 * 1000) 13 | assert not risk.risk_check(user_id, 1000000 * 1000 + 1) 14 | -------------------------------------------------------------------------------- /backend/tests/webapp_tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/tests/webapp_tests/routes/test_rates.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from flask import Response 7 | from flask.testing import Client 8 | 9 | 10 | class TestGetRates: 11 | def test_200(self, authorized_client: Client) -> None: 12 | res: Response = authorized_client.get("/account/rates") 13 | data = res.get_json() 14 | assert res.status_code == 200 15 | assert data["rates"] 16 | -------------------------------------------------------------------------------- /backend/wallet/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # keep config import first, because we MUST configure dramatiq broker prior to background_tasks import 5 | # once @actor is being used (e.g. in background_tasks) and no global dramatiq broker configured - 6 | # dramatiq will try to use default RabbitMQ one (this is hardcoded and can't be changed) - which will fail 7 | 8 | from . import config 9 | from . import background_tasks 10 | -------------------------------------------------------------------------------- /backend/wallet/background_tasks/__init__.py: -------------------------------------------------------------------------------- 1 | from .background import * 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /backend/wallet/security.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import json 5 | from functools import wraps 6 | from http import HTTPStatus 7 | 8 | from flask import g, request, Response 9 | 10 | from .services.user import is_valid_token, revoke_token, get_user_by_token 11 | 12 | 13 | def current_user(): 14 | if hasattr(g, "current_user"): 15 | return g.current_user 16 | 17 | 18 | def get_token_id_from_request() -> str: 19 | return request.headers["Authorization"].split()[1] 20 | 21 | 22 | def verify_token(f): 23 | @wraps(f) 24 | def decorated_function(*args, **kwargs): 25 | token_id = get_token_id_from_request() 26 | 27 | if is_valid_token(token_id): 28 | g.current_user = get_user_by_token(token_id) 29 | return f(*args, **kwargs) 30 | else: 31 | revoke_token(token_id) 32 | error = json.dumps( 33 | { 34 | "code": HTTPStatus.UNAUTHORIZED, 35 | "error": "Invalid authorization token", 36 | } 37 | ) 38 | return Response( 39 | error, status=HTTPStatus.UNAUTHORIZED, mimetype="application/json" 40 | ) 41 | 42 | return decorated_function 43 | -------------------------------------------------------------------------------- /backend/wallet/services/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import os 5 | 6 | _RUN_BACKGROUND_TASKS = bool(os.getenv("RUN_BACKGROUND_TASKS", True)) 7 | 8 | 9 | def run_bg_tasks() -> bool: 10 | return _RUN_BACKGROUND_TASKS 11 | 12 | 13 | INVENTORY_ACCOUNT_NAME = "Inventory" 14 | -------------------------------------------------------------------------------- /backend/wallet/services/fx/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /backend/wallet/services/log.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from wallet.storage import save_transaction_log 5 | 6 | 7 | def add_transaction_log(transaction_id, log) -> None: 8 | save_transaction_log(transaction_id=transaction_id, log=log) 9 | -------------------------------------------------------------------------------- /backend/wallet/services/offchain/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/backend/wallet/services/offchain/__init__.py -------------------------------------------------------------------------------- /backend/wallet/services/risk.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | """ Risk module determines if a transaction by a user can be executed. Risk check is stubbed out for LRW 5 | with a simple amount threshold check. """ 6 | 7 | from wallet.logging import log_execution 8 | from wallet.types import UserNotFoundError 9 | 10 | TX_AMOUNT_THRESHOLD = 1_000_000 * 1_000 11 | 12 | 13 | def risk_check(user_id, amount) -> bool: 14 | if user_id is None: 15 | raise UserNotFoundError("Risk check failed with user as None") 16 | if amount <= TX_AMOUNT_THRESHOLD: 17 | log_execution(f"Risk check passed for user {user_id} amount {amount}") 18 | return True 19 | 20 | log_execution( 21 | f"Risk check failed for user {user_id} amount {amount}, need travel rule check" 22 | ) 23 | return False 24 | -------------------------------------------------------------------------------- /backend/wallet/storage/__init__.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from sqlalchemy import MetaData 7 | from sqlalchemy import create_engine 8 | from sqlalchemy.orm import sessionmaker, scoped_session 9 | from sqlalchemy.ext.declarative import declarative_base 10 | from ..config import DB_URL 11 | 12 | connect_args = {} 13 | 14 | if DB_URL.startswith("sqlite"): 15 | connect_args = {"check_same_thread": False} 16 | 17 | engine = create_engine(DB_URL, connect_args=connect_args) 18 | # engine.echo = True 19 | metadata = MetaData() 20 | db_session = scoped_session( 21 | sessionmaker(autocommit=False, autoflush=False, bind=engine) 22 | ) 23 | 24 | Base = declarative_base(metadata=metadata) 25 | Base.query = db_session.query_property() 26 | 27 | from .user import * 28 | from .account import * 29 | from .order import * 30 | from .token import * 31 | from .transaction import * 32 | from .logs import * 33 | from .funds_pull_pre_approval_command import * 34 | from .p2p_payment import * 35 | from .p2m_payment import * 36 | -------------------------------------------------------------------------------- /backend/wallet/storage/logs.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from datetime import datetime 7 | from . import db_session 8 | from .models import ExecutionLog 9 | 10 | 11 | # logs to both database and stdout 12 | def add_execution_log(message) -> None: 13 | # get the previous frame in the stack 14 | log = ExecutionLog(log=message, timestamp=datetime.utcnow()) 15 | db_session.add(log) 16 | db_session.commit() 17 | 18 | 19 | def get_execution_logs(): 20 | return [log for log in ExecutionLog.query.all()] 21 | -------------------------------------------------------------------------------- /backend/wallet/storage/p2m_payment.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from . import db_session, models 4 | 5 | logger = logging.getLogger(__name__) 6 | 7 | 8 | def save_payment(payment: models.Payment): 9 | db_session.add(payment) 10 | db_session.commit() 11 | 12 | return payment 13 | 14 | 15 | def get_payment_details(reference_id: str) -> models.Payment: 16 | return models.Payment.query.filter_by(reference_id=reference_id).first() 17 | 18 | 19 | def update_payment(reference_id: str, status: str, recipient_signature: str = None): 20 | payment_in_db = get_payment_details(reference_id) 21 | 22 | if recipient_signature: 23 | payment_in_db.recipient_signature = recipient_signature 24 | 25 | payment_in_db.status = status 26 | 27 | try: 28 | payment_in_db.update(payment_in_db) 29 | db_session.commit() 30 | except Exception as e: 31 | logger.error(error) 32 | raise error 33 | -------------------------------------------------------------------------------- /backend/wallet/storage/setup.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from wallet.storage import Base, engine 7 | 8 | 9 | def setup_wallet_storage(): 10 | Base.metadata.create_all(bind=engine) 11 | -------------------------------------------------------------------------------- /backend/wallet/storage/token.py: -------------------------------------------------------------------------------- 1 | # pyre-ignore-all-errors 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from time import time 7 | from uuid import uuid1 8 | 9 | from . import db_session 10 | from .models import Token 11 | 12 | 13 | def get_token(token_id: str): 14 | return Token.query.get(token_id) 15 | 16 | 17 | def create_token(user_id, expiration_time: float) -> str: 18 | token = Token( 19 | user_id=user_id, 20 | expiration_time=expiration_time, 21 | ) 22 | db_session.add(token) 23 | db_session.commit() 24 | return token.id 25 | 26 | 27 | def delete_token(token_id) -> None: 28 | token = Token.query.get(token_id) 29 | if token is not None: 30 | db_session.delete(token) 31 | db_session.commit() 32 | 33 | 34 | def delete_user_tokens(user_id) -> None: 35 | Token.query.filter_by(user_id=user_id).delete() 36 | db_session.commit() 37 | 38 | 39 | def update_token(token_id: uuid1, expiration_time: float) -> None: 40 | token = Token.query.get(token_id) 41 | if token is not None: 42 | token.expiration_time = expiration_time 43 | db_session.add(token) 44 | db_session.commit() 45 | -------------------------------------------------------------------------------- /backend/webapp/debug.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from typing import Union 5 | from flask import ( 6 | Blueprint, 7 | render_template, 8 | ) 9 | from werkzeug.wrappers import Response 10 | from wallet.storage import get_execution_logs 11 | 12 | 13 | root = Blueprint("root", __name__, url_prefix="/") 14 | 15 | 16 | @root.route("/execution_logs", methods=["GET"]) 17 | def list_execution_logs() -> Union[str, Response]: 18 | logs = get_execution_logs() 19 | return render_template("execution_logs.html", logs=logs) 20 | -------------------------------------------------------------------------------- /backend/webapp/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import traceback 5 | from http import HTTPStatus 6 | from json import JSONDecodeError 7 | 8 | from flask import Blueprint, jsonify, make_response, current_app 9 | from werkzeug.exceptions import HTTPException 10 | 11 | errors = Blueprint("errors", __name__) 12 | 13 | 14 | @errors.app_errorhandler(HTTPException) 15 | def handle_http_exception(error): 16 | """Just logs the error. Any unhandled error will eventually get here.""" 17 | 18 | real_error = getattr(error, "original_exception", error) 19 | 20 | current_app.logger.exception(real_error) 21 | 22 | response = { 23 | "code": error.code, 24 | "error": error.description, 25 | } 26 | return make_response(jsonify(response), error.code) 27 | 28 | 29 | @errors.app_errorhandler(JSONDecodeError) 30 | def handle_unexpected_error(error): 31 | status_code = HTTPStatus.BAD_REQUEST 32 | response = {"code": HTTPStatus.BAD_REQUEST, "error": "Could not parse json data"} 33 | 34 | current_app.logger.error(f"error: {error}, exec: {traceback.format_exc()}") 35 | 36 | return make_response(jsonify(response), status_code) 37 | -------------------------------------------------------------------------------- /backend/webapp/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/backend/webapp/static/favicon.ico -------------------------------------------------------------------------------- /backend/webapp/templates/execution_logs.html: -------------------------------------------------------------------------------- 1 | 2 | Global Execution Log 3 | 4 |

Global Execution Log

5 | {% if logs %} 6 | 11 | {% else %} 12 |

No execution log to show.

13 | {% endif %} 14 | 15 | -------------------------------------------------------------------------------- /docker/debug.docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | services: 3 | gateway: 4 | image: nginx:1.17-alpine 5 | volumes: 6 | - ../gateway/nginx.debug.conf:/etc/nginx/nginx.conf 7 | 8 | docker-host: 9 | image: qoomon/docker-host 10 | cap_add: [ 'NET_ADMIN', 'NET_RAW' ] 11 | restart: on-failure 12 | environment: 13 | - PORTS=5000 14 | -------------------------------------------------------------------------------- /docker/dev.docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | services: 3 | gateway: 4 | build: 5 | target: dynamic_conf 6 | volumes: 7 | - ../gateway/nginx.dev.conf:/etc/nginx/nginx.conf 8 | 9 | backend-web-server: 10 | environment: 11 | COMPOSE_ENV: development 12 | ADMIN_LOGIN_ENABLED: 1 13 | ports: 14 | - 5000:5000 15 | volumes: 16 | - ../backend:/wallet 17 | - /wallet/src 18 | - /tmp:/tmp 19 | 20 | backend-worker: 21 | environment: 22 | COMPOSE_ENV: development 23 | volumes: 24 | - ../backend:/wallet 25 | - /wallet/src 26 | - /tmp:/tmp 27 | 28 | backend-pubsub-worker: 29 | environment: 30 | COMPOSE_ENV: development 31 | volumes: 32 | - ../backend:/wallet 33 | - /wallet/src 34 | 35 | liquidity: 36 | environment: 37 | COMPOSE_ENV: development 38 | volumes: 39 | - ../liquidity:/liquidity 40 | - /liquidity/src 41 | ports: 42 | - "5001:5000" 43 | 44 | frontend: 45 | image: lrw_frontend 46 | build: 47 | context: ../frontend 48 | dockerfile: Dockerfile 49 | volumes: 50 | - ../frontend/:/app 51 | - /app/node_modules/ 52 | 53 | db: 54 | ports: 55 | - 15432:5432 56 | -------------------------------------------------------------------------------- /docker/e2e.docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | services: 3 | gateway: 4 | volumes: 5 | - ../gateway/nginx.conf:/etc/nginx/nginx.conf 6 | 7 | backend-web-server: 8 | environment: 9 | - COMPOSE_ENV="development" 10 | ports: 11 | - "5000" 12 | 13 | backend-worker: 14 | environment: 15 | - COMPOSE_ENV="development" 16 | 17 | backend-pubsub-worker: 18 | environment: 19 | - COMPOSE_ENV="development" 20 | 21 | liquidity: 22 | environment: 23 | - COMPOSE_ENV="development" 24 | ports: 25 | - "5000" 26 | -------------------------------------------------------------------------------- /docker/pg/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:12.2-alpine 2 | 3 | COPY ./init.d/* /docker-entrypoint-initdb.d/ 4 | -------------------------------------------------------------------------------- /docker/pg/init.d/backend.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | set -e 7 | 8 | LP_DB_NAME="liquidity_provider_db" 9 | DB_NAME="backend_db" 10 | DB_USER="backenduser" 11 | DB_PASSWORD="backendpassword" 12 | 13 | psql -v ON_ERROR_STOP=0 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL 14 | CREATE USER $DB_USER WITH PASSWORD '$DB_PASSWORD'; 15 | CREATE DATABASE $DB_NAME; 16 | GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER; 17 | EOSQL 18 | 19 | psql -v ON_ERROR_STOP=0 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL 20 | CREATE DATABASE $LP_DB_NAME; 21 | GRANT ALL PRIVILEGES ON DATABASE $LP_DB_NAME TO $DB_USER; 22 | EOSQL 23 | -------------------------------------------------------------------------------- /docker/static.docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | services: 3 | gateway: 4 | build: 5 | target: static_conf 6 | volumes: 7 | - ../gateway/nginx.static.conf:/etc/nginx/nginx.conf 8 | -------------------------------------------------------------------------------- /format.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | (cd backend && exec pipenv run black .) 5 | 6 | (cd frontend && exec yarn prettier --write .) 7 | 8 | (cd vasp-validator && exec ./lint.sh) -------------------------------------------------------------------------------- /frontend/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | Dockerfile -------------------------------------------------------------------------------- /frontend/.env.example: -------------------------------------------------------------------------------- 1 | REACT_APP_BACKEND_URL=/api 2 | REACT_APP_EXPLORER_URL=https://librabrowser.io/version/{version} -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | # JetBrains 26 | .idea 27 | -------------------------------------------------------------------------------- /frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12.16.2-alpine3.11 2 | 3 | WORKDIR /app 4 | ENV PATH /app/node_modules/.bin:$PATH 5 | RUN npm install -g react-scripts --silent 6 | 7 | COPY package.json yarn.lock /app/ 8 | RUN yarn install 9 | 10 | COPY . /app 11 | 12 | RUN CI=true yarn test 13 | RUN yarn build 14 | 15 | CMD yarn start 16 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # LRW Frontend 2 | 3 | This project is based on [React](https://github.com/facebook/react) 4 | 5 | ## How to use? 6 | 7 | 1. Download or clone this repo. 8 | 9 | 2. Install dependencies. 10 | 11 | ```bash 12 | npm install 13 | // or 14 | yarn install 15 | ``` 16 | 17 | 3. Run project on Browser. 18 | 19 | ```bash 20 | npm run start 21 | // or 22 | yarn start 23 | ``` 24 | 25 | ## Run tests 26 | 27 | ```bash 28 | npm run test 29 | // or 30 | yarn test 31 | ``` 32 | -------------------------------------------------------------------------------- /frontend/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/frontend/public/favicon.png -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Diem Reference Wallet 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /frontend/src/assets/fonts/freesans/FreeSans.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/frontend/src/assets/fonts/freesans/FreeSans.woff -------------------------------------------------------------------------------- /frontend/src/assets/fonts/freesans/FreeSansBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/frontend/src/assets/fonts/freesans/FreeSansBold.woff -------------------------------------------------------------------------------- /frontend/src/assets/fonts/freesans/FreeSansBoldOblique.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/frontend/src/assets/fonts/freesans/FreeSansBoldOblique.woff -------------------------------------------------------------------------------- /frontend/src/assets/fonts/freesans/FreeSansOblique.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/frontend/src/assets/fonts/freesans/FreeSansOblique.woff -------------------------------------------------------------------------------- /frontend/src/assets/fonts/freesans/style.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "FreeSans"; 3 | font-style: normal; 4 | font-weight: normal; 5 | src: local("FreeSans Medium"), url("FreeSans.woff") format("woff"); 6 | } 7 | 8 | @font-face { 9 | font-family: "FreeSans"; 10 | font-style: italic; 11 | font-weight: normal; 12 | src: local("FreeSans Oblique"), url("FreeSansOblique.woff") format("woff"); 13 | } 14 | 15 | @font-face { 16 | font-family: "FreeSans"; 17 | font-style: normal; 18 | font-weight: bold; 19 | src: local("FreeSans Bold"), url("FreeSansBold.woff") format("woff"); 20 | } 21 | 22 | @font-face { 23 | font-family: "FreeSans"; 24 | font-style: italic; 25 | font-weight: bold; 26 | src: local("FreeSans BoldOblique"), url("FreeSansBoldOblique.woff") format("woff"); 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/assets/img/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /frontend/src/assets/scss/_credit-cards.scss: -------------------------------------------------------------------------------- 1 | $rccs-card-ratio: 1.5858; 2 | $rccs-size: 16rem; 3 | 4 | $rccs-name-font-size: 1rem; 5 | $rccs-name-font-family: Consolas, Courier, monospace; 6 | $rccs-number-font-size: 1.15rem; 7 | $rccs-number-font-family: Consolas, Courier, monospace; 8 | $rccs-valid-font-size: 0.65rem; 9 | $rccs-expiry-font-size: 0.9rem; 10 | $rccs-expiry-font-family: Consolas, Courier, monospace; 11 | $rccs-cvc-font-size: 0.9rem; 12 | $rccs-cvc-font-family: Consolas, Courier, monospace; 13 | $rccs-cvc-color: #222; 14 | -------------------------------------------------------------------------------- /frontend/src/assets/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | $font-family-sans-serif: "FreeSans", "Helvetica Neue", Arial; 2 | 3 | $body-color: #75767f; 4 | $font-size-base: 0.875rem; 5 | 6 | $theme-colors: ( 7 | "black": #000000, 8 | "default": #eff1f3, 9 | ); 10 | 11 | $headings-color: #000; 12 | $headings-font-weight: 700; 13 | $headings-line-height: 130%; 14 | $headings-margin-bottom: 1rem; 15 | 16 | $primary: #506efa; 17 | $success: #4caf50; 18 | $danger: #ff331f; 19 | $info: #96a8fc; 20 | $text-muted: $body-color; 21 | $link-color: #506efa; 22 | $component-active-bg: #506efa; 23 | $custom-control-indicator-size: 1.25rem; 24 | $border-radius: 0.5rem; 25 | 26 | $btn-font-weight: bold; 27 | $input-bg: #eff1f3; 28 | $input-color: #1a1b29; 29 | $input-placeholder-color: #75767f; 30 | $input-group-addon-bg: #eff1f3; 31 | $input-border-width: 0rem; 32 | $input-btn-padding-y: 0.75rem; 33 | $input-btn-padding-x: 1rem; 34 | 35 | $dropdown-padding-y: 0; 36 | $dropdown-item-padding-y: 0.5rem; 37 | $dropdown-link-color: #000; 38 | $dropdown-link-hover-color: #000; 39 | $dropdown-link-active-color: #000; 40 | $dropdown-link-active-bg: #f5f5f5; 41 | 42 | $alert-padding-y: 0.75rem !default; 43 | $alert-padding-x: 1.25rem !default; 44 | $alert-bg-level: 0; 45 | $alert-border-level: 0; 46 | $alert-border-radius: $border-radius / 2; 47 | 48 | $list-group-border-color: #eff1f3; 49 | -------------------------------------------------------------------------------- /frontend/src/components/Actions.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { useTranslation } from "react-i18next"; 5 | import React from "react"; 6 | import { Button } from "reactstrap"; 7 | 8 | interface ActionsProps { 9 | onSendClick?: () => void; 10 | onRequestClick?: () => void; 11 | onTransferClick?: () => void; 12 | } 13 | 14 | function Actions({ onSendClick, onRequestClick, onTransferClick }: ActionsProps) { 15 | const { t } = useTranslation("layout"); 16 | 17 | return ( 18 | <> 19 | 22 | 31 | 34 | 35 | ); 36 | } 37 | 38 | export default Actions; 39 | -------------------------------------------------------------------------------- /frontend/src/components/Breadcrumbs.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Link } from "react-router-dom"; 5 | import React from "react"; 6 | 7 | function Breadcrumbs({ pageName }: { pageName: string }) { 8 | return ( 9 | 21 | ); 22 | } 23 | 24 | export default Breadcrumbs; 25 | -------------------------------------------------------------------------------- /frontend/src/components/CloseButton.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { useTranslation } from "react-i18next"; 6 | 7 | interface CloseButtonProps { 8 | onClick: () => void; 9 | } 10 | 11 | function CloseButton({ onClick }: CloseButtonProps) { 12 | const { t } = useTranslation("layout"); 13 | 14 | return ( 15 | 24 | ); 25 | } 26 | 27 | export default CloseButton; 28 | -------------------------------------------------------------------------------- /frontend/src/components/ConfirmationModal.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from "reactstrap"; 6 | 7 | export interface ConfirmationModalProps { 8 | title: React.ReactNode; 9 | bodyText: string; 10 | cancelText: string; 11 | confirmText: string; 12 | onClose: (confirmed: boolean) => void; 13 | isOpen: boolean; 14 | } 15 | 16 | export default function ConfirmationModal({ 17 | title, 18 | bodyText, 19 | cancelText, 20 | confirmText, 21 | onClose, 22 | isOpen, 23 | }: ConfirmationModalProps) { 24 | return ( 25 | onClose(false)}> 26 | onClose(false)}>{title} 27 | {bodyText} 28 | 29 | {" "} 32 | 35 | 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /frontend/src/components/ExampleSectionWarning.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { useTranslation } from "react-i18next"; 6 | 7 | const ExampleSectionWarning = () => { 8 | const { t } = useTranslation("legal"); 9 | 10 | return ( 11 |
12 | {t("example_section_warning")} 13 |
14 | ); 15 | }; 16 | 17 | export default ExampleSectionWarning; 18 | -------------------------------------------------------------------------------- /frontend/src/components/Feedback.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { Button } from "reactstrap"; 6 | import { useTranslation } from "react-i18next"; 7 | 8 | const URL = 9 | "https://docs.google.com/forms/d/e/1FAIpQLSfHlFQ4Xz94_9c7ISzdEAPhJ6z1dBXZJ62lF8KGy8u5QoOhMw/viewform"; 10 | 11 | function Feedback() { 12 | const { t } = useTranslation("layout"); 13 | 14 | return ( 15 | 26 | ); 27 | } 28 | 29 | export default Feedback; 30 | -------------------------------------------------------------------------------- /frontend/src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React, { useContext } from "react"; 5 | import { useTranslation } from "react-i18next"; 6 | import { Link } from "react-router-dom"; 7 | import LogoImage from "../assets/img/logo.svg"; 8 | import SettingsImage from "../assets/img/gears.svg"; 9 | import { settingsContext } from "../contexts/app"; 10 | 11 | const Header = () => { 12 | const { t } = useTranslation("layout"); 13 | const [settings] = useContext(settingsContext)!; 14 | 15 | return ( 16 | <> 17 |
18 |
19 | {t("actions.running_on")} {settings.network} 20 |
21 |
22 | 23 | {t("name")} 24 | 25 |
26 | {settings.user && ( 27 | 28 | {t("actions.settings")} 29 | 30 | )} 31 |
32 |
33 | 34 | ); 35 | }; 36 | 37 | export default Header; 38 | -------------------------------------------------------------------------------- /frontend/src/components/LegalDisclaimer.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { useTranslation } from "react-i18next"; 6 | import { Button } from "reactstrap"; 7 | 8 | function LegalDisclaimer({ onClose }: { onClose: () => void }) { 9 | const { t } = useTranslation("legal"); 10 | 11 | return ( 12 |
13 |

{t("legal_disclaimer")}

14 | 15 | 18 |
19 | ); 20 | } 21 | 22 | export default LegalDisclaimer; 23 | -------------------------------------------------------------------------------- /frontend/src/components/Messages/ErrorMessage.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Alert } from "reactstrap"; 5 | import React from "react"; 6 | 7 | interface ErrorMessageProps { 8 | message: string; 9 | } 10 | 11 | function ErrorMessage({ message }: ErrorMessageProps) { 12 | return ( 13 | 14 | {message} 15 | 16 | ); 17 | } 18 | 19 | export default ErrorMessage; 20 | -------------------------------------------------------------------------------- /frontend/src/components/Messages/InfoMessage.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { Alert } from "reactstrap"; 6 | 7 | interface InfoMessageProps { 8 | message: string; 9 | } 10 | 11 | function InfoMessage({ message }: InfoMessageProps) { 12 | return ( 13 | 14 | {message} 15 | 16 | ); 17 | } 18 | 19 | export default InfoMessage; 20 | -------------------------------------------------------------------------------- /frontend/src/components/Messages/SuccessMessage.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Alert } from "reactstrap"; 5 | import React from "react"; 6 | 7 | interface SuccessMessageProps { 8 | message: string; 9 | } 10 | 11 | function SuccessMessage({ message }: SuccessMessageProps) { 12 | return ( 13 | 14 | {message} 15 | 16 | ); 17 | } 18 | 19 | export default SuccessMessage; 20 | -------------------------------------------------------------------------------- /frontend/src/components/Send/interfaces.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { FiatCurrency, DiemCurrency } from "../../interfaces/currencies"; 5 | 6 | export interface Send { 7 | currency?: DiemCurrency; 8 | fiatCurrency: FiatCurrency; 9 | amount?: number; 10 | address?: string; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/components/SettlementDetails.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React, { useContext } from "react"; 5 | import { settingsContext } from "../contexts/app"; 6 | import { diemAmountToHumanFriendly } from "../utils/amount-precision"; 7 | import { Debt } from "../interfaces/settlement"; 8 | 9 | export interface SettlementDetailsProps { 10 | debt: Debt[]; 11 | } 12 | 13 | export default function SettlementDetails({ debt }: SettlementDetailsProps) { 14 | const [settings] = useContext(settingsContext)!; 15 | 16 | return ( 17 |
    18 | {debt.map(({ currency, amount }) => { 19 | const symbol = settings.fiatCurrencies[currency].sign; 20 | return ( 21 |
  • 25 |
    26 | {currency} 27 |
    28 |
    29 |
    30 | {diemAmountToHumanFriendly(amount, true)} {symbol} 31 |
    32 |
    33 |
  • 34 | ); 35 | })} 36 |
37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /frontend/src/components/SignedUpMessage.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { useTranslation } from "react-i18next"; 6 | import { Spinner } from "reactstrap"; 7 | 8 | function SignedUpMessage({ username }: { username: string }) { 9 | const { t } = useTranslation("auth"); 10 | 11 | return ( 12 | <> 13 | {process.env.NODE_ENV === "production" ? ( 14 | <> 15 |

{t("signup.success_username.headline")}

16 |

{t("signup.success_username.text", { replace: { email: username } })}

17 | 18 | ) : ( 19 | <> 20 |

{t("signup.success_email.headline")}

21 |

{t("signup.success_email.text", { replace: { username } })}

22 | 23 | )} 24 |
25 | 26 | {t("signup.redirect", { replace: { username } })} 27 |
28 | 29 | ); 30 | } 31 | 32 | export default SignedUpMessage; 33 | -------------------------------------------------------------------------------- /frontend/src/components/TestnetWarning.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { useTranslation } from "react-i18next"; 6 | 7 | const TestnetWarning = () => { 8 | const { t } = useTranslation("legal"); 9 | 10 | return ( 11 |
12 | {t("testnet_warning")} 13 |
14 | ); 15 | }; 16 | 17 | export default TestnetWarning; 18 | -------------------------------------------------------------------------------- /frontend/src/components/TotalBalance.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { useTranslation } from "react-i18next"; 5 | import React, { useContext } from "react"; 6 | import { settingsContext } from "../contexts/app"; 7 | import { fiatToDiemHumanFriendly, diemAmountToFloat } from "../utils/amount-precision"; 8 | 9 | function TotalBalance() { 10 | const { t } = useTranslation("layout"); 11 | const [settings] = useContext(settingsContext)!; 12 | 13 | if (!settings.account) { 14 | return null; 15 | } 16 | 17 | const fiatCurrency = settings.fiatCurrencies[settings.defaultFiatCurrencyCode!]; 18 | 19 | const totalFiatBalance = settings.account.balances.reduce((totalBalance, currencyBalance) => { 20 | const exchangeRate = 21 | settings.currencies[currencyBalance.currency].rates[settings.defaultFiatCurrencyCode!]; 22 | totalBalance += diemAmountToFloat(currencyBalance.balance) * exchangeRate; 23 | return totalBalance; 24 | }, 0); 25 | 26 | return ( 27 | <> 28 |
29 | {fiatCurrency.sign} 30 | {fiatToDiemHumanFriendly(totalFiatBalance, true)} {fiatCurrency.symbol} 31 |
32 | {t("total_balance")} 33 | 34 | ); 35 | } 36 | 37 | export default TotalBalance; 38 | -------------------------------------------------------------------------------- /frontend/src/components/Transfer/interfaces.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { FiatCurrency, DiemCurrency } from "../../interfaces/currencies"; 5 | 6 | export interface DepositData extends Record { 7 | fundingSource?: number; 8 | fiatCurrency: FiatCurrency; 9 | currency?: DiemCurrency; 10 | amount?: number; 11 | } 12 | 13 | export interface WithdrawData extends Record { 14 | fundingSource?: number; 15 | fiatCurrency: FiatCurrency; 16 | currency?: DiemCurrency; 17 | amount?: number; 18 | } 19 | 20 | export interface ConvertData extends Record { 21 | fromCurrency?: DiemCurrency; 22 | toCurrency?: DiemCurrency; 23 | amount?: number; 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/components/VerifyLoader.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import ContentLoader from "react-content-loader"; 6 | 7 | function VerifyLoader() { 8 | return ( 9 |
10 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | ); 31 | } 32 | 33 | export default VerifyLoader; 34 | -------------------------------------------------------------------------------- /frontend/src/components/VerifyingMessage.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { useTranslation } from "react-i18next"; 6 | import { Spinner } from "reactstrap"; 7 | 8 | function VerifyingMessage() { 9 | const { t } = useTranslation("layout"); 10 | 11 | return ( 12 |
13 |

{t("verification_pending.title")}

14 |

{t("verification_pending.description")}

15 |
16 | 17 | {t("verification_pending.redirect")} 18 |
19 |
20 | ); 21 | } 22 | 23 | export default VerifyingMessage; 24 | -------------------------------------------------------------------------------- /frontend/src/components/datetime-picker/index.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import ReactDatetime from "react-datetime"; 5 | import React from "react"; 6 | import { Moment } from "moment"; 7 | import "react-datetime/css/react-datetime.css"; 8 | 9 | const DATE_FORMAT = "MM/DD/YYYY"; 10 | 11 | interface DateTimeProps { 12 | value?: Moment | string; 13 | onChange?: (value: Moment | string) => void; 14 | placeholder: string; 15 | disabled?: boolean; 16 | invalid?: boolean; 17 | isValidDate?: (currentDate: Moment, selectedDate?: Moment) => boolean; 18 | } 19 | 20 | function DateTimePicker({ 21 | value, 22 | onChange, 23 | placeholder, 24 | disabled, 25 | invalid, 26 | isValidDate, 27 | }: DateTimeProps) { 28 | return ( 29 | 42 | ); 43 | } 44 | 45 | export default DateTimePicker; 46 | -------------------------------------------------------------------------------- /frontend/src/contexts/app.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { createContext, Dispatch, SetStateAction } from "react"; 5 | import { AppSettings } from "../interfaces/settings"; 6 | 7 | type SettingsContext = [AppSettings, Dispatch>]; 8 | 9 | export const settingsContext = createContext(undefined); 10 | -------------------------------------------------------------------------------- /frontend/src/contexts/appInitialState.ts: -------------------------------------------------------------------------------- 1 | import { AppSettings } from "../interfaces/settings"; 2 | 3 | export const initialState: AppSettings = { 4 | network: "", 5 | currencies: { 6 | XUS: { 7 | name: "XUS", 8 | symbol: "XUS", 9 | sign: "≋XUS", 10 | rates: { 11 | USD: 1, 12 | EUR: 0.85, 13 | GBP: 0.8, 14 | CHF: 1, 15 | CAD: 1, 16 | AUD: 1, 17 | NZD: 1, 18 | JPY: 1, 19 | }, 20 | }, 21 | }, 22 | fiatCurrencies: { 23 | USD: { 24 | symbol: "USD", 25 | sign: "$", 26 | }, 27 | EUR: { 28 | symbol: "EUR", 29 | sign: "€", 30 | }, 31 | GBP: { 32 | symbol: "GBP", 33 | sign: "£", 34 | }, 35 | CHF: { 36 | symbol: "CHF", 37 | sign: "Fr", 38 | }, 39 | CAD: { 40 | symbol: "CAD", 41 | sign: "$", 42 | }, 43 | AUD: { 44 | symbol: "AUD", 45 | sign: "$", 46 | }, 47 | NZD: { 48 | symbol: "NZD", 49 | sign: "$", 50 | }, 51 | JPY: { 52 | symbol: "JPY", 53 | sign: "¥", 54 | }, 55 | }, 56 | user: undefined, 57 | account: undefined, 58 | paymentMethods: undefined, 59 | walletTotals: { balances: [], userCount: -1 }, 60 | language: "en", 61 | defaultFiatCurrencyCode: "USD", 62 | }; 63 | -------------------------------------------------------------------------------- /frontend/src/i18n.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import i18next from "i18next"; 5 | import { initReactI18next } from "react-i18next"; 6 | import LocaleResources from "./locales"; 7 | 8 | i18next.use(initReactI18next).init({ 9 | interpolation: { escapeValue: false }, // React already does escaping, 10 | lng: "en", 11 | debug: true, 12 | resources: LocaleResources, 13 | }); 14 | 15 | export const Languages = Object.keys(LocaleResources); 16 | 17 | export default i18next; 18 | -------------------------------------------------------------------------------- /frontend/src/index.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import ReactDOM from "react-dom"; 6 | import App from "./App"; 7 | 8 | export const isProd = process.env.NODE_ENV === "production"; 9 | 10 | ReactDOM.render(, document.getElementById("root")); 11 | -------------------------------------------------------------------------------- /frontend/src/interfaces/account.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { DiemCurrency } from "./currencies"; 5 | 6 | export interface CurrencyBalance { 7 | currency: DiemCurrency; 8 | balance: number; 9 | } 10 | 11 | export interface Account { 12 | balances: CurrencyBalance[]; 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/interfaces/approval.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { DiemCurrency } from "./currencies"; 5 | 6 | type ApprovalStatus = "pending" | "valid" | "rejected" | "closed"; 7 | 8 | type ScopeType = "consent" | "save_sub_account"; 9 | 10 | type UnitType = "day" | "week" | "month" | "year"; 11 | 12 | export interface Approval { 13 | address: string; 14 | biller_address: string; 15 | funds_pull_pre_approval_id: string; 16 | scope: Scope; 17 | description: string; 18 | status: ApprovalStatus; 19 | biller_name: string; 20 | created_at: string; 21 | updated_at: string; 22 | approved_at: string; 23 | } 24 | 25 | interface Scope { 26 | type: ScopeType; 27 | expiration_timestamp: number; 28 | max_cumulative_amount: ScopedCumulativeAmount; 29 | max_transaction_amount: Currency; 30 | } 31 | 32 | interface ScopedCumulativeAmount { 33 | unit: UnitType; 34 | value: number; 35 | max_amount: Currency; 36 | } 37 | 38 | interface Currency { 39 | amount: number; 40 | currency: DiemCurrency; 41 | } 42 | -------------------------------------------------------------------------------- /frontend/src/interfaces/blockchain.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export const VALID_VASP_ADDRESS_REGEX = new RegExp("^[a-zA-Z0-9]{50}$"); 5 | 6 | export const ADDR_PROTOCOL_PREFIX = "diem://"; 7 | 8 | export interface VASPAccount { 9 | vasp_name: string; 10 | user_id: string; 11 | full_addr: string; 12 | } 13 | 14 | export interface BlockchainTransaction { 15 | version: number; 16 | status: string; 17 | expirationTime: string; 18 | source: string; 19 | destination: string; 20 | amount: number; 21 | sequenceNumber: number; 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/interfaces/cico.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export type QuoteAction = "buy" | "sell"; 5 | 6 | export interface RequestForQuote { 7 | action: QuoteAction; 8 | amount: number; 9 | currency_pair: string; // FIXME: specify the supported values 10 | } 11 | 12 | export interface Quote { 13 | quoteId: string; 14 | rfq: RequestForQuote; 15 | price: number; 16 | expirationTime: Date; 17 | } 18 | 19 | export interface Rate { 20 | currency_pair: string; 21 | price: number; 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/interfaces/currencies.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export type DiemCurrency = "XUS"; 5 | 6 | export type FiatCurrency = "USD" | "EUR" | "GBP" | "CHF" | "CAD" | "AUD" | "NZD" | "JPY"; 7 | -------------------------------------------------------------------------------- /frontend/src/interfaces/payment_details.ts: -------------------------------------------------------------------------------- 1 | export interface PaymentDetails { 2 | action: string; 3 | amount: number; 4 | currency: string; 5 | expiration: number; 6 | merchant_name: string; 7 | reference_id: string; 8 | vasp_address: string; 9 | demo: boolean; 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/interfaces/settings.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { FiatCurrency, DiemCurrency } from "./currencies"; 5 | import { PaymentMethod, User } from "./user"; 6 | import { Account, CurrencyBalance } from "./account"; 7 | 8 | export interface CurrencySettings { 9 | name: string; 10 | symbol: DiemCurrency; 11 | sign: string; 12 | rates: { 13 | [key in FiatCurrency]: number; 14 | }; 15 | } 16 | 17 | export interface FiatCurrencySettings { 18 | symbol: FiatCurrency; 19 | sign: string; 20 | } 21 | 22 | export interface WalletTotals { 23 | balances: CurrencyBalance[]; 24 | userCount: number; 25 | } 26 | 27 | export interface AppSettings { 28 | network: string; 29 | currencies: { 30 | [key in DiemCurrency]: CurrencySettings; 31 | }; 32 | fiatCurrencies: { 33 | [key in FiatCurrency]: FiatCurrencySettings; 34 | }; 35 | user?: User; 36 | account?: Account; 37 | language?: string; 38 | defaultFiatCurrencyCode?: FiatCurrency; 39 | paymentMethods?: PaymentMethod[]; 40 | walletTotals: WalletTotals; 41 | } 42 | -------------------------------------------------------------------------------- /frontend/src/interfaces/settlement.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { FiatCurrency } from "./currencies"; 5 | 6 | export interface Debt { 7 | debt_id: string; 8 | currency: FiatCurrency; 9 | amount: number; 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/interfaces/system.ts: -------------------------------------------------------------------------------- 1 | export interface Chain { 2 | chain_id: number; 3 | display_name: string; 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/interfaces/transaction.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { DiemCurrency } from "./currencies"; 5 | import { BlockchainTransaction, VASPAccount } from "./blockchain"; 6 | 7 | export type TransactionDirection = "received" | "sent"; 8 | 9 | export type TransactionStatus = "completed" | "pending" | "canceled" | "locked"; 10 | 11 | export interface Transaction { 12 | id: number; 13 | direction: TransactionDirection; 14 | status: TransactionStatus; 15 | currency: DiemCurrency; 16 | source: VASPAccount; 17 | destination: VASPAccount; 18 | amount: number; 19 | blockchain_tx?: BlockchainTransaction; 20 | timestamp: string; 21 | is_internal: boolean; 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/locales/en/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import Layout from "./layout.json"; 5 | import Auth from "./auth.json"; 6 | import Verify from "./verify.json"; 7 | import Transaction from "./transaction.json"; 8 | import Send from "./send.json"; 9 | import Receive from "./receive.json"; 10 | import Transfer from "./transfer.json"; 11 | import Validations from "./validations.json"; 12 | import Settings from "./settings.json"; 13 | import Admin from "./admin.json"; 14 | import Legal from "./legal.json"; 15 | import FundsPullPreApproval from "./funds_pull_pre_approval.json"; 16 | import Payment from "./payment.json"; 17 | 18 | export default { 19 | layout: Layout, 20 | auth: Auth, 21 | verify: Verify, 22 | transaction: Transaction, 23 | send: Send, 24 | receive: Receive, 25 | transfer: Transfer, 26 | validations: Validations, 27 | settings: Settings, 28 | admin: Admin, 29 | legal: Legal, 30 | funds_pull_pre_approval: FundsPullPreApproval, 31 | payment: Payment, 32 | }; 33 | -------------------------------------------------------------------------------- /frontend/src/locales/en/layout.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Diem Wallet", 3 | "total_balance": "Total Balance", 4 | "balances": "Your Balances", 5 | "transactions": "Latest Transactions", 6 | "transactions_empty": "You don’t have any transactions yet. Once you send, request or transfer money, the transactions will appear here.", 7 | "all_transactions": "All Transactions", 8 | "all_transactions_link": "See All", 9 | "all_currencies": "All Currencies", 10 | "price": "Currently equal to", 11 | "close": "Close", 12 | "approvals": "Funds Pull Pre Approvals Requests", 13 | "all_approvals": "See All Approvals", 14 | "actions": { 15 | "send": "Send", 16 | "request": "Request", 17 | "transfer": "Transfer", 18 | "settings": "Settings", 19 | "running_on": "Running on" 20 | }, 21 | "verification_pending": { 22 | "title": "Verification Pending", 23 | "description": "Your information is being reviewed. We’ll let you know when it’s complete.", 24 | "redirect": "You will be redirected shortly" 25 | }, 26 | "no_payment_methods": { 27 | "title": "You don't have any payment method associated with your account", 28 | "button": "Update now" 29 | }, 30 | "feedback": { 31 | "title": "Leave your feedback", 32 | "text": "Feedback" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /frontend/src/locales/en/legal.json: -------------------------------------------------------------------------------- 1 | { 2 | "legal_disclaimer": "This is a demonstration wallet with no actual users. Do not use any username and/or password you use for other services. Create a test account instead. The compliance processes depicted in this demo wallet are for demonstration purposes only and do not reflect the specific compliance obligations of VASPs under applicable regulatory frameworks, their compliance programs, and/or standards imposed by Diem Networks.", 3 | "example_section_warning": "Example section. No real data required", 4 | "testnet_warning": "This demonstration wallet does not use real money" 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/locales/en/payment.json: -------------------------------------------------------------------------------- 1 | { 2 | "confirmation": { 3 | "title": "Payment Awaiting Approval", 4 | "title_payment_approved": "Payment Approved!", 5 | "payment_approved": "Your payment to {{merchant}} was completed successfully. You can now safely return to the merchant website", 6 | "summary": "Do you approve payment of {{amount}} {{currency}} to {{merchant}}?", 7 | "amount": "Amount", 8 | "merchant": "Merchant", 9 | "receiver": "Receiver", 10 | "expiration": "Expiration", 11 | "reference_id": "Reference Id", 12 | "approve": "Approve", 13 | "reject": "Reject", 14 | "close": "All Good, back to merchant", 15 | "invalid_payment": "Invalid payment request.", 16 | "processing": "Processing", 17 | "store_name": "Store Name", 18 | "error_occured": "An unexpected error occured. Please try again later." 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/locales/en/receive.json: -------------------------------------------------------------------------------- 1 | { 2 | "headline": "Select Digital Currency", 3 | "currency_label": "Each one of your digital currencies has a different address.", 4 | "currency": "Currency", 5 | "scan_qr": "Scan QR", 6 | "text": "You can copy your unique Diem Address and give it to the person you’d like to receive money from, or others can read the Diem Address by scanning the QR code.", 7 | "copy": "Copy Address", 8 | "copied": "Copied <1 />" 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/locales/en/send.json: -------------------------------------------------------------------------------- 1 | { 2 | "success_message": "Your transaction is on the way!", 3 | "fail_message": "Failed to send transaction", 4 | "form": { 5 | "title": "Send Money", 6 | "currency": "currency", 7 | "currency_placeholder": "Select a currency", 8 | "fiatCurrency": "fiat currency", 9 | "amount": "amount", 10 | "price": "currently equal to", 11 | "address": "recipient", 12 | "address_placeholder": "Enter an address", 13 | "exchange_rate": "Exchange rate", 14 | "review": "Review" 15 | }, 16 | "review": { 17 | "title": "Review Transaction", 18 | "description": "Please review your transaction. Once you send money, the transaction can’t be reversed.", 19 | "amount": "You’re sending", 20 | "price": "Currently equal to", 21 | "exchange_rate": "Exchange rate", 22 | "address": "To", 23 | "confirm": "Send", 24 | "done": "Done", 25 | "back": "Back" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/locales/en/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Settings", 3 | "success_message": "Settings saved successfully!", 4 | "payment_methods": { 5 | "title": "Payment Methods", 6 | "credit_cards": { 7 | "title": "Credit Cards", 8 | "not_found": "You haven't added a credit card yet", 9 | "add": "Add New", 10 | "form": { 11 | "title": "Add Credit Card", 12 | "number": "Card number", 13 | "name": "Name", 14 | "expiry": "Valid Thru", 15 | "cvc": "CVC", 16 | "submit": "Add New Credit Card" 17 | } 18 | }, 19 | "bank_accounts": { 20 | "title": "Bank Accounts", 21 | "not_found": "You haven't added a bank account yet", 22 | "add": "Add New", 23 | "form": { 24 | "title": "Add Bank Account", 25 | "account_number": "Account Number", 26 | "bank": "Bank", 27 | "name": "Name", 28 | "submit": "Add New Bank Account" 29 | } 30 | } 31 | }, 32 | "preferences": { 33 | "general": { 34 | "title": "General", 35 | "email": "Your email", 36 | "username": "Your username" 37 | }, 38 | "form": { 39 | "title": "Preferences", 40 | "fiat_currency": "Local currency", 41 | "language": "Language", 42 | "submit": "Save Settings" 43 | } 44 | }, 45 | "signout": "Logout" 46 | } 47 | -------------------------------------------------------------------------------- /frontend/src/locales/en/transaction.json: -------------------------------------------------------------------------------- 1 | { 2 | "sent": "Sent", 3 | "received": "Received", 4 | "price": "Currently equal to", 5 | "date": "Date", 6 | "to": "to", 7 | "from": "from", 8 | "sent_to": "Sent to", 9 | "sent_from": "Sent from", 10 | "status": "Status", 11 | "tx_id": "Transaction ID", 12 | "internal": "Internal", 13 | "not_available": "Not available", 14 | "locked_status": "Locked" 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/locales/en/validations.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": "Please enter {{field}}", 3 | "min": "Please enter {{field}} above {{min}}", 4 | "max": "Please enter {{field}} below {{max}}", 5 | "minLength": "Please enter {{field}} longer than {{minLength}}", 6 | "maxLength": "Please enter {{field}} shorter than {{maxLength}}", 7 | "pattern": "Please enter valid {{field}}", 8 | "numbersOnly": "Please enter {{field}} with numbers only", 9 | "validDate": "Please enter a valid date", 10 | "pastDateOnly": "Please enter a date in the past", 11 | "noEqualCurrencies": "Please select different currencies", 12 | "noMoreThanBalance": "Please enter {{field}} less than your current {{currency}} balance", 13 | "passwordsDontMatch": "Passwords do not match" 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/locales/es/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import Layout from "./layout.json"; 5 | import Auth from "./auth.json"; 6 | import Verify from "./verify.json"; 7 | import Transaction from "./transaction.json"; 8 | import Send from "./send.json"; 9 | import Receive from "./receive.json"; 10 | import Transfer from "./transfer.json"; 11 | import Validations from "./validations.json"; 12 | import Settings from "./settings.json"; 13 | import Admin from "./admin.json"; 14 | import FundsPullPreApproval from "./funds_pull_pre_approval.json"; 15 | 16 | export default { 17 | layout: Layout, 18 | auth: Auth, 19 | verify: Verify, 20 | transaction: Transaction, 21 | send: Send, 22 | receive: Receive, 23 | transfer: Transfer, 24 | validations: Validations, 25 | settings: Settings, 26 | admin: Admin, 27 | funds_pull_pre_approval: FundsPullPreApproval, 28 | }; 29 | -------------------------------------------------------------------------------- /frontend/src/locales/es/layout.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Cartera Diem", 3 | "total_balance": "Saldo Total", 4 | "balances": "Ver sus saldos", 5 | "transactions": "'Últimas transacciones'", 6 | "transactions_empty": "Aún no tienes ninguna transacción. Una vez que envíe, solicite o transfiera dinero, las transacciones aparecerán aquí.", 7 | "all_transactions": "Todas las Transacciones", 8 | "all_transactions_link": "Ver todo", 9 | "all_currencies": "Todas las monedas", 10 | "price": "Actualmente igual a", 11 | "close": "Cerrar", 12 | "actions": { 13 | "send": "Enviar", 14 | "request": "Solicitud", 15 | "transfer": "Transferir", 16 | "settings": "Ajustes" 17 | }, 18 | "verification_pending": { 19 | "title": "Verificación pendiente", 20 | "description": "Su información está siendo revisada. Te avisaremos cuando esté completo." 21 | }, 22 | "feedback": { 23 | "title": "Deje sus comentarios", 24 | "text": "Commentarios" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /frontend/src/locales/es/payment.json: -------------------------------------------------------------------------------- 1 | { 2 | "confirmation": { 3 | "title": "Payment Awaiting Approval", 4 | "title_payment_approved": "Payment Approved!", 5 | "payment_approved": "Your payment to {{merchant}} was completed successfully. You can now safely return to the merchant website", 6 | "summary": "Do you approve payment of {{amount}} {{currency}} to {{merchant}}?", 7 | "amount": "Amount", 8 | "merchant": "Merchant", 9 | "receiver": "Receiver", 10 | "expiration": "Expiration", 11 | "reference_id": "Reference Id", 12 | "approve": "Approve", 13 | "reject": "Reject", 14 | "close": "All Good, back to merchant", 15 | "invalid_payment": "Invalid payment request.", 16 | "processing": "Processing", 17 | "error_occured": "An unexpected error occured. Please try again later." 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/locales/es/receive.json: -------------------------------------------------------------------------------- 1 | { 2 | "headline": "Seleccionar moneda digital", 3 | "currency_label": "Cada una de sus monedas digitales tiene una dirección diferente.", 4 | "currency": "Currency", 5 | "scan_qr": "Escanea el código QR", 6 | "text": "Puede copiar su dirección única y dársela a la persona de la que desea recibir dinero. O otros pueden leer la dirección escaneando el código QR.", 7 | "copy": "Copiar dirección", 8 | "copied": "Copiado <1 />" 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/locales/es/send.json: -------------------------------------------------------------------------------- 1 | { 2 | "success_message": "Su transacción está en camino!", 3 | "fail_message": "Error al enviar la transacción", 4 | "form": { 5 | "title": "Enviar Dinero a Usuario", 6 | "currency": "moneda", 7 | "currency_placeholder": "Selecciona una moneda", 8 | "fiatCurrency": "Moneda Fiat", 9 | "amount": "importe", 10 | "price": "actualmente igual a", 11 | "address": "receptor", 12 | "address_placeholder": "Ingresar Dirección", 13 | "exchange_rate": "Tipo de cambio", 14 | "review": "Revisión" 15 | }, 16 | "review": { 17 | "title": "Revisar transacción", 18 | "description": "Por favor revise su transacción. Una vez que envía dinero, la transacción no se puede revertir.", 19 | "amount": "Estas enviando", 20 | "price": "Actualmente igual a", 21 | "exchange_rate": "Tipo de cambio", 22 | "address": "Para", 23 | "confirm": "Enviar", 24 | "done": "Hecho", 25 | "back": "Atrás" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/locales/es/transaction.json: -------------------------------------------------------------------------------- 1 | { 2 | "sent": "Enviado", 3 | "received": "Recibido", 4 | "price": "Actualmente igual a", 5 | "date": "Fecha", 6 | "to": "a", 7 | "from": "desde", 8 | "sent_to": "Enviar a", 9 | "sent_from": "Enviado desde", 10 | "status": "Estado", 11 | "tx_id": "ID de transacción de Diem", 12 | "internal": "Interna", 13 | "not_available": "No disponible" 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/locales/es/validations.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": "Por favor, complete el campo:", 3 | "min": "Ingrese {{field}} arriba {{min}}", 4 | "max": "Ingrese {{field}} debajo de {{max}}", 5 | "minLength": "Ingrese {{field}} más de {{minLength}}", 6 | "maxLength": "Ingrese {{field}} más corto que {{maxLength}}", 7 | "pattern": "Introduzca el campo válido", 8 | "numbersOnly": "Ingrese {{field}} solo con números", 9 | "validDate": "Por favor, introduzca una fecha válida", 10 | "pastDateOnly": "Por favor introduce una fecha de inicio en el pasado.", 11 | "noEqualCurrencies": "Por favor seleccione diferentes monedas", 12 | "noMoreThanBalance": "Ingrese {{field}} menos que su saldo actual de {{currency}}", 13 | "passwordsDontMatch": "Las contraseñas no concuerdan" 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/locales/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Resource } from "i18next"; 5 | import EN from "./en"; 6 | import ES from "./es"; 7 | 8 | export default { 9 | en: EN, 10 | es: ES, 11 | } as Resource; 12 | -------------------------------------------------------------------------------- /frontend/src/pages/VerifySteps/interfaces.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Moment } from "moment"; 5 | import { FiatCurrency } from "../../interfaces/currencies"; 6 | 7 | export interface IdentityInfo extends Record { 8 | first_name: string; 9 | last_name: string; 10 | dob: string | Moment; 11 | phone_prefix: string; 12 | phone_number: string; 13 | } 14 | 15 | export interface CountryInfo extends Record { 16 | country: string; 17 | } 18 | 19 | export interface AddressInfo extends Record { 20 | address_1: string; 21 | address_2: string; 22 | city: string; 23 | state: string; 24 | zip: string; 25 | } 26 | 27 | export interface DefaultSettings extends Record { 28 | default_fiat_currency: FiatCurrency; 29 | } 30 | -------------------------------------------------------------------------------- /frontend/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// 5 | -------------------------------------------------------------------------------- /frontend/src/services/errors.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export interface ErrorMessage { 5 | error: string; 6 | code: number; 7 | } 8 | 9 | export class BackendError extends Error { 10 | constructor(message: string, public httpStatus: number) { 11 | super(message); 12 | } 13 | } 14 | 15 | export class UsernameAlreadyExistsError extends Error {} 16 | -------------------------------------------------------------------------------- /frontend/src/services/sessionStorage.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | class SessionStorage { 5 | storeAccessToken(token: string): void { 6 | window.localStorage.setItem("token", token); 7 | } 8 | 9 | getAccessToken(): string | undefined { 10 | const token = window.localStorage.getItem("token"); 11 | if (!token) { 12 | return undefined; 13 | } 14 | return token; 15 | } 16 | 17 | removeAccessToken(): void { 18 | window.localStorage.removeItem("token"); 19 | } 20 | } 21 | 22 | export default new SessionStorage(); 23 | -------------------------------------------------------------------------------- /frontend/src/utils/auth-routes.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import SessionStorage from "../services/sessionStorage"; 5 | import { Redirect, Route, useLocation } from "react-router-dom"; 6 | import React from "react"; 7 | 8 | export const LoggedInRoute = ({ component: Component, ...rest }) => { 9 | const queryString = useLocation().search; 10 | 11 | const loggedIn = !!SessionStorage.getAccessToken(); 12 | return ( 13 | 16 | loggedIn ? : 17 | } 18 | /> 19 | ); 20 | }; 21 | 22 | export const LoggedOutRoute = ({ component: Component, ...rest }) => { 23 | const loggedOut = !SessionStorage.getAccessToken(); 24 | return ( 25 | (loggedOut ? : )} 28 | /> 29 | ); 30 | }; 31 | -------------------------------------------------------------------------------- /frontend/src/utils/class-names.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export function classNames(classes: object): string { 5 | return Object.entries(classes) 6 | .filter((e) => e[1]) 7 | .map((e) => e[0]) 8 | .join(" "); 9 | } 10 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "noImplicitAny": false, 6 | "allowJs": true, 7 | "skipLibCheck": true, 8 | "esModuleInterop": true, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react", 18 | "baseUrl": "src" 19 | }, 20 | "include": ["src"] 21 | } 22 | -------------------------------------------------------------------------------- /gateway/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.17-alpine as dynamic_conf 2 | 3 | #------------------------------------------------------------------- 4 | FROM dynamic_conf as default_conf 5 | COPY nginx.conf /etc/nginx/nginx.conf 6 | COPY tmp/frontend/. /html/ 7 | 8 | #------------------------------------------------------------------- 9 | FROM default_conf as static_conf 10 | COPY nginx.static.conf /etc/nginx/nginx.conf -------------------------------------------------------------------------------- /gateway/nginx.conf: -------------------------------------------------------------------------------- 1 | events { 2 | worker_connections 4096; ## Default: 1024 3 | } 4 | 5 | http { 6 | server { 7 | include /etc/nginx/mime.types; 8 | server_name reference-wallet; 9 | listen 8000; 10 | keepalive_timeout 70; 11 | 12 | location /api/ { 13 | proxy_set_header X-Real-IP $remote_addr; 14 | proxy_set_header Host $host; 15 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 16 | proxy_set_header X-Forwarded-Prefix /api/; 17 | proxy_redirect off; 18 | proxy_pass http://backend-web-server:5000/; 19 | } 20 | 21 | location / { 22 | root /html; 23 | try_files $uri $uri/ /index.html; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /gateway/nginx.debug.conf: -------------------------------------------------------------------------------- 1 | events { 2 | worker_connections 4096; ## Default: 1024 3 | } 4 | 5 | http { 6 | server { 7 | resolver 127.0.0.11 valid=30s; 8 | include /etc/nginx/mime.types; 9 | server_name reference-wallet; 10 | listen 8000; 11 | keepalive_timeout 70; 12 | 13 | location /api/ { 14 | proxy_set_header X-Real-IP $remote_addr; 15 | proxy_set_header Host $host; 16 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 17 | proxy_set_header X-Forwarded-Prefix /api/; 18 | proxy_redirect off; 19 | proxy_pass http://docker-host:5000/; 20 | } 21 | 22 | location / { 23 | set $frontend_uptstream http://frontend:3000; 24 | proxy_set_header X-Real-IP $remote_addr; 25 | proxy_set_header Host $host; 26 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 27 | proxy_redirect off; 28 | proxy_pass $frontend_uptstream; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /gateway/nginx.dev.conf: -------------------------------------------------------------------------------- 1 | error_log /var/log/nginx/error.log notice; 2 | 3 | events { 4 | worker_connections 4096; ## Default: 1024 5 | } 6 | 7 | http { 8 | log_format verbose_log '[$time_local] $status ' 9 | '$request -> $proxy_host ' 10 | '"$http_referer" "$http_user_agent"'; 11 | access_log /var/log/nginx/access.log verbose_log; 12 | 13 | server { 14 | resolver 127.0.0.11 valid=30s; 15 | include /etc/nginx/mime.types; 16 | server_name reference-wallet; 17 | listen 8000; 18 | keepalive_timeout 70; 19 | 20 | location /api/ { 21 | proxy_set_header X-Real-IP $remote_addr; 22 | proxy_set_header Host $host; 23 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 24 | proxy_set_header X-Forwarded-Prefix /api/; 25 | proxy_redirect off; 26 | proxy_pass http://backend-web-server:5000/; 27 | } 28 | 29 | location / { 30 | set $frontend_uptstream http://frontend:3000; 31 | proxy_set_header X-Real-IP $remote_addr; 32 | proxy_set_header Host $host; 33 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 34 | proxy_redirect off; 35 | proxy_pass $frontend_uptstream; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /gateway/nginx.static.conf: -------------------------------------------------------------------------------- 1 | events { 2 | worker_connections 4096; ## Default: 1024 3 | } 4 | 5 | http { 6 | server { 7 | include /etc/nginx/mime.types; 8 | server_name reference-wallet; 9 | listen 8080; 10 | keepalive_timeout 70; 11 | 12 | location / { 13 | root /html; 14 | try_files $uri $uri/ /index.html; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /helm/reference-wallet/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /helm/reference-wallet/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: reference-wallet 3 | version: 1.0.0 4 | description: A Helm chart for Diem Reference Wallet 5 | type: application 6 | home: https://github.com/diem/reference-wallet 7 | icon: https://github.com/diem/diem/raw/master/developers.diem.com/static/img/diem-logo.png 8 | -------------------------------------------------------------------------------- /helm/reference-wallet/templates/frontend-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "reference-wallet.fullname" . }}-frontend 5 | labels: 6 | {{- include "reference-wallet.labels" . | nindent 4 }} 7 | app: {{ include "reference-wallet.fullname" . }}-frontend 8 | spec: 9 | type: {{ .Values.service.type }} 10 | ports: 11 | - port: {{ .Values.service.port }} 12 | targetPort: {{ .Values.service.targetPort }} 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "reference-wallet.selectorLabels" . | nindent 4 }} 17 | app: {{ include "reference-wallet.fullname" . }}-frontend 18 | -------------------------------------------------------------------------------- /helm/reference-wallet/templates/peripherals-service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.peripherals.redis.create -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "reference-wallet.fullname" . }}-redis 6 | labels: 7 | app: {{ include "reference-wallet.fullname" . }}-redis 8 | {{- include "reference-wallet.labels" . | nindent 4 }} 9 | spec: 10 | selector: 11 | app: {{ include "reference-wallet.fullname" . }}-redis 12 | {{- include "reference-wallet.selectorLabels" . | nindent 4 }} 13 | ports: 14 | - protocol: "TCP" 15 | port: {{ .Values.peripherals.redis.port }} 16 | targetPort: {{ .Values.peripherals.redis.port }} 17 | name: redis 18 | --- 19 | {{- end }} 20 | {{- if .Values.peripherals.database.create -}} 21 | apiVersion: v1 22 | kind: Service 23 | metadata: 24 | name: {{ include "reference-wallet.fullname" . }}-db 25 | labels: 26 | app: {{ include "reference-wallet.fullname" . }}-db 27 | {{- include "reference-wallet.labels" . | nindent 4 }} 28 | spec: 29 | selector: 30 | app: {{ include "reference-wallet.fullname" . }}-db 31 | {{- include "reference-wallet.selectorLabels" . | nindent 4 }} 32 | ports: 33 | - protocol: "TCP" 34 | port: {{ .Values.peripherals.database.port }} 35 | targetPort: {{ .Values.peripherals.database.port }} 36 | name: db 37 | --- 38 | {{- end }} 39 | -------------------------------------------------------------------------------- /helm/reference-wallet/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "reference-wallet.serviceAccountName" . }} 6 | labels: 7 | {{- include "reference-wallet.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /mobile/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /mobile/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /mobile/.env.example: -------------------------------------------------------------------------------- 1 | BACKEND_URL= 2 | EXPLORER_URL=https://librabrowser.io/version/{version} 3 | -------------------------------------------------------------------------------- /mobile/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native-community', 4 | parser: '@typescript-eslint/parser', 5 | plugins: ['@typescript-eslint'], 6 | }; 7 | -------------------------------------------------------------------------------- /mobile/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /mobile/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | 24 | # Android/IntelliJ 25 | # 26 | build/ 27 | .idea 28 | .gradle 29 | local.properties 30 | *.iml 31 | 32 | # Visual Studio Code 33 | # 34 | .vscode/ 35 | 36 | # node.js 37 | # 38 | node_modules/ 39 | npm-debug.log 40 | yarn-error.log 41 | 42 | # BUCK 43 | buck-out/ 44 | \.buckd/ 45 | *.keystore 46 | !debug.keystore 47 | 48 | # fastlane 49 | # 50 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 51 | # screenshots whenever they are needed. 52 | # For more information about the recommended setup visit: 53 | # https://docs.fastlane.tools/best-practices/source-control/ 54 | 55 | */fastlane/report.xml 56 | */fastlane/Preview.html 57 | */fastlane/screenshots 58 | 59 | # Bundle artifact 60 | *.jsbundle 61 | 62 | # CocoaPods 63 | /ios/Pods/ 64 | -------------------------------------------------------------------------------- /mobile/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: false, 3 | jsxBracketSameLine: true, 4 | singleQuote: true, 5 | trailingComma: 'all', 6 | }; 7 | -------------------------------------------------------------------------------- /mobile/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /mobile/README.md: -------------------------------------------------------------------------------- 1 | # LRW Mobile 2 | 3 | This project is based on [React Native](https://github.com/facebook/react-native) 4 | 5 | ## How to use? 6 | 7 | 1. Download or clone this repo. 8 | 2. Make sure your development environment is configured as described in the [React Native documentation](https://reactnative.dev/docs/environment-setup) 9 | 3. Install dependencies: 10 | 11 | ```sh 12 | yarn install 13 | ``` 14 | 15 | 4. Run the bundler: 16 | 17 | ```sh 18 | yarn start 19 | ``` 20 | 5. While the bundler is running in its own terminal, run start the app on iOS/Android: 21 | 22 | ```sh 23 | yarn ios 24 | yarn android 25 | ``` 26 | -------------------------------------------------------------------------------- /mobile/__tests__/App-test.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /** 5 | * @format 6 | */ 7 | 8 | import 'react-native'; 9 | import React from 'react'; 10 | import App from '../src/App'; 11 | 12 | // Note: test renderer must be required after react-native. 13 | import renderer from 'react-test-renderer'; 14 | 15 | it('renders correctly', () => { 16 | renderer.create(); 17 | }); 18 | -------------------------------------------------------------------------------- /mobile/android/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM circleci/android:api-29-node 2 | 3 | 4 | RUN gem install fastlane -NV 5 | RUN sdkmanager --install \ 6 | "ndk;21.3.6528147" \ 7 | "cmake;3.10.2.4988404" 8 | -------------------------------------------------------------------------------- /mobile/android/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" 4 | -------------------------------------------------------------------------------- /mobile/android/app/build_defs.bzl: -------------------------------------------------------------------------------- 1 | """Helper definitions to glob .aar and .jar targets""" 2 | 3 | def create_aar_targets(aarfiles): 4 | for aarfile in aarfiles: 5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")] 6 | lib_deps.append(":" + name) 7 | android_prebuilt_aar( 8 | name = name, 9 | aar = aarfile, 10 | ) 11 | 12 | def create_jar_targets(jarfiles): 13 | for jarfile in jarfiles: 14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")] 15 | lib_deps.append(":" + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | -------------------------------------------------------------------------------- /mobile/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/debug.keystore -------------------------------------------------------------------------------- /mobile/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /mobile/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /mobile/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/AntDesign.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/AntDesign.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/Entypo.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/EvilIcons.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/Feather.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/Feather.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/FontAwesome.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/FontAwesome5_Brands.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/FontAwesome5_Brands.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/FontAwesome5_Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/FontAwesome5_Regular.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/FontAwesome5_Solid.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/FontAwesome5_Solid.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/Fontisto.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/Fontisto.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/Foundation.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/Foundation.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/FreeSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/FreeSans-Bold.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/FreeSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/FreeSans-Regular.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/Ionicons.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/MaterialIcons.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/Octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/Octicons.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/SimpleLineIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/SimpleLineIcons.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/assets/fonts/Zocial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/assets/fonts/Zocial.ttf -------------------------------------------------------------------------------- /mobile/android/app/src/main/java/com/lrw/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.lrw; 2 | 3 | import com.reactnativenavigation.NavigationActivity; 4 | 5 | public class MainActivity extends NavigationActivity { 6 | 7 | 8 | } 9 | -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | LRW 3 | 4 | -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /mobile/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | RNNKotlinVersion = "1.3.61" 6 | buildToolsVersion = "29.0.3" 7 | minSdkVersion = 19 8 | compileSdkVersion = 29 9 | targetSdkVersion = 29 10 | } 11 | repositories { 12 | google() 13 | jcenter() 14 | } 15 | dependencies { 16 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61" 17 | classpath('com.android.tools.build:gradle:4.0.0') 18 | 19 | // NOTE: Do not place your application dependencies here; they belong 20 | // in the individual module build.gradle files 21 | } 22 | } 23 | 24 | allprojects { 25 | repositories { 26 | mavenLocal() 27 | maven { 28 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 29 | url("$rootDir/../node_modules/react-native/android") 30 | } 31 | maven { 32 | // Android JSC is installed from npm 33 | url("$rootDir/../node_modules/jsc-android/dist") 34 | } 35 | 36 | google() 37 | jcenter() 38 | maven { url 'https://www.jitpack.io' } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mobile/android/fastlane/Appfile: -------------------------------------------------------------------------------- 1 | json_key_file("/tmp/key.json") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one 2 | package_name("com.lrw") # e.g. com.krausefx.app 3 | -------------------------------------------------------------------------------- /mobile/android/fastlane/README.md: -------------------------------------------------------------------------------- 1 | fastlane documentation 2 | ================ 3 | # Installation 4 | 5 | Make sure you have the latest version of the Xcode command line tools installed: 6 | 7 | ``` 8 | xcode-select --install 9 | ``` 10 | 11 | Install _fastlane_ using 12 | ``` 13 | [sudo] gem install fastlane -NV 14 | ``` 15 | or alternatively using `brew cask install fastlane` 16 | 17 | # Available Actions 18 | ## Android 19 | ### android test 20 | ``` 21 | fastlane android test 22 | ``` 23 | Runs all the tests 24 | ### android beta 25 | ``` 26 | fastlane android beta 27 | ``` 28 | Submit a new Beta Build to Play Store 29 | 30 | ---- 31 | 32 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. 33 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). 34 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). 35 | -------------------------------------------------------------------------------- /mobile/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | # Automatically convert third-party libraries to use AndroidX 25 | android.enableJetifier=true 26 | 27 | # Version of flipper SDK to use with React Native 28 | FLIPPER_VERSION=0.33.1 29 | -------------------------------------------------------------------------------- /mobile/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /mobile/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun May 31 10:48:37 IDT 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip 7 | -------------------------------------------------------------------------------- /mobile/android/publish.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | if [[ -z ${LRW_KEYSTORE_B64+x} ]]; then 7 | echo "no keystore (base64) supplied in LRW_KEYSTORE_B64" 8 | exit -1 9 | fi 10 | 11 | if [[ -z ${GOOGLE_SERVICE_ACCOUNT_B64+x} ]]; then 12 | echo "no google service account key json (base64) supplied in GOOGLE_SERVICE_ACCOUNT_B64" 13 | exit -1 14 | fi 15 | 16 | if [[ -z ${STORE_PASSWORD+x} ]]; then 17 | echo "no keystore password supplied in STORE_PASSWORD" 18 | exit -1 19 | fi 20 | 21 | if [[ -z ${KEY_PASSWORD+x} ]]; then 22 | echo "no key entry (alias) password supplied in KEY_PASSWORD" 23 | exit -1 24 | fi 25 | 26 | if [[ -z ${VERSION_CODE+x} ]]; then 27 | echo "no version code supplied in VERSION_CODE" 28 | exit -1 29 | fi 30 | 31 | echo ${GOOGLE_SERVICE_ACCOUNT_B64} | base64 -d > /tmp/key.json 32 | echo ${LRW_KEYSTORE_B64} | base64 -d > /tmp/lrw-release-key.keystore 33 | 34 | 35 | fastlane beta -------------------------------------------------------------------------------- /mobile/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LRW", 3 | "displayName": "LRW" 4 | } -------------------------------------------------------------------------------- /mobile/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["module:metro-react-native-babel-preset"], 3 | plugins: ["transform-inline-environment-variables"], 4 | }; 5 | -------------------------------------------------------------------------------- /mobile/ios/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" 4 | -------------------------------------------------------------------------------- /mobile/ios/LRW.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /mobile/ios/LRW.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /mobile/ios/LRW/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : UIResponder 5 | 6 | @property (nonatomic, strong) UIWindow *window; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/1024.png -------------------------------------------------------------------------------- /mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/120-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/120-1.png -------------------------------------------------------------------------------- /mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/120.png -------------------------------------------------------------------------------- /mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/180.png -------------------------------------------------------------------------------- /mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/40.png -------------------------------------------------------------------------------- /mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/58.png -------------------------------------------------------------------------------- /mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/60.png -------------------------------------------------------------------------------- /mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/80.png -------------------------------------------------------------------------------- /mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/Images.xcassets/AppIcon.appiconset/87.png -------------------------------------------------------------------------------- /mobile/ios/LRW/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /mobile/ios/LRW/icons/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/icons/1024.png -------------------------------------------------------------------------------- /mobile/ios/LRW/icons/120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/icons/120.png -------------------------------------------------------------------------------- /mobile/ios/LRW/icons/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/icons/180.png -------------------------------------------------------------------------------- /mobile/ios/LRW/icons/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/icons/40.png -------------------------------------------------------------------------------- /mobile/ios/LRW/icons/58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/icons/58.png -------------------------------------------------------------------------------- /mobile/ios/LRW/icons/60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/icons/60.png -------------------------------------------------------------------------------- /mobile/ios/LRW/icons/80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/icons/80.png -------------------------------------------------------------------------------- /mobile/ios/LRW/icons/87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/ios/LRW/icons/87.png -------------------------------------------------------------------------------- /mobile/ios/LRW/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char * argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /mobile/ios/fastlane/Appfile: -------------------------------------------------------------------------------- 1 | apple_id(ENV["APPLE_ID"]) 2 | app_identifier(ENV["APPLE_APP_IDENTIFIER"]) 3 | team_id(ENV["APPLE_TEAM_ID"]) # Developer Portal Team ID 4 | -------------------------------------------------------------------------------- /mobile/ios/fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | # This file contains the fastlane.tools configuration 2 | # You can find the documentation at https://docs.fastlane.tools 3 | # 4 | # For a list of all available actions, check out 5 | # 6 | # https://docs.fastlane.tools/actions 7 | # 8 | # For a list of all available plugins, check out 9 | # 10 | # https://docs.fastlane.tools/plugins/available-plugins 11 | # 12 | 13 | # Uncomment the line if you want fastlane to automatically update itself 14 | # update_fastlane 15 | 16 | default_platform(:ios) 17 | 18 | platform :ios do 19 | before_all do 20 | setup_circle_ci 21 | end 22 | desc "Upload to Testflight" 23 | lane :beta do 24 | increment_build_number( 25 | build_number: latest_testflight_build_number( 26 | initial_build_number: 1, 27 | version: get_version_number(xcodeproj: "LRW.xcodeproj") 28 | ) + 1, 29 | ) 30 | match(type: "appstore") 31 | gym(scheme: "LRW", xcargs: "PROVISIONING_PROFILE_SPECIFIER='#{ENV['PROVISIONING_PROFILE']}'") 32 | pilot( 33 | distribute_external: true, 34 | notify_external_testers: false, 35 | changelog: "CircleCI build" 36 | ) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /mobile/ios/fastlane/Matchfile: -------------------------------------------------------------------------------- 1 | git_url(ENV["FASTLANE_MATCH_REPO"]) 2 | 3 | storage_mode("git") 4 | 5 | type("development") # The default type, can be: appstore, adhoc, enterprise or development 6 | keychain_password(ENV["FASTLANE_KEYCHAIN_PWD"]) 7 | app_identifier([ENV["APPLE_APP_IDENTIFIER"]]) 8 | username(ENV["APPLE_ID"]) # Your Apple Developer Portal username 9 | 10 | -------------------------------------------------------------------------------- /mobile/ios/fastlane/README.md: -------------------------------------------------------------------------------- 1 | fastlane documentation 2 | ================ 3 | # Installation 4 | 5 | Make sure you have the latest version of the Xcode command line tools installed: 6 | 7 | ``` 8 | xcode-select --install 9 | ``` 10 | 11 | Install _fastlane_ using 12 | ``` 13 | [sudo] gem install fastlane -NV 14 | ``` 15 | or alternatively using `brew cask install fastlane` 16 | 17 | # Available Actions 18 | ## iOS 19 | ### ios beta 20 | ``` 21 | fastlane ios beta 22 | ``` 23 | Upload to Testflight 24 | 25 | ---- 26 | 27 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. 28 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). 29 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). 30 | -------------------------------------------------------------------------------- /mobile/ios/publish.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | #!/usr/bin/env bash 5 | 6 | if [[ -z ${APPLE_ID+x} ]]; then 7 | echo "no apple id supplied in APPLE_ID" 8 | exit -1 9 | fi 10 | 11 | if [[ -z ${APPLE_APP_IDENTIFIER+x} ]]; then 12 | echo "no apple application identifier (app id) supplied in APPLE_APP_IDENTIFIER" 13 | exit -1 14 | fi 15 | 16 | if [[ -z ${APPLE_TEAM_ID+x} ]]; then 17 | echo "no apple team id supplied in APPLE_TEAM_ID" 18 | exit -1 19 | fi 20 | 21 | if [[ -z ${FASTLANE_MATCH_REPO+x} ]]; then 22 | echo "no fastlane match repo (git url with access token) supplied in FASTLANE_MATCH_REPO" 23 | exit -1 24 | fi 25 | 26 | if [[ -z ${FASTLANE_KEYCHAIN_PWD+x} ]]; then 27 | echo "no fastlane keychain password supplied in FASTLANE_KEYCHAIN_PWD" 28 | exit -1 29 | fi 30 | 31 | if [[ -z ${MATCH_PASSWORD+x} ]]; then 32 | echo "no fastlane match storage passphrase supplied in MATCH_PASSWORD" 33 | exit -1 34 | fi 35 | 36 | if [[ -z ${PROVISIONING_PROFILE+x} ]]; then 37 | echo "no xcode provisioning profile specifier supplied in PROVISIONING_PROFILE" 38 | exit -1 39 | fi 40 | 41 | #cd .. 42 | #npx yarn build:ios 43 | # 44 | #cd ios 45 | bundle exec fastlane beta --verbose 46 | -------------------------------------------------------------------------------- /mobile/metro.config.js: -------------------------------------------------------------------------------- 1 | const {getDefaultConfig} = require('metro-config'); 2 | 3 | module.exports = (async () => { 4 | const { 5 | resolver: {sourceExts, assetExts}, 6 | } = await getDefaultConfig(); 7 | return { 8 | transformer: { 9 | babelTransformerPath: require.resolve('react-native-svg-transformer'), 10 | getTransformOptions: async () => ({ 11 | transform: { 12 | experimentalImportSupport: false, 13 | inlineRequires: false, 14 | }, 15 | }), 16 | }, 17 | resolver: { 18 | assetExts: assetExts.filter((ext) => ext !== 'svg'), 19 | sourceExts: [...sourceExts, 'svg'], 20 | }, 21 | }; 22 | })(); 23 | -------------------------------------------------------------------------------- /mobile/react-native.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | project: { 3 | ios: {}, 4 | android: {}, 5 | }, 6 | assets: ["./src/assets/fonts/freesans/"], 7 | }; 8 | -------------------------------------------------------------------------------- /mobile/src/assets/back-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /mobile/src/assets/chevron.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /mobile/src/assets/fonts/freesans/FreeSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/src/assets/fonts/freesans/FreeSans-Bold.ttf -------------------------------------------------------------------------------- /mobile/src/assets/fonts/freesans/FreeSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/src/assets/fonts/freesans/FreeSans-Regular.ttf -------------------------------------------------------------------------------- /mobile/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diem/reference-wallet/e8efec4acc6af6e319cf075c10693ddf7754cc83/mobile/src/assets/logo.png -------------------------------------------------------------------------------- /mobile/src/components/DatePicker.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import ReactDatePicker from "react-native-datepicker"; 6 | import { ThemeConsumer } from "react-native-elements"; 7 | import { appTheme } from "../styles"; 8 | 9 | interface DatePickerProps { 10 | value?: string | Date; 11 | placeholder?: string; 12 | onChange?: (dateStr: string, date: Date) => void; 13 | maxDate?: string | Date; 14 | disabled?: boolean; 15 | } 16 | 17 | function DatePicker({ value, placeholder, onChange, maxDate, disabled }: DatePickerProps) { 18 | return ( 19 | > 20 | {({ theme }) => ( 21 | 35 | )} 36 | 37 | ); 38 | } 39 | 40 | export default DatePicker; 41 | -------------------------------------------------------------------------------- /mobile/src/components/ExampleSectionWarning.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { View } from "react-native"; 6 | import { Text, ThemeConsumer } from "react-native-elements"; 7 | import { useTranslation } from "react-i18next"; 8 | import { appTheme } from "../styles"; 9 | 10 | function ExampleSectionWarning() { 11 | const { t } = useTranslation("legal"); 12 | 13 | return ( 14 | > 15 | {({ theme }) => ( 16 | 17 | {t("example_section_warning")} 18 | 19 | )} 20 | 21 | ); 22 | } 23 | 24 | export default ExampleSectionWarning; 25 | -------------------------------------------------------------------------------- /mobile/src/components/ExplorerLink.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { BlockchainTransaction } from "../interfaces/blockchain"; 5 | import { Text, ThemeConsumer } from "react-native-elements"; 6 | import React from "react"; 7 | import { Linking, TouchableOpacity } from "react-native"; 8 | import { appTheme } from "../styles"; 9 | 10 | // @ts-ignore 11 | const EXPLORER_URL_FORMAT = 12 | process.env.REACT_APP_EXPLORER_URL || "https://librabrowser.io/version/{version}"; 13 | 14 | interface ExplorerLinkProps { 15 | blockchainTx: BlockchainTransaction; 16 | } 17 | 18 | function ExplorerLink({ blockchainTx }: ExplorerLinkProps) { 19 | const blockExplorerUrl = EXPLORER_URL_FORMAT.replace( 20 | "{version}", 21 | blockchainTx.version.toString() 22 | ); 23 | return ( 24 | > 25 | {({ theme }) => ( 26 | Linking.openURL(blockExplorerUrl)}> 27 | {blockchainTx.version} 28 | 29 | )} 30 | 31 | ); 32 | } 33 | 34 | export default ExplorerLink; 35 | -------------------------------------------------------------------------------- /mobile/src/components/InputErrorMessage.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { Text, ThemeConsumer } from "react-native-elements"; 6 | import { appTheme } from "../styles"; 7 | 8 | interface InputErrorMessageProps { 9 | message: string; 10 | } 11 | 12 | function InputErrorMessage({ message }: InputErrorMessageProps) { 13 | return ( 14 | > 15 | {({ theme }) => {message}} 16 | 17 | ); 18 | } 19 | 20 | export default InputErrorMessage; 21 | -------------------------------------------------------------------------------- /mobile/src/components/LegalDisclaimer.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { Text } from "react-native-elements"; 6 | import { View } from "react-native"; 7 | import { useTranslation } from "react-i18next"; 8 | 9 | function LegalDisclaimer() { 10 | const { t } = useTranslation("legal"); 11 | 12 | return ( 13 | 21 | {t("legal_disclaimer")} 22 | 23 | ); 24 | } 25 | 26 | export default LegalDisclaimer; 27 | -------------------------------------------------------------------------------- /mobile/src/components/Messages/ErrorMessage.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { Text, View } from "react-native"; 6 | import { appTheme } from "../../styles"; 7 | import { ThemeConsumer } from "react-native-elements"; 8 | 9 | interface ErrorMessageProps { 10 | message: string; 11 | } 12 | 13 | function ErrorMessage({ message }: ErrorMessageProps) { 14 | return ( 15 | > 16 | {({ theme }) => ( 17 | 18 | {message} 19 | 20 | )} 21 | 22 | ); 23 | } 24 | 25 | export default ErrorMessage; 26 | -------------------------------------------------------------------------------- /mobile/src/components/Messages/InfoMessage.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { Text, View } from "react-native"; 6 | import { appTheme } from "../../styles"; 7 | import { ThemeConsumer } from "react-native-elements"; 8 | 9 | interface InfoMessageProps { 10 | message: string; 11 | } 12 | 13 | function InfoMessage({ message }: InfoMessageProps) { 14 | return ( 15 | > 16 | {({ theme }) => ( 17 | 18 | {message} 19 | 20 | )} 21 | 22 | ); 23 | } 24 | 25 | export default InfoMessage; 26 | -------------------------------------------------------------------------------- /mobile/src/components/NetworkIndicator.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { View } from "react-native"; 6 | import { Text } from "react-native-elements"; 7 | // @ts-ignore 8 | import BackArrow from "../assets/back-arrow.svg"; 9 | 10 | interface NetworkIndicatorProps { 11 | showBack: boolean; 12 | onBackPress: () => void; 13 | } 14 | 15 | const NetworkIndicator = ({ showBack, onBackPress }: NetworkIndicatorProps) => ( 16 | 17 | {showBack && } 18 | 19 | Running on Testnet 20 | 21 | 22 | ); 23 | 24 | export default NetworkIndicator; 25 | -------------------------------------------------------------------------------- /mobile/src/components/TestnetWarning.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { StyleSheet, View } from "react-native"; 6 | import { Text, ThemeConsumer } from "react-native-elements"; 7 | import { useTranslation } from "react-i18next"; 8 | import { appTheme } from "../styles"; 9 | 10 | function TestnetWarning() { 11 | const { t } = useTranslation("legal"); 12 | 13 | return ( 14 | > 15 | {({ theme }) => ( 16 | 17 | {t("testnet_warning")} 18 | 19 | )} 20 | 21 | ); 22 | } 23 | 24 | export default TestnetWarning; 25 | -------------------------------------------------------------------------------- /mobile/src/components/VerifyingMessage.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import React from "react"; 5 | import { Text, ThemeConsumer } from "react-native-elements"; 6 | import { useTranslation } from "react-i18next"; 7 | import { appTheme } from "../styles"; 8 | import {View} from "react-native"; 9 | 10 | function VerifyingMessage() { 11 | const { t } = useTranslation("layout"); 12 | 13 | return ( 14 | > 15 | {({ theme }) => ( 16 | 17 | {t("verification_pending.title")} 18 | {t("verification_pending.description")} 19 | 20 | )} 21 | 22 | ); 23 | } 24 | 25 | export default VerifyingMessage; 26 | -------------------------------------------------------------------------------- /mobile/src/currencies.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { FiatCurrenciesSettings, DiemCurrenciesSettings } from "./interfaces/currencies"; 5 | 6 | export const diemCurrencies: DiemCurrenciesSettings = { 7 | XDM: { 8 | name: "Diem", 9 | symbol: "XDM", 10 | sign: "≋XDM", 11 | }, 12 | XUS: { 13 | name: "XUS", 14 | symbol: "XUS", 15 | sign: "≋XUS", 16 | }, 17 | Coin2: { 18 | name: "Coin2", 19 | symbol: "Coin2", 20 | sign: "≋Coin2", 21 | }, 22 | }; 23 | 24 | export const fiatCurrencies: FiatCurrenciesSettings = { 25 | USD: { 26 | symbol: "USD", 27 | sign: "$", 28 | }, 29 | EUR: { 30 | symbol: "EUR", 31 | sign: "€", 32 | }, 33 | GBP: { 34 | symbol: "GBP", 35 | sign: "£", 36 | }, 37 | CHF: { 38 | symbol: "CHF", 39 | sign: "Fr", 40 | }, 41 | CAD: { 42 | symbol: "CAD", 43 | sign: "$", 44 | }, 45 | AUD: { 46 | symbol: "AUD", 47 | sign: "$", 48 | }, 49 | NZD: { 50 | symbol: "NZD", 51 | sign: "$", 52 | }, 53 | JPY: { 54 | symbol: "JPY", 55 | sign: "¥", 56 | }, 57 | }; 58 | -------------------------------------------------------------------------------- /mobile/src/i18n.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import i18next from "i18next"; 5 | import { initReactI18next } from "react-i18next"; 6 | import LocaleResources from "./locales"; 7 | 8 | i18next.use(initReactI18next).init({ 9 | interpolation: { escapeValue: false }, // React already does escaping, 10 | lng: "en", 11 | debug: true, 12 | resources: LocaleResources, 13 | }); 14 | 15 | export const Languages = Object.keys(LocaleResources); 16 | 17 | export default i18next; 18 | -------------------------------------------------------------------------------- /mobile/src/interfaces/account.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { DiemCurrency } from "./currencies"; 5 | 6 | export interface DiemCurrencyBalance { 7 | currency: DiemCurrency; 8 | balance: number; 9 | } 10 | 11 | export interface Account { 12 | balances: DiemCurrencyBalance[]; 13 | } 14 | -------------------------------------------------------------------------------- /mobile/src/interfaces/blockchain.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export interface BlockchainTransaction { 5 | version: number; 6 | status: string; 7 | expirationTime: string; 8 | source: string; 9 | destination: string; 10 | amount: number; 11 | sequenceNumber: number; 12 | } 13 | -------------------------------------------------------------------------------- /mobile/src/interfaces/cico.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export type QuoteAction = "buy" | "sell"; 5 | 6 | export interface RequestForQuote { 7 | action: QuoteAction; 8 | amount: number; 9 | currency_pair: string; // FIXME: specify the supported values 10 | } 11 | 12 | export interface Quote { 13 | quoteId: string; 14 | rfq: RequestForQuote; 15 | price: number; 16 | expirationTime: Date; 17 | } 18 | 19 | export interface Rate { 20 | currency_pair: string; 21 | price: number; 22 | } 23 | -------------------------------------------------------------------------------- /mobile/src/interfaces/currencies.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export type DiemCurrency = "XDM" | "XUS" | "Coin2"; 5 | 6 | export type FiatCurrency = "USD" | "EUR" | "GBP" | "CHF" | "CAD" | "AUD" | "NZD" | "JPY"; 7 | 8 | export type DiemCurrenciesSettings = { 9 | [key in DiemCurrency]: { 10 | name: string; 11 | symbol: DiemCurrency; 12 | sign: string; 13 | }; 14 | }; 15 | 16 | export type FiatCurrenciesSettings = { 17 | [key in FiatCurrency]: { 18 | symbol: FiatCurrency; 19 | sign: string; 20 | }; 21 | }; 22 | 23 | export type Rates = { 24 | [key in DiemCurrency]: { 25 | [key in FiatCurrency | DiemCurrency]: number; 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /mobile/src/interfaces/transaction.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { DiemCurrency } from "./currencies"; 5 | import { BlockchainTransaction } from "./blockchain"; 6 | 7 | export interface VASPAccount { 8 | vasp_name: string; 9 | user_id: string; 10 | full_addr: string; 11 | } 12 | 13 | export type TransactionDirection = "received" | "sent"; 14 | 15 | export type TransactionStatus = "completed" | "pending" | "canceled"; 16 | 17 | export interface Transaction { 18 | id: string; 19 | direction: TransactionDirection; 20 | status: TransactionStatus; 21 | currency: DiemCurrency; 22 | source: VASPAccount; 23 | destination: VASPAccount; 24 | amount: number; 25 | blockchain_tx?: BlockchainTransaction; 26 | timestamp: string; 27 | is_internal: boolean; 28 | } 29 | -------------------------------------------------------------------------------- /mobile/src/interfaces/user.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Moment } from "moment"; 5 | import { FiatCurrency } from "./currencies"; 6 | 7 | export enum RegistrationStatus { 8 | Registered = "Registered", 9 | Verified = "Verified", 10 | Pending = "Pending", 11 | Approved = "Approved", 12 | Rejected = "Rejected", 13 | } 14 | 15 | export type PaymentMethodProviders = "BankAccount" | "CreditCard"; 16 | 17 | export const paymentMethodsLabels: { [key in PaymentMethodProviders]: string } = { 18 | BankAccount: "Bank Account", 19 | CreditCard: "Credit Card", 20 | }; 21 | 22 | export interface PaymentMethod { 23 | id: number; 24 | name: string; 25 | provider: PaymentMethodProviders; 26 | token: string; 27 | } 28 | 29 | export type NewPaymentMethod = Pick; 30 | 31 | export interface UserInfo { 32 | selected_fiat_currency: FiatCurrency; 33 | selected_language: string; 34 | first_name: string; 35 | last_name: string; 36 | dob: Moment | string; 37 | phone: string; 38 | country?: string; 39 | address_1: string; 40 | address_2: string; 41 | city: string; 42 | state: string; 43 | zip: string; 44 | } 45 | 46 | export interface User extends UserInfo { 47 | username: string; 48 | is_admin: boolean; 49 | registration_status: RegistrationStatus; 50 | paymentMethods?: PaymentMethod[]; 51 | } 52 | -------------------------------------------------------------------------------- /mobile/src/locales/en/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import Layout from "./layout.json"; 5 | import Auth from "./auth.json"; 6 | import Verify from "./verify.json"; 7 | import Transaction from "./transaction.json"; 8 | import Transfer from "./transfer.json"; 9 | import Send from "./send.json"; 10 | import Receive from "./receive.json"; 11 | import Validations from "./validations.json"; 12 | import Settings from "./settings.json"; 13 | import Legal from "./legal.json"; 14 | 15 | export default { 16 | layout: Layout, 17 | auth: Auth, 18 | verify: Verify, 19 | transaction: Transaction, 20 | send: Send, 21 | receive: Receive, 22 | transfer: Transfer, 23 | validations: Validations, 24 | settings: Settings, 25 | legal: Legal, 26 | }; 27 | -------------------------------------------------------------------------------- /mobile/src/locales/en/layout.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Diem Wallet", 3 | "total_balance": "Total Balance", 4 | "balances": "Your Balances", 5 | "transactions": "Latest Transactions", 6 | "transactions_empty": "You don’t have any transactions yet. Once you send, request or transfer money, the transactions will appear here.", 7 | "all_transactions": "All Transactions", 8 | "all_transactions_link": "See All", 9 | "all_currencies": "All Currencies", 10 | "all_sorts": "All Sorts", 11 | "price": "Currently equal to", 12 | "close": "Close", 13 | "actions": { 14 | "send": "Send", 15 | "request": "Request", 16 | "transfer": "Transfer", 17 | "settings": "Settings" 18 | }, 19 | "verification_pending": { 20 | "title": "Verification Pending", 21 | "description": "Your information is being reviewed. We’ll let you know when it’s complete." 22 | }, 23 | "feedback": { 24 | "title": "Leave your feedback", 25 | "text": "Feedback" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /mobile/src/locales/en/legal.json: -------------------------------------------------------------------------------- 1 | { 2 | "legal_disclaimer": "This is a demonstration wallet with no actual users. Do not use any username and/or password you use for other services. Create a test account instead. The compliance processes depicted in this demo wallet are for demonstration purposes only and do not reflect the specific compliance obligations of VASPs under applicable regulatory frameworks, their compliance programs, and/or standards imposed by Diem Networks.", 3 | "example_section_warning": "Example section. No real data required", 4 | "testnet_warning": "This demonstration wallet does not use real money" 5 | } -------------------------------------------------------------------------------- /mobile/src/locales/en/receive.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "headline": "Select Digital Currency", 4 | "currency_label": "Each one of your digital currencies has a different address.", 5 | "currency": "Currency", 6 | "scan_qr": "Scan QR", 7 | "text": "You can copy your unique address and give it to the person you’d like to receive money from. Or others can read the address by scanning the QR code.", 8 | "copy": "Copy Address", 9 | "copied": "Copied <1 />" 10 | } 11 | -------------------------------------------------------------------------------- /mobile/src/locales/en/send.json: -------------------------------------------------------------------------------- 1 | { 2 | "success_message": "Your transaction is on the way!", 3 | "fail_message": "Failed to send transaction", 4 | "form": { 5 | "title": "Send Money", 6 | "diemCurrency": "currency", 7 | "diemCurrency_placeholder": "Select a currency", 8 | "fiatCurrency": "fiat currency", 9 | "amount": "Amount", 10 | "price": "currently equal to", 11 | "address": "recipient", 12 | "address_placeholder": "Enter an address", 13 | "exchange_rate": "Exchange rate", 14 | "review": "Review" 15 | }, 16 | "review": { 17 | "title": "Review Transaction", 18 | "description": "Please review your transaction. Once you send money, the transaction can’t be reversed.", 19 | "amount": "You’re sending", 20 | "price": "Currently equal to", 21 | "exchange_rate": "Exchange rate", 22 | "address": "To", 23 | "confirm": "Send", 24 | "done": "Done", 25 | "back": "Back" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /mobile/src/locales/en/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Settings", 3 | "success_message": "Settings saved successfully!", 4 | "payment_methods": { 5 | "title": "Payment Methods", 6 | "credit_cards": { 7 | "title": "Credit Cards", 8 | "not_found": "You haven't added a credit card yet", 9 | "add": "Add New", 10 | "form": { 11 | "title": "Add Credit Card", 12 | "number": "Card number", 13 | "name": "Name", 14 | "expiry": "Valid Thru", 15 | "cvc": "CVC", 16 | "submit": "Add New Credit Card" 17 | } 18 | }, 19 | "bank_accounts": { 20 | "title": "Bank Accounts", 21 | "not_found": "You haven't added a bank account yet", 22 | "add": "Add New", 23 | "form": { 24 | "title": "Add Bank Account", 25 | "account_number": "Account Number", 26 | "bank": "Bank", 27 | "name": "Name", 28 | "submit": "Add New Bank Account" 29 | } 30 | } 31 | }, 32 | "preferences": { 33 | "general": { 34 | "title": "General", 35 | "email": "Your email" 36 | }, 37 | "form": { 38 | "title": "Preferences", 39 | "fiat_currency": "Local currency", 40 | "language": "Language", 41 | "submit": "Save Settings" 42 | } 43 | }, 44 | "signout": "Logout" 45 | } -------------------------------------------------------------------------------- /mobile/src/locales/en/transaction.json: -------------------------------------------------------------------------------- 1 | { 2 | "sent": "Sent", 3 | "received": "Received", 4 | "price": "Currently equal to", 5 | "date": "Date", 6 | "to": "to", 7 | "from": "from", 8 | "sent_to": "Sent to", 9 | "sent_from": "Sent from", 10 | "status": "Status", 11 | "tx_id": "Diem Transaction ID", 12 | "internal": "Internal", 13 | "not_available": "Not available" 14 | } 15 | -------------------------------------------------------------------------------- /mobile/src/locales/en/validations.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": "Please enter {{field}}", 3 | "min": "Please enter {{field}} above {{min}}", 4 | "max": "Please enter {{field}} below {{max}}", 5 | "minLength": "Please enter {{field}} longer than {{minLength}}", 6 | "maxLength": "Please enter {{field}} shorter than {{maxLength}}", 7 | "pattern": "Please enter valid {{field}}", 8 | "numbersOnly": "Please enter {{field}} with numbers only", 9 | "validDate": "Please enter a valid date", 10 | "pastDateOnly": "Please enter a date in the past", 11 | "noEqualCurrencies": "Please select different currencies", 12 | "noMoreThanBalance": "Please enter {{field}} less than your current {{currency}} balance" 13 | } 14 | -------------------------------------------------------------------------------- /mobile/src/locales/es/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import Layout from "./layout.json"; 5 | import Auth from "./auth.json"; 6 | import Verify from "./verify.json"; 7 | import Transaction from "./transaction.json"; 8 | import Transfer from "./transfer.json"; 9 | import Send from "./send.json"; 10 | import Receive from "./receive.json"; 11 | import Validations from "./validations.json"; 12 | import Settings from "./settings.json"; 13 | 14 | export default { 15 | layout: Layout, 16 | auth: Auth, 17 | verify: Verify, 18 | transaction: Transaction, 19 | send: Send, 20 | receive: Receive, 21 | transfer: Transfer, 22 | validations: Validations, 23 | settings: Settings, 24 | }; 25 | -------------------------------------------------------------------------------- /mobile/src/locales/es/layout.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Cartera Diem", 3 | "total_balance": "Saldo Total", 4 | "balances": "Ver sus saldos", 5 | "transactions": "'Últimas transacciones'", 6 | "transactions_empty": "Aún no tienes ninguna transacción. Una vez que envíe, solicite o transfiera dinero, las transacciones aparecerán aquí.", 7 | "all_transactions": "Todas las Transacciones", 8 | "all_transactions_link": "Ver todo", 9 | "all_currencies": "Todas las monedas", 10 | "all_sorts": "Todo tipo", 11 | "price": "Actualmente igual a", 12 | "close": "Cerrar", 13 | "actions": { 14 | "send": "Enviar", 15 | "request": "Solicitud", 16 | "transfer": "Transferir", 17 | "settings": "Configuración" 18 | }, 19 | "verification_pending": { 20 | "title": "Verificación pendiente", 21 | "description": "Su información está siendo revisada. Te avisaremos cuando esté completo." 22 | }, 23 | "feedback": { 24 | "title": "Deje sus comentarios", 25 | "text": "Comentarios" 26 | } 27 | } -------------------------------------------------------------------------------- /mobile/src/locales/es/receive.json: -------------------------------------------------------------------------------- 1 | { 2 | "headline": "Seleccionar moneda digital", 3 | "currency_label": "Cada una de sus monedas digitales tiene una dirección diferente.", 4 | "currency": "Divisa", 5 | "scan_qr": "Escanea el código QR", 6 | "text": "Puede copiar su dirección única y dársela a la persona de la que desea recibir dinero. O otros pueden leer la dirección escaneando el código QR.", 7 | "copy": "Copiar dirección", 8 | "copied": "Copiado <1 />" 9 | } -------------------------------------------------------------------------------- /mobile/src/locales/es/send.json: -------------------------------------------------------------------------------- 1 | { 2 | "success_message": "Su transacción está en camino!", 3 | "fail_message": "Error al enviar la transacción", 4 | "form": { 5 | "title": "Enviar Dinero a Usuario", 6 | "diemCurrency": "moneda", 7 | "diemCurrency_placeholder": "Selecciona una moneda", 8 | "fiatCurrency": "Moneda Fiat", 9 | "amount": "Cantidad", 10 | "price": "actualmente igual a", 11 | "address": "destinatario", 12 | "address_placeholder": "Ingresar Dirección", 13 | "exchange_rate": "Tipo de cambio", 14 | "review": "Revisión" 15 | }, 16 | "review": { 17 | "title": "Revisar transacción", 18 | "description": "Por favor revise su transacción. Una vez que envía dinero, la transacción no se puede revertir.", 19 | "amount": "Estas enviando", 20 | "price": "Actualmente igual a", 21 | "exchange_rate": "Tipo de cambio", 22 | "address": "Para", 23 | "confirm": "Enviar", 24 | "done": "Listo", 25 | "back": "Volver" 26 | } 27 | } -------------------------------------------------------------------------------- /mobile/src/locales/es/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Configuración", 3 | "success_message": "Ajustes guardados correctamente!", 4 | "payment_methods": { 5 | "title": "Formas de pago", 6 | "credit_cards": { 7 | "title": "Tarjetas de Crédito", 8 | "not_found": "Aún no ha agregado una tarjeta de crédito", 9 | "add": "Añadir nueva", 10 | "form": { 11 | "title": "Añadir una tarjeta de crédito", 12 | "number": "Número de la tarjeta", 13 | "name": "Nombre", 14 | "expiry": "Válida hasta", 15 | "cvc": "CVC", 16 | "submit": "Añadir nueva tarjeta de crédito" 17 | } 18 | }, 19 | "bank_accounts": { 20 | "title": "Cuentas Bancarias", 21 | "not_found": "Aún no ha agregado una cuenta bancaria", 22 | "add": "Añadir nueva", 23 | "form": { 24 | "title": "Añadir cuenta bancaria", 25 | "account_number": "Numero de Tarjeta de Banco", 26 | "bank": "Banco", 27 | "name": "Nombre", 28 | "submit": "Nueva cuenta bancaria" 29 | } 30 | } 31 | }, 32 | "preferences": { 33 | "general": { 34 | "title": "General", 35 | "email": "Su correo electrónico" 36 | }, 37 | "form": { 38 | "title": "Preferencias", 39 | "fiat_currency": "Moneda local", 40 | "language": "Idioma", 41 | "submit": "Salvar configuración" 42 | } 43 | }, 44 | "signout": "Cerrar Sesión" 45 | } -------------------------------------------------------------------------------- /mobile/src/locales/es/transaction.json: -------------------------------------------------------------------------------- 1 | { 2 | "sent": "Enviado", 3 | "received": "Recibido", 4 | "price": "Actualmente igual a", 5 | "date": "Fecha", 6 | "to": "a", 7 | "from": "desde", 8 | "sent_to": "Enviar a", 9 | "sent_from": "Enviado desde", 10 | "status": "Estatus", 11 | "tx_id": "ID de transacción de Diem", 12 | "internal": "Interna", 13 | "not_available": "No disponible" 14 | } -------------------------------------------------------------------------------- /mobile/src/locales/es/validations.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": "Por favor, complete el campo:", 3 | "min": "Ingrese {{field}} arriba {{min}}", 4 | "max": "Ingrese {{field}} debajo de {{max}}", 5 | "minLength": "Ingrese {{field}} más de {{minLength}}", 6 | "maxLength": "Ingrese {{field}} más corto que {{maxLength}}", 7 | "pattern": "Introduzca el campo válido", 8 | "numbersOnly": "Ingrese {{field}} solo con números", 9 | "validDate": "Por favor, introduzca una fecha válida", 10 | "pastDateOnly": "Por favor introduce una fecha de inicio en el pasado.", 11 | "noEqualCurrencies": "Por favor seleccione diferentes monedas", 12 | "noMoreThanBalance": "Ingrese {{field}} menos que su saldo actual de {{currency}}" 13 | } -------------------------------------------------------------------------------- /mobile/src/locales/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Resource } from "i18next"; 5 | import EN from "./en"; 6 | import ES from "./es"; 7 | 8 | export default { 9 | en: EN, 10 | es: ES, 11 | } as Resource; 12 | -------------------------------------------------------------------------------- /mobile/src/screens/VerifySteps/interfaces.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Moment } from "moment"; 5 | import { FiatCurrency } from "../../interfaces/currencies"; 6 | 7 | export interface IdentityInfo extends Record { 8 | first_name: string; 9 | last_name: string; 10 | dob: string | Moment; 11 | phone_prefix: string; 12 | phone_number: string; 13 | } 14 | 15 | export interface CountryInfo extends Record { 16 | country: string; 17 | } 18 | 19 | export interface AddressInfo extends Record { 20 | address_1: string; 21 | address_2: string; 22 | city: string; 23 | state: string; 24 | zip: string; 25 | } 26 | 27 | export interface DefaultSettings extends Record { 28 | default_fiat_currency: FiatCurrency; 29 | } 30 | -------------------------------------------------------------------------------- /mobile/src/services/errors.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export interface ErrorMessage { 5 | error: string; 6 | code: number; 7 | } 8 | 9 | export class BackendError extends Error { 10 | constructor(message: string, public httpStatus: number) { 11 | super(message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /mobile/src/services/sessionStorage.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import AsyncStorage from "@react-native-community/async-storage"; 5 | 6 | class SessionStorage { 7 | async storeAccessToken(token: string): Promise { 8 | await AsyncStorage.setItem("token", token); 9 | } 10 | 11 | async getAccessToken(): Promise { 12 | const token = await AsyncStorage.getItem("token"); 13 | if (!token) { 14 | return undefined; 15 | } 16 | return token; 17 | } 18 | 19 | async removeAccessToken(): Promise { 20 | await AsyncStorage.removeItem("token"); 21 | } 22 | } 23 | 24 | export default new SessionStorage(); 25 | -------------------------------------------------------------------------------- /mobile/src/utils/shorten-address.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export function shortenDiemAddress(address: string): string { 5 | const len = 6; 6 | return address.substr(0, len) + "...." + address.substr(len * -1); 7 | } 8 | -------------------------------------------------------------------------------- /scripts/compile_frontend.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | script_dir="$(dirname "$0")" 7 | project_dir="$(dirname "$script_dir")" 8 | 9 | docker build -t reference-wallet-frontend-build -f "${project_dir}/frontend/Dockerfile" "${project_dir}/frontend/" 10 | -------------------------------------------------------------------------------- /scripts/funcs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | NC='\033[0m' 7 | RED='\033[0;31m' 8 | GREEN='\033[0;32m' 9 | PINK='\033[1;35m' 10 | YELLOW='\033[0;33m' 11 | 12 | ## 13 | # More consistent echo. 14 | # 15 | ec() { 16 | IFS=' ' printf "%b\n" "$*" 17 | } 18 | 19 | ## 20 | # Outputs new line. 21 | # No parameters. 22 | # 23 | br() { 24 | ec '' 25 | } 26 | 27 | success() { 28 | ec "${GREEN}$1${NC}" 29 | } 30 | 31 | info() { 32 | ec "${PINK}$1${NC}" 33 | } 34 | 35 | warn() { 36 | ec "${YELLOW}$1${NC}" 37 | } 38 | 39 | error() { 40 | >&2 ec "${RED}ERROR: $1${NC}" 41 | } 42 | 43 | fail() { 44 | error "$@" 45 | exit 1 46 | } 47 | -------------------------------------------------------------------------------- /scripts/install-git-hooks.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | 7 | # This is the list of existing hook scripts 8 | # All the hook scripts must be inside scripts directory 9 | hooks=pre-commit 10 | 11 | a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.} 12 | scripts_dir=$(cd "$a"; pwd) 13 | 14 | get_path="git rev-parse --git-path hooks" 15 | 16 | for hook in "${hooks}"; do 17 | echo Installing ${hook} 18 | cp ${scripts_dir}/${hook} $(${get_path})/${hook} || exit 1 19 | done 20 | 21 | echo Done. 22 | 23 | -------------------------------------------------------------------------------- /scripts/wait_for_server_ready.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | set -euo pipefail 7 | 8 | service_num=$1 9 | 10 | for attempt in {1..60} ; do 11 | logs=$(docker ps -a | awk '{ print $1 }' | awk 'NR>1' | xargs -L1 -I {} sh -c "docker logs {} 2>&1 | tail -1") 12 | lines=$(echo "$logs"| wc -l) 13 | echo "tail logs lines: $lines, expect: $service_num" 14 | unreachable=$(echo "$logs"| grep unreachable || true) 15 | echo "unreachable: $unreachable" 16 | if [ $lines -ge $service_num ]; then 17 | if [ -z "$unreachable" ]; then 18 | echo "All services reachable" 19 | exit 0 20 | fi 21 | fi 22 | 23 | echo "Attempt $attempt, some services still unreachable" 24 | sleep 3 25 | done 26 | echo "Services unhealthy" 27 | exit 1 28 | -------------------------------------------------------------------------------- /vasp-validator/.env.example: -------------------------------------------------------------------------------- 1 | VALIDATOR_URL=http://localhost:45461/api 2 | TESTEE_URL=http://localhost:48163/api 3 | -------------------------------------------------------------------------------- /vasp-validator/.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 88 3 | extend-ignore = E203 4 | -------------------------------------------------------------------------------- /vasp-validator/Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | diem-vasp-validator = {editable = true, path = "."} 8 | diem = {editable = true, git = "https://github.com/firstdag/client-sdk-python.git", ref = "dip-8"} 9 | flake8 = "*" 10 | black = "*" 11 | 12 | [packages] 13 | 14 | [requires] 15 | python_version = "3.7" 16 | 17 | [pipenv] 18 | allow_prereleases = true 19 | -------------------------------------------------------------------------------- /vasp-validator/lint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright (c) The Diem Core Contributors 5 | # SPDX-License-Identifier: Apache-2.0 6 | # 7 | 8 | echo "> Running Black" 9 | pipenv run black src tests 10 | echo 11 | 12 | echo "> Running flake8" 13 | pipenv run flake8 src tests 14 | -------------------------------------------------------------------------------- /vasp-validator/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | log_cli_level = INFO 3 | log_format = %(levelname)-7s [%(name)s] %(message)s 4 | -------------------------------------------------------------------------------- /vasp-validator/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import os 5 | 6 | from setuptools import setup 7 | 8 | this_directory = os.path.abspath(os.path.dirname(__file__)) 9 | with open(os.path.join(this_directory, "README.md"), encoding="utf-8") as f: 10 | long_description = f.read() 11 | 12 | setup( 13 | name="diem-vasp-validator", 14 | version="1.0.0", 15 | description="Diem VASP validation library", 16 | long_description=long_description, 17 | long_description_content_type="text/markdown", 18 | license="Apache-2.0", 19 | url="https://github.com/diem/reference-wallet", 20 | package_dir={"": "src"}, 21 | packages=["vasp_validator"], 22 | install_requires=[ 23 | "diem>=1.1.0,<2.0.0", 24 | "dataclasses_json", 25 | "requests", 26 | "pytest", 27 | ], 28 | entry_points={ 29 | "console_scripts": [ 30 | "validate-vasp = vasp_validator.tests:automatic_validation_main", 31 | ], 32 | }, 33 | python_requires=">=3.7", 34 | ) 35 | -------------------------------------------------------------------------------- /vasp-validator/src/vasp_validator/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from .validator_client import ValidatorClient 5 | 6 | __all__ = [ 7 | ValidatorClient, 8 | ] 9 | -------------------------------------------------------------------------------- /vasp-validator/src/vasp_validator/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import argparse 5 | import pytest 6 | 7 | 8 | def parse_args(): 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument( 11 | "vasp_proxy_module", 12 | help="Module path containing vasp_proxy_class", 13 | ) 14 | parser.add_argument( 15 | "vasp_proxy_class", 16 | help="Instances of this class will be used to communicate with the tested VASP", 17 | ) 18 | return parser.parse_args() 19 | 20 | 21 | def automatic_validation_main(): 22 | args = parse_args() 23 | pytest.main( 24 | [ 25 | "-p", 26 | "vasp_validator.tests.plugin", 27 | "--pyargs", 28 | "vasp_validator.tests.test_send_tx", 29 | "--vasp-proxy-module", 30 | args.vasp_proxy_module, 31 | "--vasp-proxy-class", 32 | args.vasp_proxy_class, 33 | ] 34 | ) 35 | -------------------------------------------------------------------------------- /vasp-validator/src/vasp_validator/tests/plugin.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from . import vasp_proxy_hook 5 | 6 | 7 | def pytest_addoption(parser, pluginmanager): 8 | parser.addoption( 9 | "--vasp-proxy-module", 10 | dest="vasp_proxy_module", 11 | help="Module path containing vasp-proxy-class", 12 | ) 13 | parser.addoption( 14 | "--vasp-proxy-class", 15 | dest="vasp_proxy_class", 16 | help="Instances of this class will be used to communicate with the tested VASP", 17 | ) 18 | 19 | 20 | def pytest_addhooks(pluginmanager): 21 | pluginmanager.add_hookspecs(vasp_proxy_hook) 22 | -------------------------------------------------------------------------------- /vasp-validator/src/vasp_validator/tests/vasp_proxy_hook.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from pytest import hookspec 5 | 6 | from ..vasp_proxy import VaspProxy 7 | 8 | 9 | @hookspec(firstresult=True) 10 | def pytest_create_vasp_proxy() -> VaspProxy: 11 | """ 12 | Controls which testee VASP object will be used during the tests 13 | """ 14 | -------------------------------------------------------------------------------- /vasp-validator/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright (c) The Diem Core Contributors 5 | # SPDX-License-Identifier: Apache-2.0 6 | # 7 | 8 | # If first argument is not a flag, it's a subtest selector 9 | if [ -n "${1}" ] && [ "${1#-}" = "${1}" ]; then 10 | subtests=$1 11 | shift 12 | fi 13 | 14 | tests_selector=vasp_validator.tests${subtests:+.}${subtests} 15 | pipenv run pytest -r A -p vasp_validator.tests.plugin --pyargs ${tests_selector} "$@" ./tests 16 | -------------------------------------------------------------------------------- /vasp-validator/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /vasp-validator/tests/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import os 5 | 6 | from vasp_validator.vasp_proxy import VaspProxy 7 | from .vasp_proxy_testee import VaspProxyTestee 8 | 9 | TESTEE_URL = os.environ["TESTEE_URL"] 10 | 11 | 12 | def pytest_create_vasp_proxy() -> VaspProxy: 13 | """ 14 | This is a hook function used by vasp_validator plugin. 15 | If defined, it will be called to created instances of the VASP proxy object. 16 | """ 17 | return VaspProxyTestee(TESTEE_URL) 18 | -------------------------------------------------------------------------------- /vasp-validator/tests/test_vasp_proxy_hook.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) The Diem Core Contributors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | def test_tautology(): 6 | ... 7 | -------------------------------------------------------------------------------- /wait.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (c) The Diem Core Contributors 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | HOST=$1 7 | PORT=$2 8 | 9 | if [ -z $HOST ] || [ -z $PORT ]; then 10 | echo "Missing HOST or PORT" 11 | exit 1 12 | fi 13 | 14 | for attempt in {1..60} ; do 15 | nc -z $HOST $PORT && echo "Ping successful!" && exit 0 || sleep 3 16 | echo "Attempt $attempt: $HOST:$PORT unreachable, sleeping..." 17 | done 18 | echo "ERROR: timed out" 19 | exit 1 20 | --------------------------------------------------------------------------------