From d97e06a042d614cca24b0307da3c70b18db57b0e Mon Sep 17 00:00:00 2001
From: Binz
Date: Thu, 16 Jun 2022 14:14:41 +0700
Subject: [PATCH 01/15] tmp commit
---
.../recipient/recipient.component.html | 9 ++++-
.../recipient/recipient.component.scss | 6 ++++
.../recipient/recipient.component.ts | 21 +++++++++++-
.../components/recipient/recipient.model.ts | 1 +
.../add/create-wallet/create-wallet.html | 4 +--
src/app/pages/home/home.ts | 33 +++++++++++++++++++
src/app/pages/send/confirm/confirm.ts | 4 +--
src/app/pages/send/send.ts | 5 +--
.../pages/wallet-details/wallet-details.html | 3 ++
src/app/providers/persistence/persistence.ts | 9 +++++
src/app/providers/wallet/wallet.ts | 1 +
11 files changed, 88 insertions(+), 8 deletions(-)
diff --git a/src/app/components/recipient/recipient.component.html b/src/app/components/recipient/recipient.component.html
index ced36cbf8f9..56a1d1c376a 100644
--- a/src/app/components/recipient/recipient.component.html
+++ b/src/app/components/recipient/recipient.component.html
@@ -34,7 +34,14 @@
{{unit}}
{{unit}}
- {{recipient.altAmountStr}} {{alternativeUnit}}
+
+
+
+
+
+ {{Buffer.from(this.message).length}} / 206
{{'Send total selected amount' | translate}}
diff --git a/src/app/components/recipient/recipient.component.scss b/src/app/components/recipient/recipient.component.scss
index 5e21a2b07cd..bf8050da668 100644
--- a/src/app/components/recipient/recipient.component.scss
+++ b/src/app/components/recipient/recipient.component.scss
@@ -82,6 +82,12 @@ recipient-component {
font-size: 16px;
}
+ ion-textarea{
+ --placeholder-color: rgba(0, 30, 46, 0.38);
+ --color: #001E2E;
+ font-size: 16px;
+ }
+
.scan-icon {
width: 20px;
height: 20px;
diff --git a/src/app/components/recipient/recipient.component.ts b/src/app/components/recipient/recipient.component.ts
index 61ec010e5d6..17d5195cebb 100644
--- a/src/app/components/recipient/recipient.component.ts
+++ b/src/app/components/recipient/recipient.component.ts
@@ -61,6 +61,7 @@ export class RecipientComponent implements OnInit {
public searchValue: string;
validAddress = false;
validAmount = false;
+ validMessage = true;
isSelectedTotalAmout: boolean = false;
remaining: number;
isShowReceiveLotus: boolean;
@@ -68,6 +69,9 @@ export class RecipientComponent implements OnInit {
receiveAmountLotus: number;
formatRemaining: string;
messagesReceiveLotus: boolean = false;
+
+ message='';
+ Buffer = Buffer;
@Input()
recipient: RecipientModel;
@@ -206,6 +210,21 @@ export class RecipientComponent implements OnInit {
this.updateUnitUI(!!isToken);
}
+ changeMessage(){
+ if(Buffer.from(this.message).length > 206) {
+ if(this.validMessage){
+ this.validMessage = false;
+ this.checkRecipientValid();
+ }
+ } else{
+ this.recipient.message = this.message;
+ if(!this.validMessage){
+ this.validMessage = true;
+ this.checkRecipientValid();
+ }
+ }
+ }
+
private updateAddressHandler: any = data => {
if (data.recipientId === this.recipient.id) {
this.searchValue = data.value;
@@ -581,7 +600,7 @@ export class RecipientComponent implements OnInit {
checkRecipientValid() {
if (!this.isDonation) {
- this.recipient.isValid = this.validAddress && this.validAmount;
+ this.recipient.isValid = this.validAddress && this.validAmount && this.validMessage;
} else {
if (this.isShowReceiveLotus) {
this.recipient.isValid = this.validAddress && this.validAmount;
diff --git a/src/app/components/recipient/recipient.model.ts b/src/app/components/recipient/recipient.model.ts
index 1850e4d6e92..7868d2ddd0a 100644
--- a/src/app/components/recipient/recipient.model.ts
+++ b/src/app/components/recipient/recipient.model.ts
@@ -3,6 +3,7 @@ export class RecipientModel {
public amount: number;
public amountToShow: string;
public altAmountStr: string;
+ public message?: string;
public isValid?: boolean;
public id?: number = Date.now();
public name?:string;
diff --git a/src/app/pages/add/create-wallet/create-wallet.html b/src/app/pages/add/create-wallet/create-wallet.html
index 93759562518..4d41b575fb4 100755
--- a/src/app/pages/add/create-wallet/create-wallet.html
+++ b/src/app/pages/add/create-wallet/create-wallet.html
@@ -108,12 +108,12 @@
-
+
Segwit
-
+
{{'Wallet Service URL' | translate}}
diff --git a/src/app/pages/home/home.ts b/src/app/pages/home/home.ts
index 3bdddc520c8..1f8d565ad43 100644
--- a/src/app/pages/home/home.ts
+++ b/src/app/pages/home/home.ts
@@ -253,6 +253,7 @@ export class HomePage {
ngOnInit() {
this.preFetchWallets();
+
//Detect Change theme
this.themeProvider.themeChange.subscribe(() => {
this.currentTheme = this.appProvider.themeProvider.currentAppTheme;
@@ -260,6 +261,9 @@ export class HomePage {
setTimeout(() => {
this.getWalletGroupsHome();
}, 2900);
+ setTimeout(() => {
+ this.doMigrateMessageOnchainProcess();
+ }, 3200);
// Required delay to improve performance loading
setTimeout(() => {
this.checkEmailLawCompliance();
@@ -267,6 +271,33 @@ export class HomePage {
}, 2000);
}
+ doMigrateMessageOnchainProcess(){
+ this.persistenceProvider.getMigrateMessageOnchainProcess().then(
+ processStatus => {
+ if(!processStatus){
+ this.persistenceProvider.setMigrateMessageOnchainProcess('start');
+ const wallets = _.filter(this.profileProvider.wallet, w => {
+ return !w.hidden;
+ });
+ _.each(wallets, wallet => {
+ this.persistenceProvider.removeTxHistory(wallet.id);
+ })
+ this.persistenceProvider.setMigrateMessageOnchainProcess('finish');
+ }
+ else if(processStatus === 'start'){
+ const wallets = _.filter(this.profileProvider.wallet, w => {
+ return !w.hidden;
+ });
+ _.each(wallets, wallet => {
+ this.persistenceProvider.removeTxHistory(wallet.id);
+ })
+ this.persistenceProvider.setMigrateMessageOnchainProcess('finish');
+ }
+ }
+
+ )
+ }
+
getAdPageOrLink(link) {
let linkTo;
// link is of formate page:PAGE_TITLE or url e.g. https://google.com
@@ -336,6 +367,7 @@ export class HomePage {
}
private preFetchWallets() {
+
// Avoid heavy tasks that can slow down the unlocking experience
if (this.appProvider.isLockModalOpen) return;
this.fetchingStatus = true;
@@ -347,6 +379,7 @@ export class HomePage {
setTimeout(() => {
refresher.target.complete();
this.updateTxps();
+ this.doMigrateMessageOnchainProcess();
}, 2000);
}
diff --git a/src/app/pages/send/confirm/confirm.ts b/src/app/pages/send/confirm/confirm.ts
index b85bfcd2794..c3390dbe569 100644
--- a/src/app/pages/send/confirm/confirm.ts
+++ b/src/app/pages/send/confirm/confirm.ts
@@ -289,7 +289,7 @@ export class ConfirmPage {
invoiceID: this.navParamsData.invoiceID, // xrp
payProUrl: this.navParamsData.payProUrl,
spendUnconfirmed: this.config.wallet.spendUnconfirmed,
-
+ messageOnChain: this.navParamsData.messageOnChain,
// Vanity tx info (not in the real tx)
recipientType: this.navParamsData.recipientType,
name: this.navParamsData.name,
@@ -1159,7 +1159,7 @@ export class ConfirmPage {
}
txp.message = tx.description;
-
+ txp.messageOnChain = tx.messageOnChain;
if (tx.paypro) {
txp.payProUrl = tx.payProUrl;
tx.paypro.host = new URL(tx.payProUrl).host;
diff --git a/src/app/pages/send/send.ts b/src/app/pages/send/send.ts
index ee9a9af68dd..77102ca9b73 100644
--- a/src/app/pages/send/send.ts
+++ b/src/app/pages/send/send.ts
@@ -341,7 +341,8 @@ export class SendPage {
toAddress: recipient.toAddress,
name: recipient.name,
fromWalletDetails: true,
- isSentXecToEtoken: recipient.isSentXecToEtoken
+ isSentXecToEtoken: recipient.isSentXecToEtoken,
+ messageOnChain: recipient.message
}
});
} else {
@@ -358,7 +359,7 @@ export class SendPage {
coin: this.wallet.coin,
network: this.wallet.network,
useSendMax: false,
- recipients: this.listRecipient
+ recipients: this.listRecipient,
}
});
}
diff --git a/src/app/pages/wallet-details/wallet-details.html b/src/app/pages/wallet-details/wallet-details.html
index 1900be41ef3..afbbd5c8491 100644
--- a/src/app/pages/wallet-details/wallet-details.html
+++ b/src/app/pages/wallet-details/wallet-details.html
@@ -292,6 +292,9 @@
{{tx.message}}
+
+ {{tx.messageOnchain}}
+
diff --git a/src/app/providers/persistence/persistence.ts b/src/app/providers/persistence/persistence.ts
index 1c9781cf020..ad801971280 100644
--- a/src/app/providers/persistence/persistence.ts
+++ b/src/app/providers/persistence/persistence.ts
@@ -71,6 +71,7 @@ const Keys = {
PROFILE: 'profile',
PROFILE_OLD: 'profileOld',
REMOTE_PREF_STORED: 'remotePrefStored',
+ MIGRATE_MESSAGE_ONCHAIN: 'start',
TX_CONFIRM_NOTIF: txid => 'txConfirmNotif-' + txid,
TX_HISTORY: walletId => 'txsHistory-' + walletId,
ORDER_WALLET: walletId => 'order-' + walletId,
@@ -600,6 +601,14 @@ export class PersistenceProvider {
return this.storage.get(Keys.TX_CONFIRM_NOTIF(txid));
}
+ setMigrateMessageOnchainProcess(val) {
+ return this.storage.set(Keys.MIGRATE_MESSAGE_ONCHAIN, val);
+ }
+
+ getMigrateMessageOnchainProcess() {
+ return this.storage.get(Keys.MIGRATE_MESSAGE_ONCHAIN);
+ }
+
removeTxConfirmNotification(txid: string) {
return this.storage.remove(Keys.TX_CONFIRM_NOTIF(txid));
}
diff --git a/src/app/providers/wallet/wallet.ts b/src/app/providers/wallet/wallet.ts
index 7c88abfe6a5..69fa1a43816 100644
--- a/src/app/providers/wallet/wallet.ts
+++ b/src/app/providers/wallet/wallet.ts
@@ -73,6 +73,7 @@ export interface TransactionProposal {
inputs: any;
fee: any;
message: string;
+ messageOnChain: string;
customData?: {
service?: string;
giftCardName?: string;
From 2dfb9fcff61e09a9cd7abe9ad43588de21da8b8a Mon Sep 17 00:00:00 2001
From: takYoon
Date: Fri, 17 Jun 2022 18:23:22 +0700
Subject: [PATCH 02/15] tmp commit
---
.../recipient/recipient.component.html | 16 +++++++++-------
.../components/recipient/recipient.component.ts | 3 +++
src/app/pages/send/confirm/confirm.html | 15 +++++++++++++++
src/app/pages/send/confirm/confirm.ts | 1 +
src/app/pages/send/send.html | 2 +-
src/app/pages/send/send.ts | 3 +++
src/app/pages/wallet-details/wallet-details.html | 3 +++
7 files changed, 35 insertions(+), 8 deletions(-)
diff --git a/src/app/components/recipient/recipient.component.html b/src/app/components/recipient/recipient.component.html
index 56a1d1c376a..f255400bd1f 100644
--- a/src/app/components/recipient/recipient.component.html
+++ b/src/app/components/recipient/recipient.component.html
@@ -34,14 +34,16 @@
{{unit}}
{{unit}}
+
+
+
+
+
+ {{Buffer.from(this.message).length}} / 206
+
-
-
-
-
- {{Buffer.from(this.message).length}} / 206
{{'Send total selected amount' | translate}}
diff --git a/src/app/components/recipient/recipient.component.ts b/src/app/components/recipient/recipient.component.ts
index 17d5195cebb..a6d741aaab5 100644
--- a/src/app/components/recipient/recipient.component.ts
+++ b/src/app/components/recipient/recipient.component.ts
@@ -99,6 +99,9 @@ export class RecipientComponent implements OnInit {
@Input()
isDonation?: boolean;
+ @Input()
+ isShowMessage?: boolean;
+
@Output() deleteEvent?= new EventEmitter();
@Output() sendMaxEvent?= new EventEmitter();
diff --git a/src/app/pages/send/confirm/confirm.html b/src/app/pages/send/confirm/confirm.html
index 615aa368754..3e5ae524d52 100644
--- a/src/app/pages/send/confirm/confirm.html
+++ b/src/app/pages/send/confirm/confirm.html
@@ -196,6 +196,21 @@
+
+
+
+ Message
+
+
+
+
+
+ {{tx.messageOnChainToShow}}
+
+
+
+
+
diff --git a/src/app/pages/send/confirm/confirm.ts b/src/app/pages/send/confirm/confirm.ts
index 191fcc131f2..14505f68322 100644
--- a/src/app/pages/send/confirm/confirm.ts
+++ b/src/app/pages/send/confirm/confirm.ts
@@ -290,6 +290,7 @@ export class ConfirmPage {
payProUrl: this.navParamsData.payProUrl,
spendUnconfirmed: this.config.wallet.spendUnconfirmed,
messageOnChain: this.navParamsData.messageOnChain,
+ messageOnChainToShow: this.navParamsData.messageOnChain,
// Vanity tx info (not in the real tx)
recipientType: this.navParamsData.recipientType,
name: this.navParamsData.name,
diff --git a/src/app/pages/send/send.html b/src/app/pages/send/send.html
index 6cdb11dfa56..dca2e245c5a 100644
--- a/src/app/pages/send/send.html
+++ b/src/app/pages/send/send.html
@@ -75,7 +75,7 @@
+ [isShowDelete]="isShowDelete" [token]="token" (sendMaxEvent)="sendMax($event)" [isShowMessage]="isShowMessage && wallet.coin === 'xpi'">
diff --git a/src/app/pages/send/send.ts b/src/app/pages/send/send.ts
index 77102ca9b73..ddd7f2af439 100644
--- a/src/app/pages/send/send.ts
+++ b/src/app/pages/send/send.ts
@@ -60,6 +60,7 @@ export class SendPage {
walletId: string;
isShowSendMax: boolean = true;
isShowDelete: boolean = false;
+ isShowMessage: boolean = true;
toAddress: string = '';
formatRemaining: string;
recipientNotInit: RecipientModel;
@@ -279,6 +280,7 @@ export class SendPage {
}))
this.isShowSendMax = this.listRecipient.length === 1;
this.isShowDelete = this.listRecipient.length > 1;
+ this.isShowMessage = this.listRecipient.length === 1;
this.content.scrollToBottom(1000);
}
@@ -286,6 +288,7 @@ export class SendPage {
this.listRecipient = this.listRecipient.filter(s => s.id !== id);
this.isShowSendMax = this.listRecipient.length === 1;
this.isShowDelete = this.listRecipient.length > 1;
+ this.isShowMessage = this.listRecipient.length === 1;
}
private goToConfirmToken(isSendMax?: boolean) {
diff --git a/src/app/pages/wallet-details/wallet-details.html b/src/app/pages/wallet-details/wallet-details.html
index afbbd5c8491..0d14eb9aa38 100644
--- a/src/app/pages/wallet-details/wallet-details.html
+++ b/src/app/pages/wallet-details/wallet-details.html
@@ -315,6 +315,9 @@
amTimeAgo}}
{{tx.time * 1000 |
amDateFormat:'MM/DD/YYYY'}}
+
+ Reply
+
From d0d9d6cbe84146495c66c0202cb096bcb963997d Mon Sep 17 00:00:00 2001
From: takYoon
Date: Tue, 21 Jun 2022 10:58:46 +0700
Subject: [PATCH 03/15] add message reply component
---
.../message-reply.component.html | 24 ++++
.../message-reply.component.scss | 103 ++++++++++++++++++
.../message-reply.component.spec.ts | 24 ++++
.../message-reply/message-reply.component.ts | 39 +++++++
src/app/pages/pages.ts | 2 +
.../pages/wallet-details/wallet-details.html | 6 +-
.../pages/wallet-details/wallet-details.ts | 88 ++++++++++++++-
.../providers/action-sheet/action-sheet.ts | 10 ++
8 files changed, 292 insertions(+), 4 deletions(-)
create mode 100644 src/app/components/message-reply/message-reply.component.html
create mode 100644 src/app/components/message-reply/message-reply.component.scss
create mode 100644 src/app/components/message-reply/message-reply.component.spec.ts
create mode 100644 src/app/components/message-reply/message-reply.component.ts
diff --git a/src/app/components/message-reply/message-reply.component.html b/src/app/components/message-reply/message-reply.component.html
new file mode 100644
index 00000000000..ec6dde899b9
--- /dev/null
+++ b/src/app/components/message-reply/message-reply.component.html
@@ -0,0 +1,24 @@
+
+
+
+
+ Replying to {{messageReplyInfo.addressTo}}
+
+
+ {{messageReplyInfo.messageOnChain}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/components/message-reply/message-reply.component.scss b/src/app/components/message-reply/message-reply.component.scss
new file mode 100644
index 00000000000..8434027e4ed
--- /dev/null
+++ b/src/app/components/message-reply/message-reply.component.scss
@@ -0,0 +1,103 @@
+message-reply-component {
+ .scanner-icon {
+ z-index: 99;
+ font-size: 28px;
+ color: var(--ion-color-primary);
+ }
+ .check {
+ font-size: 22px;
+ padding-top: 1rem;
+ &.success {
+ color: var(--ion-color-success);
+ }
+ &.fail {
+ color: var(--ion-color-danger);
+ }
+ }
+
+ label-tip {
+ margin-top: 1.8rem;
+ }
+
+ .add-address-book-container {
+ background: #FAFAFB;
+ padding: 24px;
+ .slide-title {
+ h3 {
+ margin: 0;
+ font-weight: 400;
+ font-size: 24px;
+ line-height: 32px;
+ color: #001E2E;
+ margin-bottom: 2rem;
+ }
+ }
+ form {
+ ion-item {
+ margin: 2rem 0;
+ border: 2px solid rgba(0, 30, 46, 0.38);
+ --inner-padding-start: 1rem;
+ --inner-padding-end: 1rem;
+ --inner-padding-end: 0;
+ --padding-start: 0;
+ --padding-end: 0;
+ --color: #001E2E;
+ --background: #FAFAFB;
+ border-radius: 4px;
+ ion-input {
+ font-weight: 400;
+ font-size: 16px !important;
+ line-height: 24px;
+ letter-spacing: 0.5px;
+ }
+ ion-icon {
+ padding: 0;
+ }
+ }
+ .form-field {
+ margin-bottom: 3rem !important;
+ padding: 0 !important;
+ }
+ .mat-form-field-subscript-wrapper {
+ margin-top: 2rem !important;
+ padding: 0 !important;
+ }
+
+ .mobile-view {
+ .mat-form-field-infix {
+ max-width: 85%;
+ }
+ }
+ }
+ .footer {
+ display: flex;
+ justify-content: flex-end;
+ .button-standard {
+ --padding-start: 0;
+ --padding-end: 0;
+ width: 28%;
+ margin: 1rem 0;
+ color: var(--color-primary);
+ --background: transparent;
+ font-weight: 600 !important;
+ font-size: 14px !important;
+ line-height: 20px;
+ letter-spacing: 0.1px;
+ &[disabled] {
+ --background: transparent !important;
+ color: rgba(28, 55, 69, 0.38) !important;
+ }
+ }
+ }
+ }
+
+ .reply-to-container{
+ .reply-to-title{
+ color: black;
+ }
+ .reply-to-message{
+ color: black;
+ }
+ }
+ }
+
\ No newline at end of file
diff --git a/src/app/components/message-reply/message-reply.component.spec.ts b/src/app/components/message-reply/message-reply.component.spec.ts
new file mode 100644
index 00000000000..67db8bed308
--- /dev/null
+++ b/src/app/components/message-reply/message-reply.component.spec.ts
@@ -0,0 +1,24 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+import { IonicModule } from '@ionic/angular';
+
+import { MessageReplyComponent } from './message-reply.component';
+
+describe('MessageReplyComponent', () => {
+ let component: MessageReplyComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ declarations: [ MessageReplyComponent ],
+ imports: [IonicModule.forRoot()]
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(MessageReplyComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ }));
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/components/message-reply/message-reply.component.ts b/src/app/components/message-reply/message-reply.component.ts
new file mode 100644
index 00000000000..9cfee22b759
--- /dev/null
+++ b/src/app/components/message-reply/message-reply.component.ts
@@ -0,0 +1,39 @@
+import { Component, OnInit, ViewEncapsulation } from '@angular/core';
+import { Location } from '@angular/common';
+import { Router } from '@angular/router';
+import { AppProvider } from 'src/app/providers';
+import { Logger } from 'src/app/providers/logger/logger';
+import { ActionSheetParent } from '../action-sheet/action-sheet-parent';
+import { FormBuilder, FormGroup } from '@angular/forms';
+
+@Component({
+ selector: 'message-reply-component',
+ templateUrl: './message-reply.component.html',
+ styleUrls: ['./message-reply.component.scss'],
+ encapsulation: ViewEncapsulation.None
+})
+export class MessageReplyComponent extends ActionSheetParent{
+ messageReplyInfo: any;
+ public messageReplySend: FormGroup;
+ messageOnChainValue;
+ constructor(
+ private formBuilder: FormBuilder,
+ ) {
+ super();
+ this.messageReplySend = this.formBuilder.group({
+ messageOnChain: [
+ '',
+ []
+ ]
+ });
+ }
+
+ ngOnInit() {
+ this.messageReplyInfo = this.params;
+ }
+
+ send(){
+ const message = this.messageReplySend.value.messageOnChain;
+ this.dismiss(message);
+ }
+}
diff --git a/src/app/pages/pages.ts b/src/app/pages/pages.ts
index 004c99eb2b0..282a4aace94 100644
--- a/src/app/pages/pages.ts
+++ b/src/app/pages/pages.ts
@@ -110,8 +110,10 @@ import { TokenInforPage } from './token-info/token-info';
import { AccountsPage } from './accounts/accounts';
import { SearchContactPage } from './search/search-contact/search-contact.component';
import { SelectFlowPage } from './onboarding/select-flow/select-flow';
+import { MessageReplyComponent } from '../components/message-reply/message-reply.component';
export const PAGES = [
+ MessageReplyComponent,
AddPage,
AddWalletPage,
AmountPage,
diff --git a/src/app/pages/wallet-details/wallet-details.html b/src/app/pages/wallet-details/wallet-details.html
index 0d14eb9aa38..10cf032de5a 100644
--- a/src/app/pages/wallet-details/wallet-details.html
+++ b/src/app/pages/wallet-details/wallet-details.html
@@ -232,7 +232,7 @@
-
@@ -315,9 +315,9 @@
amTimeAgo}}
{{tx.time * 1000 |
amDateFormat:'MM/DD/YYYY'}}
-
+
Reply
-
+
diff --git a/src/app/pages/wallet-details/wallet-details.ts b/src/app/pages/wallet-details/wallet-details.ts
index 5ef62e335b7..cc44729ea19 100644
--- a/src/app/pages/wallet-details/wallet-details.ts
+++ b/src/app/pages/wallet-details/wallet-details.ts
@@ -358,6 +358,87 @@ export class WalletDetailsPage {
}, 1000);
}
+ handleClick(tx){
+ this.showReplyMessageModal(tx);
+ }
+
+ getAddressFrom(tx): any{
+ if((!this.addressbook || !tx.inputAddresses[0] || !this.getContactName(tx.inputAddresses[0]))){
+ return {
+ name: tx.inputAddresses[0].slice(-8),
+ address: tx.inputAddresses[0],
+ type: ''
+ }
+ }
+ // else if(this.addressbook && tx.inputAddresses[0] && this.getContactName(tx.inputAddresses[0])){
+ // return {
+ // name: this.getContactName(tx.inputAddresses[0]),
+ // address: tx.inputAddresses[0].address,
+ // type: 'contact'
+ // }
+ // }
+ else return {
+ name: this.getContactName(tx.inputAddresses[0]),
+ address: tx.inputAddresses[0],
+ type: 'contact'
+ }
+ }
+
+ getAddressTo(tx): any{
+ if((!tx.note || (tx.note && !tx.note.body)) && (!this.addressbook || !tx.outputs[0] || !this.getContactName(tx.outputs[0].address)) && (!tx.customData || !tx.customData.toWalletName)){
+ return {
+ name: tx.addressTo.slice(-8),
+ address: tx.addressTo,
+ type: ''
+ }
+ }
+ else if((!tx.note || (tx.note && !tx.note.body)) && (!this.addressbook || !tx.outputs[0] || !this.getContactName(tx.outputs[0].address)) && (tx.customData && tx.customData.toWalletName)){
+ return {
+ name: tx.customData.toWalletName,
+ address: tx.outputs[0].address,
+ type: 'wallet'
+ }
+ }
+ else return {
+ name: this.getContactName(tx.outputs[0].address),
+ address: tx.outputs[0].address,
+ type: 'contact'
+ }
+ }
+
+ showReplyMessageModal(tx) {
+ const txInfo = this.getAddressFrom(tx);
+ const addContactModal = this.actionSheetProvider.createMessageReplyComponent({
+ addressTo: this.getAddressFrom(tx).name,
+ messageOnChain: tx.messageOnchain
+ });
+ addContactModal.present({ maxHeight: '48%%', minHeight: '48%%' });
+ addContactModal.onDidDismiss((rs) => {
+ if (rs) {
+ this.sendReplyMessage(rs, txInfo);
+ }
+ });
+ }
+
+ sendReplyMessage(rs, txInfo){
+ this.router.navigate(['/confirm'], {
+ state: {
+ walletId: this.wallet.credentials.walletId,
+ recipientType: txInfo.type,
+ amount: 5000,
+ currency: this.wallet.coin,
+ coin: this.wallet.coin,
+ network: this.wallet.network,
+ useSendMax: false,
+ toAddress: txInfo.address,
+ name: txInfo.type === 'contact' ? txInfo.name : null,
+ fromWalletDetails: true,
+ isSentXecToEtoken: false,
+ messageOnChain: rs
+ }
+ });
+ }
+
updateAddressToShowToken(tx) {
const outputAddr = tx.outputs[0].address;
let addressToShow = this.walletProvider.getAddressView(
@@ -559,7 +640,12 @@ export class WalletDetailsPage {
}
};
- public itemTapped(tx) {
+ public itemTapped(tx, itemTapped){
+ if(itemTapped.target.innerText === 'Reply'){
+ itemTapped.preventDefault();
+ itemTapped.stopPropagation();
+ return;
+ }
if (tx.hasUnconfirmedInputs) {
const infoSheet = this.actionSheetProvider.createInfoSheet(
'unconfirmed-inputs'
diff --git a/src/app/providers/action-sheet/action-sheet.ts b/src/app/providers/action-sheet/action-sheet.ts
index c9a4d6ab543..ebe82e183f8 100644
--- a/src/app/providers/action-sheet/action-sheet.ts
+++ b/src/app/providers/action-sheet/action-sheet.ts
@@ -6,6 +6,7 @@ import { FooterMenuComponent } from 'src/app/components/footer-menu/footer-menu'
import { IncomingDataMenuComponent } from 'src/app/components/incoming-data-menu/incoming-data-menu';
import { InfoSheetComponent } from 'src/app/components/info-sheet/info-sheet';
import { MemoComponent } from 'src/app/components/memo-component/memo-component';
+import { MessageReplyComponent } from 'src/app/components/message-reply/message-reply.component';
import { MinerFeeWarningComponent } from 'src/app/components/miner-fee-warning/miner-fee-warning';
import { MultisignInfoComponent } from 'src/app/components/multisign-info/multisign-info.component';
import { NeedsBackupComponent } from 'src/app/components/needs-backup/needs-backup';
@@ -220,6 +221,15 @@ export class ActionSheetProvider {
.instance;
}
+ public createMessageReplyComponent(params?): MessageReplyComponent {
+ return this.setupSheet
(
+ MessageReplyComponent,
+ null,
+ params
+ )
+ .instance;
+ }
+
public createMinerFeeWarningComponent(): MinerFeeWarningComponent {
return this.setupSheet(MinerFeeWarningComponent)
.instance;
From eb09c4030e9baaf5f31b975b97e28bd61c6ad2bd Mon Sep 17 00:00:00 2001
From: ericson
Date: Mon, 20 Mar 2023 11:19:33 +0700
Subject: [PATCH 04/15] implement ui onchain message
---
.../message-reply.component.html | 38 ++--
.../message-reply.component.scss | 176 +++++++++---------
.../message-reply/message-reply.component.ts | 7 +-
.../recipient/recipient.component.html | 4 +-
src/app/pages/send/confirm/confirm.html | 2 +-
src/app/pages/send/confirm/confirm.scss | 3 +
src/app/pages/tx-details/tx-details.html | 17 ++
src/app/pages/tx-details/tx-details.scss | 17 ++
src/app/pages/tx-details/tx-details.ts | 4 +
.../pages/wallet-details/wallet-details.html | 11 +-
.../pages/wallet-details/wallet-details.scss | 15 ++
src/assets/i18n/en.po | 6 +
src/assets/i18n/vi.po | 6 +
src/assets/img/ico-reply-dark.svg | 10 +
src/assets/img/ico-reply-light.svg | 10 +
src/theme/dark.scss | 21 +++
16 files changed, 225 insertions(+), 122 deletions(-)
create mode 100644 src/assets/img/ico-reply-dark.svg
create mode 100644 src/assets/img/ico-reply-light.svg
diff --git a/src/app/components/message-reply/message-reply.component.html b/src/app/components/message-reply/message-reply.component.html
index ec6dde899b9..a1ec92b0296 100644
--- a/src/app/components/message-reply/message-reply.component.html
+++ b/src/app/components/message-reply/message-reply.component.html
@@ -1,24 +1,22 @@
-
-
-
- Replying to {{messageReplyInfo.addressTo}}
-
-
- {{messageReplyInfo.messageOnChain}}
-
+
+
+
+ {{'Replying to ' | translate }} {{ messageReplyInfo.addressTo }}
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+ {{ 'Send' | translate }}
+
+
diff --git a/src/app/components/message-reply/message-reply.component.scss b/src/app/components/message-reply/message-reply.component.scss
index 8434027e4ed..21de426a881 100644
--- a/src/app/components/message-reply/message-reply.component.scss
+++ b/src/app/components/message-reply/message-reply.component.scss
@@ -1,103 +1,93 @@
message-reply-component {
- .scanner-icon {
- z-index: 99;
- font-size: 28px;
- color: var(--ion-color-primary);
+ .scanner-icon {
+ z-index: 99;
+ font-size: 28px;
+ color: var(--ion-color-primary);
+ }
+ .check {
+ font-size: 22px;
+ padding-top: 1rem;
+ &.success {
+ color: var(--ion-color-success);
}
- .check {
- font-size: 22px;
- padding-top: 1rem;
- &.success {
- color: var(--ion-color-success);
- }
- &.fail {
- color: var(--ion-color-danger);
- }
+ &.fail {
+ color: var(--ion-color-danger);
}
-
- label-tip {
- margin-top: 1.8rem;
+ }
+
+ label-tip {
+ margin-top: 1.8rem;
+ }
+
+ .slide-title {
+ h3 {
+ margin: 0;
+ font-weight: 400;
+ font-size: 24px;
+ line-height: 32px;
+ color: #001e2e;
+ margin-bottom: 2rem;
}
-
- .add-address-book-container {
- background: #FAFAFB;
- padding: 24px;
- .slide-title {
- h3 {
- margin: 0;
- font-weight: 400;
- font-size: 24px;
- line-height: 32px;
- color: #001E2E;
- margin-bottom: 2rem;
- }
- }
- form {
- ion-item {
- margin: 2rem 0;
- border: 2px solid rgba(0, 30, 46, 0.38);
- --inner-padding-start: 1rem;
- --inner-padding-end: 1rem;
- --inner-padding-end: 0;
- --padding-start: 0;
- --padding-end: 0;
- --color: #001E2E;
- --background: #FAFAFB;
- border-radius: 4px;
- ion-input {
- font-weight: 400;
- font-size: 16px !important;
- line-height: 24px;
- letter-spacing: 0.5px;
- }
- ion-icon {
- padding: 0;
- }
- }
- .form-field {
- margin-bottom: 3rem !important;
- padding: 0 !important;
- }
- .mat-form-field-subscript-wrapper {
- margin-top: 2rem !important;
- padding: 0 !important;
- }
-
- .mobile-view {
- .mat-form-field-infix {
- max-width: 85%;
- }
- }
+ }
+ form {
+ margin: 0 8px 24px 8px;
+ ion-item {
+ margin: 2rem 0;
+ border: 2px solid rgba(0, 30, 46, 0.38);
+ --inner-padding-start: 1rem;
+ --inner-padding-end: 1rem;
+ --inner-padding-end: 0;
+ --padding-start: 0;
+ --padding-end: 0;
+ --color: #001e2e;
+ --background: #fafafb;
+ border-radius: 4px;
+ ion-input {
+ font-weight: 400;
+ font-size: 16px !important;
+ line-height: 24px;
+ letter-spacing: 0.5px;
}
- .footer {
- display: flex;
- justify-content: flex-end;
- .button-standard {
- --padding-start: 0;
- --padding-end: 0;
- width: 28%;
- margin: 1rem 0;
- color: var(--color-primary);
- --background: transparent;
- font-weight: 600 !important;
- font-size: 14px !important;
- line-height: 20px;
- letter-spacing: 0.1px;
- &[disabled] {
- --background: transparent !important;
- color: rgba(28, 55, 69, 0.38) !important;
- }
- }
+ ion-icon {
+ padding: 0;
}
}
+ .form-field {
+ margin-bottom: 3rem !important;
+ padding: 0 !important;
+ }
+ .mat-form-field-subscript-wrapper {
+ margin-top: 2rem !important;
+ padding: 0 !important;
+ }
- .reply-to-container{
- .reply-to-title{
- color: black;
- }
- .reply-to-message{
- color: black;
- }
+ .mobile-view {
+ .mat-form-field-infix {
+ max-width: 85%;
+ }
+ }
+ }
+ .reply-to-container {
+ background: linear-gradient(0deg, rgba(0, 101, 141, 0.14), rgba(0, 101, 141, 0.14)), #FAFAFB;
+ border: 1px solid rgba(126, 208, 255, 0.08);
+ border-radius: 8px;
+ padding: 8px;
+ margin: 24px;
+ .reply-to-title {
+ color: #1C3745;
+ font-size: 16px;
+ font-weight: 600;
+ letter-spacing: 0.1px;
+ }
+ .reply-to-message {
+ color: #1C3745;
+ letter-spacing: 0.25px;
+ font-size: 14px;
}
}
-
\ No newline at end of file
+
+ .button-send-onchain {
+ width: fit-content !important;
+ margin: 5px 24px 25px auto !important;
+ }
+}
diff --git a/src/app/components/message-reply/message-reply.component.ts b/src/app/components/message-reply/message-reply.component.ts
index 9cfee22b759..306e2d643fd 100644
--- a/src/app/components/message-reply/message-reply.component.ts
+++ b/src/app/components/message-reply/message-reply.component.ts
@@ -1,10 +1,10 @@
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { Location } from '@angular/common';
import { Router } from '@angular/router';
-import { AppProvider } from 'src/app/providers';
import { Logger } from 'src/app/providers/logger/logger';
import { ActionSheetParent } from '../action-sheet/action-sheet-parent';
import { FormBuilder, FormGroup } from '@angular/forms';
+import { AppProvider } from 'src/app/providers/app/app';
@Component({
selector: 'message-reply-component',
@@ -13,13 +13,18 @@ import { FormBuilder, FormGroup } from '@angular/forms';
encapsulation: ViewEncapsulation.None
})
export class MessageReplyComponent extends ActionSheetParent{
+ message='';
+ Buffer = Buffer;
messageReplyInfo: any;
+ public currentTheme: string;
public messageReplySend: FormGroup;
messageOnChainValue;
constructor(
private formBuilder: FormBuilder,
+ private appProvider: AppProvider,
) {
super();
+ this.currentTheme = this.appProvider.themeProvider.currentAppTheme;
this.messageReplySend = this.formBuilder.group({
messageOnChain: [
'',
diff --git a/src/app/components/recipient/recipient.component.html b/src/app/components/recipient/recipient.component.html
index 1ad9f444b23..f6b4b724dad 100644
--- a/src/app/components/recipient/recipient.component.html
+++ b/src/app/components/recipient/recipient.component.html
@@ -37,12 +37,12 @@
- {{Buffer.from(this.message).length}} / 206
+ {{Buffer.from(this.message).length}} / 206 bytes
diff --git a/src/app/pages/send/confirm/confirm.html b/src/app/pages/send/confirm/confirm.html
index 07d465f6960..3de08558a78 100644
--- a/src/app/pages/send/confirm/confirm.html
+++ b/src/app/pages/send/confirm/confirm.html
@@ -208,7 +208,7 @@
-
+
{{tx.messageOnChainToShow}}
diff --git a/src/app/pages/send/confirm/confirm.scss b/src/app/pages/send/confirm/confirm.scss
index a6b4fa86c16..da70aca2954 100644
--- a/src/app/pages/send/confirm/confirm.scss
+++ b/src/app/pages/send/confirm/confirm.scss
@@ -376,6 +376,9 @@ page-confirm {
.address-note-custom {
display: flex;
letter-spacing: 0.4px;
+ .onchain-message-txt {
+ color: #001E2E !important;
+ }
}
.input-contact-custom {
diff --git a/src/app/pages/tx-details/tx-details.html b/src/app/pages/tx-details/tx-details.html
index a673a30322f..6c2f990368b 100644
--- a/src/app/pages/tx-details/tx-details.html
+++ b/src/app/pages/tx-details/tx-details.html
@@ -199,6 +199,23 @@
+
+
+ {{'Message' | translate}}
+
+
+
+ Live your life with smiles, not tears. Beat your age with friends and not years. Happy birthday!
+
+
+
+ {{'Reply' | translate}}
+
+
+
+
+
+
{{'Memo' | translate}}
diff --git a/src/app/pages/tx-details/tx-details.scss b/src/app/pages/tx-details/tx-details.scss
index 58949e4b49b..aca0af723b6 100644
--- a/src/app/pages/tx-details/tx-details.scss
+++ b/src/app/pages/tx-details/tx-details.scss
@@ -282,6 +282,23 @@ page-tx-details {
align-items: center;
}
+ .message-custom {
+ ion-note {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ }
+ .message-onchain {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ line-clamp: 3;
+ -webkit-line-clamp: 3;
+ box-orient: vertical;
+ -webkit-box-orient: vertical;
+ }
+ }
+
.wallet,
.multi-recip-title {
span {
diff --git a/src/app/pages/tx-details/tx-details.ts b/src/app/pages/tx-details/tx-details.ts
index c802d596aad..7c7b8bf7e35 100644
--- a/src/app/pages/tx-details/tx-details.ts
+++ b/src/app/pages/tx-details/tx-details.ts
@@ -462,6 +462,10 @@ export class TxDetailsModal {
}
}
+ public handleClick(btx) {
+
+ }
+
public openExternalLink(url: string): void {
const optIn = true;
const title = null;
diff --git a/src/app/pages/wallet-details/wallet-details.html b/src/app/pages/wallet-details/wallet-details.html
index b612463845e..bfe204e83d5 100644
--- a/src/app/pages/wallet-details/wallet-details.html
+++ b/src/app/pages/wallet-details/wallet-details.html
@@ -233,10 +233,10 @@
-
-
+
-
+
{{'Pending'| translate}}
@@ -316,8 +316,9 @@
amTimeAgo}}
{{tx.time * 1000 |
amDateFormat:'MM/DD/YYYY'}}
-
- Reply
+
+
+ {{'Reply' | translate}}
diff --git a/src/app/pages/wallet-details/wallet-details.scss b/src/app/pages/wallet-details/wallet-details.scss
index 9bc7bcbc92b..eb27dd31db4 100644
--- a/src/app/pages/wallet-details/wallet-details.scss
+++ b/src/app/pages/wallet-details/wallet-details.scss
@@ -247,6 +247,18 @@ page-wallet-details {
.item-icon {
margin-right: 15px;
}
+ ion-note {
+ &.note-onchain-message {
+ height: 100%;
+ .tx-info {
+ height: 100%;
+ justify-content: space-between;
+ p {
+ flex-grow: 1;
+ }
+ }
+ }
+ }
}
img {
@@ -526,6 +538,9 @@ page-wallet-details {
.date {
margin: 0;
font-size: 12px;
+ &.btn-reply {
+ --color: var(--color-light-on-background-theme);
+ }
}
}
diff --git a/src/assets/i18n/en.po b/src/assets/i18n/en.po
index 74e73e920a7..4b14ba89cdc 100755
--- a/src/assets/i18n/en.po
+++ b/src/assets/i18n/en.po
@@ -5324,6 +5324,12 @@ msgstr "{{countInArray}} of your accounts already exist in {{nameCase}}"
msgid "{{newWalletsCount}} wallets found"
msgstr "{{newWalletsCount}} wallets found"
+msgid "Replying to "
+msgstr "Replying to "
+
+msgid "Reply"
+msgstr "Reply"
+
msgid ""
"{{params.countryCode === 'US' ? 'U.S.' : params.countryCode}} Phone Required"
msgstr ""
diff --git a/src/assets/i18n/vi.po b/src/assets/i18n/vi.po
index e145a9539f1..ea00c62203f 100644
--- a/src/assets/i18n/vi.po
+++ b/src/assets/i18n/vi.po
@@ -2758,6 +2758,12 @@ msgstr "Không phải bây giờ"
msgid "Not set"
msgstr "Không được thiết lập"
+msgid "Replying to "
+msgstr "Trả lời cho "
+
+msgid "Reply"
+msgstr "Trả lời"
+
msgid "Not valid bitcoin address"
msgstr "Địa chỉ bitcoin không hợp lệ"
diff --git a/src/assets/img/ico-reply-dark.svg b/src/assets/img/ico-reply-dark.svg
new file mode 100644
index 00000000000..cba36e842b3
--- /dev/null
+++ b/src/assets/img/ico-reply-dark.svg
@@ -0,0 +1,10 @@
+
diff --git a/src/assets/img/ico-reply-light.svg b/src/assets/img/ico-reply-light.svg
new file mode 100644
index 00000000000..8bc472da296
--- /dev/null
+++ b/src/assets/img/ico-reply-light.svg
@@ -0,0 +1,10 @@
+
diff --git a/src/theme/dark.scss b/src/theme/dark.scss
index e2af6e5db3e..26c0aaf4633 100644
--- a/src/theme/dark.scss
+++ b/src/theme/dark.scss
@@ -1797,6 +1797,9 @@
.note-container {
color: rgba(255, 184, 93, 1) !important;
}
+ .onchain-message-txt {
+ color: #fff !important;
+ }
}
.send-to-content {
.item-name {
@@ -2397,6 +2400,10 @@
--placeholder-color: rgba(237, 239, 240, 0.38);
--color: #edeff0;
}
+ ion-textarea {
+ --placeholder-color: rgba(237, 239, 240, 0.38);
+ --color: #edeff0;
+ }
}
.bold-text {
color: #7ed0ff;
@@ -3724,4 +3731,18 @@
}
}
}
+
+ message-reply-component {
+ .reply-to-container {
+ background: linear-gradient(0deg, rgba(126, 208, 255, 0.14), rgba(126, 208, 255, 0.14)), #001E2E;
+ border: 1px solid rgba(0, 101, 141, 0.08);
+ .reply-to-title {
+ color: #EDEFF0;
+ }
+ .reply-to-message {
+ color: #E0E4E6;
+ }
+ }
+
+ }
}
From 4608c9710917c5c35429855e8f42a65961a944d8 Mon Sep 17 00:00:00 2001
From: ericson
Date: Mon, 20 Mar 2023 16:24:29 +0700
Subject: [PATCH 05/15] implement onchain message
---
.../message-reply.component.html | 9 +++--
.../message-reply/message-reply.component.ts | 11 +++++-
.../recipient/recipient.component.html | 2 +-
.../recipient/recipient.component.ts | 22 +++++-------
src/app/pages/tx-details/tx-details.html | 34 ++++++++++---------
src/app/pages/tx-details/tx-details.ts | 7 +++-
.../pages/wallet-details/wallet-details.html | 3 +-
.../pages/wallet-details/wallet-details.ts | 23 +++++++------
src/assets/i18n/en.po | 6 ++++
src/assets/i18n/vi.po | 6 ++++
10 files changed, 75 insertions(+), 48 deletions(-)
diff --git a/src/app/components/message-reply/message-reply.component.html b/src/app/components/message-reply/message-reply.component.html
index a1ec92b0296..aa6b592db8b 100644
--- a/src/app/components/message-reply/message-reply.component.html
+++ b/src/app/components/message-reply/message-reply.component.html
@@ -11,12 +11,15 @@
-
+
{{ 'Send' | translate }}
diff --git a/src/app/components/message-reply/message-reply.component.ts b/src/app/components/message-reply/message-reply.component.ts
index 306e2d643fd..8a97070a3af 100644
--- a/src/app/components/message-reply/message-reply.component.ts
+++ b/src/app/components/message-reply/message-reply.component.ts
@@ -13,12 +13,13 @@ import { AppProvider } from 'src/app/providers/app/app';
encapsulation: ViewEncapsulation.None
})
export class MessageReplyComponent extends ActionSheetParent{
- message='';
+ message = '';
Buffer = Buffer;
messageReplyInfo: any;
public currentTheme: string;
public messageReplySend: FormGroup;
messageOnChainValue;
+ validMessage: boolean = false;
constructor(
private formBuilder: FormBuilder,
private appProvider: AppProvider,
@@ -37,6 +38,14 @@ export class MessageReplyComponent extends ActionSheetParent{
this.messageReplyInfo = this.params;
}
+ public changeMessage() {
+ if (this.message.trim().length > 0) {
+ this.validMessage = true;
+ } else {
+ this.validMessage = false;
+ }
+ }
+
send(){
const message = this.messageReplySend.value.messageOnChain;
this.dismiss(message);
diff --git a/src/app/components/recipient/recipient.component.html b/src/app/components/recipient/recipient.component.html
index f6b4b724dad..8bd34f0b985 100644
--- a/src/app/components/recipient/recipient.component.html
+++ b/src/app/components/recipient/recipient.component.html
@@ -40,7 +40,7 @@
{{'Private message' | translate}}
-
+
{{Buffer.from(this.message).length}} / 206 bytes
diff --git a/src/app/components/recipient/recipient.component.ts b/src/app/components/recipient/recipient.component.ts
index 2d1812f0934..fb9ab0c39a0 100644
--- a/src/app/components/recipient/recipient.component.ts
+++ b/src/app/components/recipient/recipient.component.ts
@@ -239,19 +239,15 @@ export class RecipientComponent implements OnInit {
this.updateUnitUI(!!isToken);
}
- changeMessage(){
- if(Buffer.from(this.message).length > 206) {
- if(this.validMessage){
- this.validMessage = false;
- this.checkRecipientValid();
- }
- } else{
- this.recipient.message = this.message;
- if(!this.validMessage){
- this.validMessage = true;
- this.checkRecipientValid();
- }
- }
+ public changeMessage() {
+ if (this.message.trim().length > 0) {
+ this.validMessage = true;
+ this.recipient.message = this.message;
+ this.checkRecipientValid();
+ } else {
+ this.validMessage = false;
+ this.checkRecipientValid();
+ }
}
private updateAddressHandler: any = data => {
diff --git a/src/app/pages/tx-details/tx-details.html b/src/app/pages/tx-details/tx-details.html
index 6c2f990368b..dbdea4d14a9 100644
--- a/src/app/pages/tx-details/tx-details.html
+++ b/src/app/pages/tx-details/tx-details.html
@@ -197,22 +197,24 @@
-
-
-
-
- {{'Message' | translate}}
-
-
-
- Live your life with smiles, not tears. Beat your age with friends and not years. Happy birthday!
-
-
-
- {{'Reply' | translate}}
-
-
-
+
+
+
+
+
+ {{'Message' | translate}}
+
+
+
+ {{messageOnchain}}
+
+
+
+ {{'Reply' | translate}}
+
+
+
+
diff --git a/src/app/pages/tx-details/tx-details.ts b/src/app/pages/tx-details/tx-details.ts
index 7c7b8bf7e35..ade1684ad1d 100644
--- a/src/app/pages/tx-details/tx-details.ts
+++ b/src/app/pages/tx-details/tx-details.ts
@@ -62,7 +62,7 @@ export class TxDetailsModal {
public isNegative: boolean;
public currentTheme;
public fiatRateStrToken;
-
+ public messageOnchain: string;
public addressbook = [];
constructor(
@@ -99,6 +99,7 @@ export class TxDetailsModal {
this.title = this.translate.instant('Transaction');
this.wallet = this.profileProvider.getWallet(this.navParams.data.walletId);
this.tokenData = this.navParams.data.tokenData;
+ this.messageOnchain = this.navParams.data.messageOnchain;
this.token = this.navParams.data.token;
this.color = this.wallet.color;
this.copayerId = this.wallet.credentials.copayerId;
@@ -186,6 +187,10 @@ export class TxDetailsModal {
});
}
+ public showReplyMessageModal() {
+ this.viewCtrl.dismiss(true);
+ }
+
private initActionList(): void {
this.actionList = [];
if (
diff --git a/src/app/pages/wallet-details/wallet-details.html b/src/app/pages/wallet-details/wallet-details.html
index bfe204e83d5..cf894cb0a4d 100644
--- a/src/app/pages/wallet-details/wallet-details.html
+++ b/src/app/pages/wallet-details/wallet-details.html
@@ -293,8 +293,7 @@
{{tx.message}}
-
{{tx.messageOnchain}}
-
+
{{tx.messageOnchain}}
diff --git a/src/app/pages/wallet-details/wallet-details.ts b/src/app/pages/wallet-details/wallet-details.ts
index 507077cb3b7..a2cf34547fd 100644
--- a/src/app/pages/wallet-details/wallet-details.ts
+++ b/src/app/pages/wallet-details/wallet-details.ts
@@ -113,7 +113,6 @@ export class WalletDetailsPage {
private actionSheetProvider: ActionSheetProvider,
private platform: Platform,
private profileProvider: ProfileProvider,
- private viewCtrl: ModalController,
public platformProvider: PlatformProvider,
private socialSharing: SocialSharing,
private bwcErrorProvider: BwcErrorProvider,
@@ -731,18 +730,20 @@ export class WalletDetailsPage {
});
}
- public goToTxDetails(tx) {
- const txDetailModal = this.modalCtrl
- .create({
- component: TxDetailsModal,
+ public async goToTxDetails(tx) {
+ const txDetailModal = await this.modalCtrl.create({
+ component: TxDetailsModal,
componentProps: {
walletId: this.wallet.credentials.walletId,
- txid: tx.txid
+ txid: tx.txid,
+ messageOnchain: tx.messageOnchain ? tx.messageOnchain : null
}
- })
- .then(res => {
- res.present();
- });
+ });
+ txDetailModal.present();
+ const { data } = await txDetailModal.onWillDismiss();
+ if (data) {
+ this.showReplyMessageModal(tx);
+ }
}
public openBackupModal(): void {
@@ -888,7 +889,7 @@ export class WalletDetailsPage {
}
public close() {
- this.viewCtrl.dismiss();
+ this.modalCtrl.dismiss();
}
public goToReceivePage() {
diff --git a/src/assets/i18n/en.po b/src/assets/i18n/en.po
index 4b14ba89cdc..1e1ef76db7d 100755
--- a/src/assets/i18n/en.po
+++ b/src/assets/i18n/en.po
@@ -24,6 +24,12 @@ msgstr "Password unmatched!"
msgid "Important"
msgstr "Important"
+msgid "Private message"
+msgstr "Private message"
+
+msgid "Type your private message"
+msgstr "Type your private message"
+
msgid "{appName} cannot recovery your fund for you if you lose your recovery key. The loss of it will lead to permanent asset loss."
msgstr "{appName} cannot recovery your fund for you if you lose your recovery key. The loss of it will lead to permanent asset loss."
diff --git a/src/assets/i18n/vi.po b/src/assets/i18n/vi.po
index ea00c62203f..ca1edb796a2 100644
--- a/src/assets/i18n/vi.po
+++ b/src/assets/i18n/vi.po
@@ -24,6 +24,12 @@ msgstr "Mật khẩu không khớp!"
msgid "Important"
msgstr "Quan Trọng"
+msgid "Private message"
+msgstr "Tin nhắn riêng tư"
+
+msgid "Type your private message"
+msgstr "Nhập tin nhắn riêng tư của bạn"
+
msgid "{appName} cannot recovery your fund for you if you lose your recovery key. The loss of it will lead to permanent asset loss."
msgstr "{appName} không thể khôi phục số dư nếu bạn mất cụm từ khóa (12 từ). Đồng nghĩa với việc tài sản của bạn sẽ bị mất vĩnh viễn."
From 169d5a6d938f052674ca22a6f93021191659a0d8 Mon Sep 17 00:00:00 2001
From: takYoon
Date: Thu, 23 Mar 2023 11:12:45 +0700
Subject: [PATCH 06/15] apply logic encrypt and decrypt message
---
package.json | 1 +
src/app/constants.ts | 33 +++++
src/app/pages/send/confirm/confirm.ts | 140 +++++++++++-------
src/app/pages/tx-details/tx-details.html | 14 +-
src/app/pages/tx-details/tx-details.ts | 109 +++++++++-----
.../pages/wallet-details/wallet-details.ts | 133 ++++++++++++-----
src/app/providers/index.ts | 1 +
src/app/providers/wallet/wallet.ts | 12 ++
8 files changed, 304 insertions(+), 139 deletions(-)
diff --git a/package.json b/package.json
index aa60cd22a1b..f7193eb21d6 100644
--- a/package.json
+++ b/package.json
@@ -96,6 +96,7 @@
"buffer-compare": "^1.1.1",
"capacitor-resources": "^2.0.5",
"chart.js": "^3.5.1",
+ "chronik-client": "^0.8.2",
"cordova": "^10.0.0",
"cordova-android": "^10.1.0",
"cordova-clipboard": "^1.3.0",
diff --git a/src/app/constants.ts b/src/app/constants.ts
index 45948987a91..513d9e62036 100644
--- a/src/app/constants.ts
+++ b/src/app/constants.ts
@@ -1,3 +1,36 @@
export const CARD_IAB_CONFIG =
'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no,hidden=yes,clearcache=yes,hidespinner=yes,disallowoverscroll=yes,zoom=no,transitionstyle=crossdissolve';
export const DUST_AMOUNT = 546;
+export const currency = {
+ name: 'Lotus',
+ ticker: 'XPI',
+ legacyPrefix: 'bitcoincash',
+ prefixes: ['lotus'],
+ coingeckoId: 'bitcoin-cash-abc-2',
+ defaultFee: 1.01,
+ dustSats: 550,
+ etokenSats: 546,
+ cashDecimals: 6,
+ blockExplorerUrl: 'https://explorer.givelotus.org',
+ tokenExplorerUrl: 'https://explorer.be.cash',
+ blockExplorerUrlTestnet: 'https://texplorer.bitcoinabc.org',
+ tokenName: 'eToken',
+ tokenTicker: 'eToken',
+ tokenPrefixes: ['etoken'],
+ tokenIconsUrl: '', // https://tokens.bitcoin.com/32 for BCH SLP
+ txHistoryCount: 10,
+ hydrateUtxoBatchSize: 20,
+ defaultSettings: { fiatCurrency: 'usd' },
+ opReturn: {
+ opReturnPrefixHex: '6a',
+ opReturnAppPrefixLengthHex: '04',
+ opPushDataOne: '4c',
+ appPrefixesHex: {
+ eToken: '534c5000',
+ lotusChat: '02020202',
+ lotusChatEncrypted: '03030303'
+ },
+ encryptedMsgByteLimit: 206,
+ unencryptedMsgByteLimit: 215
+ }
+};
\ No newline at end of file
diff --git a/src/app/pages/send/confirm/confirm.ts b/src/app/pages/send/confirm/confirm.ts
index aaa57f9c262..e83c132c76d 100644
--- a/src/app/pages/send/confirm/confirm.ts
+++ b/src/app/pages/send/confirm/confirm.ts
@@ -33,14 +33,17 @@ import {
TransactionProposal,
WalletProvider
} from '../../../providers/wallet/wallet';
-import { IonRouterOutlet, ModalController, NavController, NavParams } from '@ionic/angular';
+import {
+ IonRouterOutlet,
+ ModalController,
+ NavController,
+ NavParams
+} from '@ionic/angular';
import { EventManagerService } from 'src/app/providers/event-manager.service';
import { Router } from '@angular/router';
import { ChooseFeeLevelModal } from '../../choose-fee-level/choose-fee-level';
-import { FinishModalPage } from '../../finish/finish';
-import { PreviousRouteService } from 'src/app/providers/previous-route/previous-route';
import { LoadingProvider } from 'src/app/providers/loading/loading';
-import { EventsService } from 'src/app/providers/events.service';
+import { OnchainMessageProvider } from 'src/app/providers';
@Component({
selector: 'page-confirm',
templateUrl: 'confirm.html',
@@ -165,14 +168,21 @@ export class ConfirmPage {
private location: Location,
private routerOutlet: IonRouterOutlet,
private loadingProvider: LoadingProvider,
- private eventsService: EventsService
+ private onchainMessageProvider: OnchainMessageProvider
) {
if (this.router.getCurrentNavigation()) {
- this.navParamsData = this.router.getCurrentNavigation().extras.state ? this.router.getCurrentNavigation().extras.state : {};
+ this.navParamsData = this.router.getCurrentNavigation().extras.state
+ ? this.router.getCurrentNavigation().extras.state
+ : {};
} else {
this.navParamsData = history ? history.state : {};
}
- if (_.isEmpty(this.navParamsData) && this.navParams && !_.isEmpty(this.navParams.data)) this.navParamsData = this.navParams.data;
+ if (
+ _.isEmpty(this.navParamsData) &&
+ this.navParams &&
+ !_.isEmpty(this.navParams.data)
+ )
+ this.navParamsData = this.navParams.data;
this.wallet = this.profileProvider.getWallet(this.navParamsData.walletId);
this.isDonation = this.navParamsData.isDonation;
@@ -232,7 +242,7 @@ export class ConfirmPage {
this.routerOutlet.swipeGesture = true;
}
- loadInit() {
+ async loadInit() {
this.logger.info('Loaded: ConfirmPage');
this.routerOutlet.swipeGesture = false;
this.isOpenSelector = false;
@@ -248,12 +258,10 @@ export class ConfirmPage {
amount = this.navParamsData.amount
? this.navParamsData.amount
: this.navParamsData.totalInputsAmount;
- }
- else if (this.navParamsData.isSentXecToEtoken) {
+ } else if (this.navParamsData.isSentXecToEtoken) {
networkName = this.navParamsData.network;
amount = this.navParamsData.amount;
- }
- else {
+ } else {
amount = this.navParamsData.amount;
try {
networkName = this.addressProvider.getCoinAndNetwork(
@@ -282,7 +290,25 @@ export class ConfirmPage {
return;
}
}
-
+ let messageEncrypted = null;
+ if (
+ !!(
+ this.navParamsData &&
+ this.navParamsData.messageOnChain &&
+ this.navParamsData.messageOnChain.trim().length > 0
+ )
+ ) {
+ const result = await this.walletProvider.getMnemonicAndPassword(
+ this.wallet
+ );
+ messageEncrypted =
+ await this.onchainMessageProvider.processEncryptMessageOnchain(
+ this.navParamsData.messageOnChain,
+ this.wallet,
+ result.mnemonic,
+ this.navParamsData.toAddress
+ );
+ }
this.tx = {
toAddress: this.navParamsData.toAddress,
description: this.navParamsData.description,
@@ -291,7 +317,7 @@ export class ConfirmPage {
invoiceID: this.navParamsData.invoiceID, // xrp
payProUrl: this.navParamsData.payProUrl,
spendUnconfirmed: this.config.wallet.spendUnconfirmed,
- messageOnChain: this.navParamsData.messageOnChain,
+ messageOnChain: !!messageEncrypted ? Array.from(messageEncrypted) : null,
messageOnChainToShow: this.navParamsData.messageOnChain,
// Vanity tx info (not in the real tx)
recipientType: this.navParamsData.recipientType,
@@ -319,15 +345,15 @@ export class ConfirmPage {
? 0
: this.tx.coin == 'eth' ||
this.currencyProvider.isERCToken(this.tx.coin)
- ? Number(amount)
- : parseInt(amount, 10);
+ ? Number(amount)
+ : parseInt(amount, 10);
this.tx.origToAddress = this.tx.toAddress;
if (this.navParamsData.requiredFeeRate) {
this.usingMerchantFee = true;
- this.tx.feeRate = this.requiredFeeRate = +this.navParamsData
- .requiredFeeRate;
+ this.tx.feeRate = this.requiredFeeRate =
+ +this.navParamsData.requiredFeeRate;
} else if (this.isSpeedUpTx) {
this.usingCustomFee = true;
this.tx.feeLevel =
@@ -511,7 +537,8 @@ export class ConfirmPage {
this.wallet.credentials.multisigEthInfo &&
this.wallet.credentials.multisigEthInfo.multisigContractAddress
) {
- this.tx.multisigContractAddress = this.wallet.credentials.multisigEthInfo.multisigContractAddress;
+ this.tx.multisigContractAddress =
+ this.wallet.credentials.multisigEthInfo.multisigContractAddress;
}
this.setButtonText(
@@ -572,7 +599,7 @@ export class ConfirmPage {
return (
this.wallet.cachedStatus &&
this.wallet.cachedStatus.balance.totalAmount >=
- this.tx.amount + this.tx.feeRate &&
+ this.tx.amount + this.tx.feeRate &&
!this.tx.spendUnconfirmed
);
}
@@ -854,21 +881,20 @@ export class ConfirmPage {
}
showHighFeeSheet() {
- const minerFeeWarning = this.actionSheetProvider.createMinerFeeWarningComponent();
+ const minerFeeWarning =
+ this.actionSheetProvider.createMinerFeeWarningComponent();
minerFeeWarning.present({ maxHeight: '100%', minHeight: '100%' });
}
showTotalAmountSheet() {
- const totalAmountFeeInfoSheet = this.actionSheetProvider.createInfoSheet(
- 'total-amount'
- );
+ const totalAmountFeeInfoSheet =
+ this.actionSheetProvider.createInfoSheet('total-amount');
totalAmountFeeInfoSheet.present();
}
showSubtotalAmountSheet() {
- const subtotalAmountFeeInfoSheet = this.actionSheetProvider.createInfoSheet(
- 'subtotal-amount'
- );
+ const subtotalAmountFeeInfoSheet =
+ this.actionSheetProvider.createInfoSheet('subtotal-amount');
subtotalAmountFeeInfoSheet.present();
}
@@ -938,9 +964,9 @@ export class ConfirmPage {
this.tx = tx;
this.logger.debug(
'Confirm. TX Fully Updated for wallet:' +
- wallet.id +
- ' Txp:' +
- txp.id
+ wallet.id +
+ ' Txp:' +
+ txp.id
);
this.getTotalAmountDetails(tx, wallet);
@@ -1274,8 +1300,7 @@ export class ConfirmPage {
.Transactions.get({ chain: 'ETHMULTISIG' })
.instantiateEncodeData({
addresses: this.navParamsData.multisigAddresses,
- requiredConfirmations: this.navParamsData
- .requiredConfirmations,
+ requiredConfirmations: this.navParamsData.requiredConfirmations,
multisigGnosisContractAddress: tx.multisigContractAddress,
dailyLimit: 0
});
@@ -1332,10 +1357,11 @@ export class ConfirmPage {
sender: txp.from,
txId: txp.txid
};
- multisigContractInstantiationInfo = await this.walletProvider.getMultisigContractInstantiationInfo(
- this.wallet,
- opts
- );
+ multisigContractInstantiationInfo =
+ await this.walletProvider.getMultisigContractInstantiationInfo(
+ this.wallet,
+ opts
+ );
if (multisigContractInstantiationInfo.length > 0) {
const multisigContract = multisigContractInstantiationInfo.filter(
multisigContract => {
@@ -1404,13 +1430,14 @@ export class ConfirmPage {
}
private showInsufficientFundsInfoSheet(): void {
- const insufficientFundsInfoSheet = this.actionSheetProvider.createInfoSheet(
- 'insufficient-funds'
- );
+ const insufficientFundsInfoSheet =
+ this.actionSheetProvider.createInfoSheet('insufficient-funds');
insufficientFundsInfoSheet.present();
insufficientFundsInfoSheet.onDidDismiss(option => {
if (option || typeof option === 'undefined') {
- this.fromWalletDetails ? this.location.back() : this.router.navigate(['']);
+ this.fromWalletDetails
+ ? this.location.back()
+ : this.router.navigate(['']);
} else {
this.tx.sendMax = true;
this.setWallet(this.wallet);
@@ -1454,7 +1481,9 @@ export class ConfirmPage {
return;
}
if (exit) {
- this.fromWalletDetails ? this.location.back() : this.router.navigate(['']);
+ this.fromWalletDetails
+ ? this.location.back()
+ : this.router.navigate(['']);
}
});
}
@@ -1485,11 +1514,11 @@ export class ConfirmPage {
if (error.toString().includes('500 - "{}"')) {
msg = this.tx.paypro
? this.translate.instant(
- 'There is a temporary problem with the merchant requesting the payment. Please try later'
- )
+ 'There is a temporary problem with the merchant requesting the payment. Please try later'
+ )
: this.translate.instant(
- 'Error 500 - There is a temporary problem, please try again later.'
- );
+ 'Error 500 - There is a temporary problem, please try again later.'
+ );
}
const infoSheetTitle = title ? title : this.translate.instant('Error');
@@ -1501,7 +1530,7 @@ export class ConfirmPage {
if (exit) {
this.fromWalletDetails
? // PopTo AmountPage case
- this.location.back()
+ this.location.back()
: this.router.navigate([''], { replaceUrl: true });
}
}
@@ -1517,7 +1546,7 @@ export class ConfirmPage {
else this.setWallet(option);
}
- public approve(tx, wallet): Promise {
+ public approve(tx, wallet): any {
if (!tx || (!wallet && !this.coinbaseAccount)) return undefined;
if (this.nameContact && this.nameContact.trim().length > 0) {
this.ab
@@ -1712,7 +1741,7 @@ export class ConfirmPage {
},
replaceUrl: true
});
- })
+ });
// TODO: Test handle key not update
// .then(
// () => {
@@ -1850,9 +1879,8 @@ export class ConfirmPage {
title: this.walletSelectorTitle,
coinbaseData
};
- const walletSelector = this.actionSheetProvider.createWalletSelector(
- params
- );
+ const walletSelector =
+ this.actionSheetProvider.createWalletSelector(params);
walletSelector.present();
walletSelector.onDidDismiss(option => {
this.onSelectWalletEvent(option);
@@ -1892,9 +1920,8 @@ export class ConfirmPage {
}
private showCustomFeeWarningSheet(data) {
- const warningSheet = this.actionSheetProvider.createInfoSheet(
- 'custom-fee-warning'
- );
+ const warningSheet =
+ this.actionSheetProvider.createInfoSheet('custom-fee-warning');
warningSheet.present();
warningSheet.onDidDismiss(option => {
option ? this.chooseFeeLevel() : this.onFeeModalDismiss(data);
@@ -1917,9 +1944,8 @@ export class ConfirmPage {
public setGasLimit(): void {
this.editGasLimit = !this.editGasLimit;
- this.tx.gasLimit = this.tx.txp[
- this.wallet.id
- ].gasLimit = this.customGasLimit;
+ this.tx.gasLimit = this.tx.txp[this.wallet.id].gasLimit =
+ this.customGasLimit;
const data = {
newFeeLevel: 'custom',
diff --git a/src/app/pages/tx-details/tx-details.html b/src/app/pages/tx-details/tx-details.html
index 6c2f990368b..c86cad45856 100644
--- a/src/app/pages/tx-details/tx-details.html
+++ b/src/app/pages/tx-details/tx-details.html
@@ -205,12 +205,14 @@
- Live your life with smiles, not tears. Beat your age with friends and not years. Happy birthday!
-
-
-
- {{'Reply' | translate}}
-
+ {{messageOnchain}}
+ 0 && btx.action == 'received'">
+
+
+ {{'Reply' | translate}}
+
+
diff --git a/src/app/pages/tx-details/tx-details.ts b/src/app/pages/tx-details/tx-details.ts
index 7c7b8bf7e35..80e8d6b4497 100644
--- a/src/app/pages/tx-details/tx-details.ts
+++ b/src/app/pages/tx-details/tx-details.ts
@@ -20,17 +20,21 @@ import { EventManagerService } from 'src/app/providers/event-manager.service';
import { ModalController, NavController, NavParams } from '@ionic/angular';
import { Location } from '@angular/common';
import { PersistenceProvider } from 'src/app/providers/persistence/persistence';
-import { AddressBookProvider, AppProvider, TokenProvider } from 'src/app/providers';
+import {
+ AddressBookProvider,
+ AppProvider,
+ TokenProvider
+} from 'src/app/providers';
import { Router } from '@angular/router';
import { DecimalFormatBalance } from 'src/app/providers/decimal-format.ts/decimal-format';
import { Token } from 'src/app/models/tokens/tokens.model';
export interface TokenData {
- amountToken: string,
- tokenId: string,
- symbolToken: string,
- name: string,
- addressToShow: string
+ amountToken: string;
+ tokenId: string;
+ symbolToken: string;
+ name: string;
+ addressToShow: string;
}
@Component({
@@ -39,9 +43,9 @@ export interface TokenData {
styleUrls: ['tx-details.scss'],
encapsulation: ViewEncapsulation.None
})
-
export class TxDetailsModal {
private txId: string;
+ public messageOnchain: string = '';
private config;
private blockexplorerUrl: string;
private blockexplorerUrlTestnet: string;
@@ -88,14 +92,17 @@ export class TxDetailsModal {
private appProvider: AppProvider,
private router: Router,
private tokenProvider: TokenProvider,
- private addressbookProvider: AddressBookProvider,
- ) { }
-
+ private addressbookProvider: AddressBookProvider
+ ) {}
+
ngOnInit() {
this.events.subscribe('bwsEvent', this.bwsEventHandler);
this.config = this.configProvider.get();
this.currentTheme = this.appProvider.themeProvider.currentAppTheme;
this.txId = this.navParams.data.txid;
+ if (this.navParams.data && this.navParams.data.messageOnchain) {
+ this.messageOnchain = this.navParams.data.messageOnchain;
+ }
this.title = this.translate.instant('Transaction');
this.wallet = this.profileProvider.getWallet(this.navParams.data.walletId);
this.tokenData = this.navParams.data.tokenData;
@@ -238,7 +245,7 @@ export class TxDetailsModal {
leading: true
}
);
-
+
async updateInputAddress(txId: string) {
let inputAddresses = [];
try {
@@ -254,14 +261,17 @@ export class TxDetailsModal {
try {
const walletId = this.navParams.data.walletId;
const history = await this.walletProvider.getSavedTxs(walletId);
- if (!history) return ;
+ if (!history) return;
const historyByTxId = _.find(history, item => item.txid == txid);
if (historyByTxId) {
historyByTxId.inputAddresses = inputAddresses;
const historyToSave = JSON.stringify(history);
- return await this.persistenceProvider.setTxHistory(walletId, historyToSave);
+ return await this.persistenceProvider.setTxHistory(
+ walletId,
+ historyToSave
+ );
}
- } catch (error) { }
+ } catch (error) {}
}
private updateTx(opts?): void {
@@ -272,7 +282,6 @@ export class TxDetailsModal {
.then(async tx => {
this.retryGetTx = 0;
if (!opts.hideLoading) this.onGoingProcess.clear();
-
this.btx = this.txFormatProvider.processTx(this.wallet.coin, tx);
this.btx.network = this.wallet.credentials.network;
this.btx.coin = this.wallet.coin;
@@ -307,27 +316,26 @@ export class TxDetailsModal {
}
if (this.btx.action != 'invalid') {
-
if (this.btx.isGenesis) {
this.title = this.translate.instant('Genesis');
} else {
- if (this.btx.action == 'sent'){
+ if (this.btx.action == 'sent') {
this.title = this.translate.instant('Sent');
this.isNegative = true;
}
- if (this.btx.action == 'received'){
+ if (this.btx.action == 'received') {
this.title = this.translate.instant('Received');
this.isNegative = false;
}
- if (this.btx.action == 'moved'){
+ if (this.btx.action == 'moved') {
this.title = this.translate.instant('Sent to self');
this.isNegative = false;
}
- if (this.btx.action == 'immature'){
+ if (this.btx.action == 'immature') {
this.title = this.translate.instant('Immature');
this.isNegative = false;
}
- if (this.btx.action == 'mined'){
+ if (this.btx.action == 'mined') {
this.title = this.translate.instant('Mined');
this.isNegative = false;
}
@@ -338,7 +346,7 @@ export class TxDetailsModal {
this.initActionList();
this.updateFiatRate();
- if(this.token){
+ if (this.token) {
this.getFiatRateStrToken();
}
if (this.currencyProvider.isUtxoCoin(this.wallet.coin)) {
@@ -385,19 +393,26 @@ export class TxDetailsModal {
tokenInfo: {
symbol: this.btx?.symbolToken
}
- }
- const alternativeBalanceToken = this.tokenProvider.getAlternativeBalanceToken(token, this.wallet);
- let rate = this.rateProvider.getRate(this.wallet.cachedStatus.alternativeIsoCode, token.tokenInfo.symbol);
+ };
+ const alternativeBalanceToken =
+ this.tokenProvider.getAlternativeBalanceToken(token, this.wallet);
+ let rate = this.rateProvider.getRate(
+ this.wallet.cachedStatus.alternativeIsoCode,
+ token.tokenInfo.symbol
+ );
if (!rate) {
rate = 0;
}
- this.fiatRateStrToken =
- DecimalFormatBalance(alternativeBalanceToken) +
- ' ' +
- this.wallet.cachedStatus.alternativeIsoCode +
- ' @ ' + DecimalFormatBalance(rate) + ' ' +
- this.wallet.cachedStatus.alternativeIsoCode + ' per ' +
- token.tokenInfo.symbol.toUpperCase();
+ this.fiatRateStrToken =
+ DecimalFormatBalance(alternativeBalanceToken) +
+ ' ' +
+ this.wallet.cachedStatus.alternativeIsoCode +
+ ' @ ' +
+ DecimalFormatBalance(rate) +
+ ' ' +
+ this.wallet.cachedStatus.alternativeIsoCode +
+ ' per ' +
+ token.tokenInfo.symbol.toUpperCase();
}
public async saveMemoInfo(): Promise {
@@ -462,9 +477,7 @@ export class TxDetailsModal {
}
}
- public handleClick(btx) {
-
- }
+ public handleClick(btx) {}
public openExternalLink(url: string): void {
const optIn = true;
@@ -498,7 +511,8 @@ export class TxDetailsModal {
this.getFiatStr(fiat) +
' ' +
settings.alternativeIsoCode +
- ' @ ' + this.getAlternativeIsoCode(fiat) +
+ ' @ ' +
+ this.getAlternativeIsoCode(fiat) +
` ${settings.alternativeIsoCode} per ` +
this.wallet.coin.toUpperCase();
} else {
@@ -508,13 +522,21 @@ export class TxDetailsModal {
}
getAlternativeIsoCode(fiat) {
- return this.btx.coin == 'xpi' || this.btx.coin == 'xec' ? parseFloat(fiat.rate).toFixed(6).toString() : this.filter.formatFiatAmount(fiat.rate);
+ return this.btx.coin == 'xpi' || this.btx.coin == 'xec'
+ ? parseFloat(fiat.rate).toFixed(6).toString()
+ : this.filter.formatFiatAmount(fiat.rate);
}
getFiatStr(fiat) {
return this.btx.coin == 'xpi' || this.btx.coin == 'xec'
- ? parseFloat((fiat.rate * this.btx.amountValueStr.replace(',', '')).toFixed(4)).toString()
- : this.filter.formatFiatAmount(parseFloat((fiat.rate * this.btx.amountValueStr.replace(',', '')).toFixed(2)));
+ ? parseFloat(
+ (fiat.rate * this.btx.amountValueStr.replace(',', '')).toFixed(4)
+ ).toString()
+ : this.filter.formatFiatAmount(
+ parseFloat(
+ (fiat.rate * this.btx.amountValueStr.replace(',', '')).toFixed(2)
+ )
+ );
}
close() {
@@ -526,7 +548,14 @@ export class TxDetailsModal {
this.router.navigate(['/send-page'], {
state: {
walletId: this.wallet.id,
- toAddress: btx.address || (btx.addressTo && btx.addressTo !== 'false') ? btx.addressTo : false || (this.tokenData && this.tokenData.addressToShow !== 'false' ? this.tokenData.addressToShow : btx.inputAddresses[0]) || btx.inputAddresses[0],
+ toAddress:
+ btx.address || (btx.addressTo && btx.addressTo !== 'false')
+ ? btx.addressTo
+ : false ||
+ (this.tokenData && this.tokenData.addressToShow !== 'false'
+ ? this.tokenData.addressToShow
+ : btx.inputAddresses[0]) ||
+ btx.inputAddresses[0],
token: this.token
}
});
diff --git a/src/app/pages/wallet-details/wallet-details.ts b/src/app/pages/wallet-details/wallet-details.ts
index 507077cb3b7..7271becad35 100644
--- a/src/app/pages/wallet-details/wallet-details.ts
+++ b/src/app/pages/wallet-details/wallet-details.ts
@@ -20,7 +20,8 @@ import {
ConfigProvider,
CurrencyProvider,
EventManagerService,
- LoadingProvider
+ LoadingProvider,
+ OnchainMessageProvider
} from '../../providers/index';
import { Logger } from '../../providers/logger/logger';
import { PlatformProvider } from '../../providers/platform/platform';
@@ -32,7 +33,12 @@ import { WalletProvider } from '../../providers/wallet/wallet';
import { TxDetailsModal } from '../../pages/tx-details/tx-details';
import { SearchTxModalPage } from './search-tx-modal/search-tx-modal';
import { WalletBalanceModal } from './wallet-balance/wallet-balance';
-import { LoadingController, ModalController, Platform, ToastController } from '@ionic/angular';
+import {
+ LoadingController,
+ ModalController,
+ Platform,
+ ToastController
+} from '@ionic/angular';
import { Router } from '@angular/router';
import { Location } from '@angular/common';
import { NgxQrcodeErrorCorrectionLevels } from '@techiediaries/ngx-qrcode';
@@ -125,7 +131,8 @@ export class WalletDetailsPage {
private location: Location,
public toastController: ToastController,
private loadingCtrl: LoadingController,
- private eventsService: EventsService
+ private eventsService: EventsService,
+ private onchainMessageService: OnchainMessageProvider
) {
this.currentTheme = this.appProvider.themeProvider.currentAppTheme;
if (this.router.getCurrentNavigation()) {
@@ -381,6 +388,42 @@ export class WalletDetailsPage {
0,
(this.currentPage + 1) * HISTORY_SHOW_LIMIT
);
+ if (this.history && this.history.length > 0) {
+ const result = await this.walletProvider.getMnemonicAndPassword(
+ this.wallet
+ );
+ for (let index = 0; index < this.history.length; index++) {
+
+ const tx = this.history[index];
+ if(!(tx.messageOnchain && tx.messageOnchain.length > 0)){
+ const outputFound = _.find(
+ tx.outputs,
+ o =>
+ o.outputScript &&
+ o.outputScript.length > 0 &&
+ o.outputScript.includes('030303')
+ );
+ let addressRecepient = "";
+ if(tx.action === 'received'){
+ addressRecepient = tx.inputAddresses[0];
+ } else{
+ addressRecepient = _.find(
+ tx.outputs,
+ o => !o.outputScript
+ ).address;
+ }
+ if (outputFound) {
+ tx.messageOnchain = await
+ this.onchainMessageService.processDecryptMessageOnchain(
+ outputFound.outputScript,
+ this.wallet,
+ result.mnemonic,
+ addressRecepient
+ );
+ }
+ }
+ }
+ }
this.zone.run(() => {
this.groupedHistory = this.groupHistory(this.history);
});
@@ -389,18 +432,21 @@ export class WalletDetailsPage {
loader.dismiss();
}, 1000);
}
-
- handleClick(tx){
- this.showReplyMessageModal(tx);
+ handleClick(tx) {
+ this.showReplyMessageModal(tx);
}
- getAddressFrom(tx): any{
- if((!this.addressbook || !tx.inputAddresses[0] || !this.getContactName(tx.inputAddresses[0]))){
+ getAddressFrom(tx): any {
+ if (
+ !this.addressbook ||
+ !tx.inputAddresses[0] ||
+ !this.getContactName(tx.inputAddresses[0])
+ ) {
return {
name: tx.inputAddresses[0].slice(-8),
- address: tx.inputAddresses[0],
+ address: tx.inputAddresses[0],
type: ''
- }
+ };
}
// else if(this.addressbook && tx.inputAddresses[0] && this.getContactName(tx.inputAddresses[0])){
// return {
@@ -409,50 +455,64 @@ export class WalletDetailsPage {
// type: 'contact'
// }
// }
- else return {
- name: this.getContactName(tx.inputAddresses[0]),
- address: tx.inputAddresses[0],
- type: 'contact'
- }
+ else
+ return {
+ name: this.getContactName(tx.inputAddresses[0]),
+ address: tx.inputAddresses[0],
+ type: 'contact'
+ };
}
- getAddressTo(tx): any{
- if((!tx.note || (tx.note && !tx.note.body)) && (!this.addressbook || !tx.outputs[0] || !this.getContactName(tx.outputs[0].address)) && (!tx.customData || !tx.customData.toWalletName)){
+ getAddressTo(tx): any {
+ if (
+ (!tx.note || (tx.note && !tx.note.body)) &&
+ (!this.addressbook ||
+ !tx.outputs[0] ||
+ !this.getContactName(tx.outputs[0].address)) &&
+ (!tx.customData || !tx.customData.toWalletName)
+ ) {
return {
name: tx.addressTo.slice(-8),
address: tx.addressTo,
type: ''
- }
- }
- else if((!tx.note || (tx.note && !tx.note.body)) && (!this.addressbook || !tx.outputs[0] || !this.getContactName(tx.outputs[0].address)) && (tx.customData && tx.customData.toWalletName)){
+ };
+ } else if (
+ (!tx.note || (tx.note && !tx.note.body)) &&
+ (!this.addressbook ||
+ !tx.outputs[0] ||
+ !this.getContactName(tx.outputs[0].address)) &&
+ tx.customData &&
+ tx.customData.toWalletName
+ ) {
return {
name: tx.customData.toWalletName,
address: tx.outputs[0].address,
type: 'wallet'
- }
- }
- else return {
- name: this.getContactName(tx.outputs[0].address),
- address: tx.outputs[0].address,
- type: 'contact'
- }
+ };
+ } else
+ return {
+ name: this.getContactName(tx.outputs[0].address),
+ address: tx.outputs[0].address,
+ type: 'contact'
+ };
}
showReplyMessageModal(tx) {
const txInfo = this.getAddressFrom(tx);
- const addContactModal = this.actionSheetProvider.createMessageReplyComponent({
- addressTo: this.getAddressFrom(tx).name,
- messageOnChain: tx.messageOnchain
- });
+ const addContactModal =
+ this.actionSheetProvider.createMessageReplyComponent({
+ addressTo: this.getAddressFrom(tx).name,
+ messageOnChain: tx.messageOnchain
+ });
addContactModal.present({ maxHeight: '48%%', minHeight: '48%%' });
- addContactModal.onDidDismiss((rs) => {
+ addContactModal.onDidDismiss(rs => {
if (rs) {
this.sendReplyMessage(rs, txInfo);
}
});
}
- sendReplyMessage(rs, txInfo){
+ sendReplyMessage(rs, txInfo) {
this.router.navigate(['/confirm'], {
state: {
walletId: this.wallet.credentials.walletId,
@@ -675,8 +735,8 @@ export class WalletDetailsPage {
}
};
- public itemTapped(tx, itemTapped){
- if(itemTapped.target.innerText === 'Reply'){
+ public itemTapped(tx, itemTapped) {
+ if (itemTapped.target.innerText === 'Reply') {
itemTapped.preventDefault();
itemTapped.stopPropagation();
return;
@@ -737,7 +797,8 @@ export class WalletDetailsPage {
component: TxDetailsModal,
componentProps: {
walletId: this.wallet.credentials.walletId,
- txid: tx.txid
+ txid: tx.txid,
+ messageOnchain: tx.messageOnchain
}
})
.then(res => {
diff --git a/src/app/providers/index.ts b/src/app/providers/index.ts
index f15edb985b5..8101a3f226e 100644
--- a/src/app/providers/index.ts
+++ b/src/app/providers/index.ts
@@ -75,4 +75,5 @@ export { CustomErrorHandler } from './custom-error-handler.service';
export { RedirectGuard } from './redirect.service';
export { PreviousRouteService } from './previous-route/previous-route';
export { TokenProvider } from './token-sevice/token-sevice';
+export { OnchainMessageProvider } from './onchain-message/onchain-message';
export { LoadingProvider } from './loading/loading';
\ No newline at end of file
diff --git a/src/app/providers/wallet/wallet.ts b/src/app/providers/wallet/wallet.ts
index 1b14e626320..54dd255ac85 100644
--- a/src/app/providers/wallet/wallet.ts
+++ b/src/app/providers/wallet/wallet.ts
@@ -1063,6 +1063,18 @@ export class WalletProvider {
delete tx.note.encryptedBody;
}
+ const outputFound = _.find(
+ tx.outputs,
+ o =>
+ o.outputScript &&
+ o.outputScript.length > 0 &&
+ o.outputScript.includes('030303')
+ );
+
+ if(outputFound){
+ tx.outputScript = outputFound.outputScript;
+ }
+
if (!txHistoryUnique[tx.txid]) {
ret.push(tx);
txHistoryUnique[tx.txid] = true;
From 4129a88a34ee5fa884258edc0633fd5c3c70bbd3 Mon Sep 17 00:00:00 2001
From: takYoon
Date: Thu, 23 Mar 2023 13:17:36 +0700
Subject: [PATCH 07/15] only wallet xpi and single address can use feature
onchain message
---
.../recipient/recipient.component.ts | 7 +-
src/app/pages/send/confirm/confirm.ts | 12 +-
src/app/pages/send/send.ts | 9 +-
src/app/pages/tx-details/tx-details.ts | 1 -
.../pages/wallet-details/wallet-details.ts | 76 +++--
.../onchain-message/onchain-message.ts | 319 ++++++++++++++++++
6 files changed, 381 insertions(+), 43 deletions(-)
create mode 100644 src/app/providers/onchain-message/onchain-message.ts
diff --git a/src/app/components/recipient/recipient.component.ts b/src/app/components/recipient/recipient.component.ts
index fb9ab0c39a0..92883185b32 100644
--- a/src/app/components/recipient/recipient.component.ts
+++ b/src/app/components/recipient/recipient.component.ts
@@ -50,6 +50,7 @@ import { Contact } from 'src/app/providers/address-book/address-book';
export class RecipientComponent implements OnInit {
public search: string = '';
public amount: string = '';
+ public amountResult: number = 0;
navParamsData: any;
public isCordova: boolean;
public expression;
@@ -76,7 +77,7 @@ export class RecipientComponent implements OnInit {
public searchValue: string;
validAddress = false;
validAmount = false;
- validMessage = true;
+ validMessage = false;
isSelectedTotalAmout: boolean = false;
remaining: number;
isShowReceiveLotus: boolean;
@@ -522,6 +523,7 @@ export class RecipientComponent implements OnInit {
this.recipient.amount = parseInt(amount, 10);
}
this.validAmount = result > 0;
+ this.amountResult = result;
this.checkRecipientValid();
if (isSendMax) {
this.sendMaxEvent.emit(true);
@@ -765,8 +767,9 @@ export class RecipientComponent implements OnInit {
checkRecipientValid() {
if (!this.isDonation) {
- this.recipient.isValid = this.validAddress && this.validAmount && this.validMessage;
+ this.recipient.isValid = this.validAddress && (this.validAmount || this.validMessage);
} else {
+
if (this.isShowReceiveLotus) {
this.recipient.isValid = this.validAddress && this.validAmount;
} else {
diff --git a/src/app/pages/send/confirm/confirm.ts b/src/app/pages/send/confirm/confirm.ts
index e83c132c76d..ebabb7079f6 100644
--- a/src/app/pages/send/confirm/confirm.ts
+++ b/src/app/pages/send/confirm/confirm.ts
@@ -44,6 +44,7 @@ import { Router } from '@angular/router';
import { ChooseFeeLevelModal } from '../../choose-fee-level/choose-fee-level';
import { LoadingProvider } from 'src/app/providers/loading/loading';
import { OnchainMessageProvider } from 'src/app/providers';
+import { DUST_AMOUNT } from 'src/app/constants';
@Component({
selector: 'page-confirm',
templateUrl: 'confirm.html',
@@ -301,13 +302,18 @@ export class ConfirmPage {
const result = await this.walletProvider.getMnemonicAndPassword(
this.wallet
);
- messageEncrypted =
+ try{
+ messageEncrypted =
await this.onchainMessageProvider.processEncryptMessageOnchain(
this.navParamsData.messageOnChain,
this.wallet,
result.mnemonic,
this.navParamsData.toAddress
);
+ } catch(e){
+ this.showErrorInfoSheet(e);
+ this.location.back();
+ }
}
this.tx = {
toAddress: this.navParamsData.toAddress,
@@ -942,8 +948,8 @@ export class ConfirmPage {
if (!this.minAllowedGasLimit)
this.minAllowedGasLimit = this.tx.txp[wallet.id].gasLimit;
}
-
- if (txp.feeTooHigh) {
+ txp.messageOnChain = tx.messageOnChain;
+ if (txp.feeTooHigh && ((!this.navParamsData.messageOnChain && !txp.messageOnChain) || (txp.messageOnChain && txp.amount !== DUST_AMOUNT))) {
this.showHighFeeSheet();
}
diff --git a/src/app/pages/send/send.ts b/src/app/pages/send/send.ts
index 2b6164c261f..b7776ec74c4 100644
--- a/src/app/pages/send/send.ts
+++ b/src/app/pages/send/send.ts
@@ -32,6 +32,7 @@ import { PageDto, PageModel } from 'src/app/providers/lixi-lotus/lixi-lotus';
import { EventsService } from 'src/app/providers/events.service';
import { Location } from '@angular/common';
+import { DUST_AMOUNT } from 'src/app/constants';
@Component({
@@ -320,7 +321,9 @@ export class SendPage {
}))
this.isShowSendMax = this.listRecipient.length === 1;
this.isShowDelete = this.listRecipient.length > 1;
- this.isShowMessage = this.listRecipient.length === 1;
+ if(this.wallet.coin === 'xpi' && this.wallet.cachedStatus.wallet.singleAddress){
+ this.isShowMessage = this.listRecipient.length === 1;
+ }
this.content.scrollToBottom(1000);
}
@@ -373,6 +376,10 @@ export class SendPage {
if (this.isDonation) return this.goToConfirmDonation();
if (this.listRecipient.length === 1) {
const recipient = this.listRecipient[0];
+ if(!recipient.amount || recipient.amount === 0){
+ recipient.amount = DUST_AMOUNT;
+ }
+
this.router.navigate(['/confirm'], {
state: {
walletId: this.wallet.credentials.walletId,
diff --git a/src/app/pages/tx-details/tx-details.ts b/src/app/pages/tx-details/tx-details.ts
index 7217bf37d42..3609934d93e 100644
--- a/src/app/pages/tx-details/tx-details.ts
+++ b/src/app/pages/tx-details/tx-details.ts
@@ -66,7 +66,6 @@ export class TxDetailsModal {
public isNegative: boolean;
public currentTheme;
public fiatRateStrToken;
- public messageOnchain: string;
public addressbook = [];
constructor(
diff --git a/src/app/pages/wallet-details/wallet-details.ts b/src/app/pages/wallet-details/wallet-details.ts
index 7de90be130f..47375751682 100644
--- a/src/app/pages/wallet-details/wallet-details.ts
+++ b/src/app/pages/wallet-details/wallet-details.ts
@@ -387,38 +387,42 @@ export class WalletDetailsPage {
0,
(this.currentPage + 1) * HISTORY_SHOW_LIMIT
);
- if (this.history && this.history.length > 0) {
- const result = await this.walletProvider.getMnemonicAndPassword(
- this.wallet
- );
- for (let index = 0; index < this.history.length; index++) {
-
- const tx = this.history[index];
- if(!(tx.messageOnchain && tx.messageOnchain.length > 0)){
- const outputFound = _.find(
- tx.outputs,
- o =>
- o.outputScript &&
- o.outputScript.length > 0 &&
- o.outputScript.includes('030303')
- );
- let addressRecepient = "";
- if(tx.action === 'received'){
- addressRecepient = tx.inputAddresses[0];
- } else{
- addressRecepient = _.find(
+ if (
+ this.wallet.coin === 'xpi' &&
+ this.wallet.cachedStatus.wallet.singleAddress
+ ) {
+ if (this.history && this.history.length > 0) {
+ const result = await this.walletProvider.getMnemonicAndPassword(
+ this.wallet
+ );
+ for (let index = 0; index < this.history.length; index++) {
+ const tx = this.history[index];
+ if (!(tx.messageOnchain && tx.messageOnchain.length > 0)) {
+ const outputFound = _.find(
tx.outputs,
- o => !o.outputScript
- ).address;
- }
- if (outputFound) {
- tx.messageOnchain = await
- this.onchainMessageService.processDecryptMessageOnchain(
- outputFound.outputScript,
- this.wallet,
- result.mnemonic,
- addressRecepient
- );
+ o =>
+ o.outputScript &&
+ o.outputScript.length > 0 &&
+ o.outputScript.includes('030303')
+ );
+ let addressRecepient = '';
+ if (tx.action === 'received') {
+ addressRecepient = tx.inputAddresses[0];
+ } else {
+ addressRecepient = _.find(
+ tx.outputs,
+ o => !o.outputScript
+ ).address;
+ }
+ if (outputFound) {
+ tx.messageOnchain =
+ await this.onchainMessageService.processDecryptMessageOnchain(
+ outputFound.outputScript,
+ this.wallet,
+ result.mnemonic,
+ addressRecepient
+ );
+ }
}
}
}
@@ -793,11 +797,11 @@ export class WalletDetailsPage {
public async goToTxDetails(tx) {
const txDetailModal = await this.modalCtrl.create({
component: TxDetailsModal,
- componentProps: {
- walletId: this.wallet.credentials.walletId,
- txid: tx.txid,
- messageOnchain: tx.messageOnchain
- }
+ componentProps: {
+ walletId: this.wallet.credentials.walletId,
+ txid: tx.txid,
+ messageOnchain: tx.messageOnchain
+ }
});
txDetailModal.present();
const { data } = await txDetailModal.onWillDismiss();
diff --git a/src/app/providers/onchain-message/onchain-message.ts b/src/app/providers/onchain-message/onchain-message.ts
new file mode 100644
index 00000000000..00b9c9d6e8f
--- /dev/null
+++ b/src/app/providers/onchain-message/onchain-message.ts
@@ -0,0 +1,319 @@
+import { PrivateKey, PublicKey } from '@abcpros/bitcore-lib-xpi';
+import BCHJS from '@abcpros/xpi-js';
+import { Injectable } from '@angular/core';
+import { currency } from 'src/app/constants';
+import { Logger } from '../logger/logger';
+import * as forge from 'node-forge';
+
+import { BitcoreLib } from '@abcpros/crypto-wallet-core';
+import { ChronikClient, TxHistoryPage } from 'chronik-client';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class OnchainMessageProvider {
+ bchjs;
+ Bitcore = BitcoreLib;
+ PrivateKey = this.Bitcore.PrivateKey;
+ PublicKey = this.Bitcore.PublicKey;
+ crypto2 = this.Bitcore.crypto;
+
+ constructor(private logger: Logger) {
+ this.logger.debug('TokenProvider initialized');
+ this.bchjs = new BCHJS({ restURL: '' });
+ }
+
+ ngOnInit() {}
+
+ async getPrivateWifKey(wallet, mnemonic) {
+ const rootSeedBuffer = await this.bchjs.Mnemonic.toSeed(mnemonic);
+ let masterHDNode;
+ masterHDNode = this.bchjs.HDNode.fromSeed(rootSeedBuffer);
+ const rootPath = wallet.getRootPath()
+ ? wallet.getRootPath()
+ : "m/44'/1899'/0'";
+ const node = this.bchjs.HDNode.derivePath(masterHDNode, rootPath);
+ const change = this.bchjs.HDNode.derivePath(node, '0/0');
+ return this.bchjs.HDNode.toWIF(change);
+ }
+
+ parseOpReturn(hexStr) {
+ if (
+ !hexStr ||
+ typeof hexStr !== 'string' ||
+ hexStr.substring(0, 2) !== currency.opReturn.opReturnPrefixHex
+ ) {
+ return false;
+ }
+
+ hexStr = hexStr.slice(2); // remove the first byte i.e. 6a
+
+ /*
+ * @Return: resultArray is structured as follows:
+ * resultArray[0] is the transaction type i.e. eToken prefix, cashtab prefix, external message itself if unrecognized prefix
+ * resultArray[1] is the actual cashtab message or the 2nd part of an external message
+ * resultArray[2 - n] are the additional messages for future protcols
+ */
+ let resultArray = [];
+ let message = '';
+ let hexStrLength = hexStr.length;
+
+ for (let i = 0; hexStrLength !== 0; i++) {
+ // part 1: check the preceding byte value for the subsequent message
+ let byteValue = hexStr.substring(0, 2);
+ let msgByteSize = 0;
+ if (byteValue === currency.opReturn.opPushDataOne) {
+ // if this byte is 4c then the next byte is the message byte size - retrieve the message byte size only
+ msgByteSize = parseInt(hexStr.substring(2, 4), 16); // hex base 16 to decimal base 10
+ hexStr = hexStr.slice(4); // strip the 4c + message byte size info
+ } else {
+ // take the byte as the message byte size
+ msgByteSize = parseInt(hexStr.substring(0, 2), 16); // hex base 16 to decimal base 10
+ hexStr = hexStr.slice(2); // strip the message byte size info
+ }
+
+ // part 2: parse the subsequent message based on bytesize
+ const msgCharLength = 2 * msgByteSize;
+ message = hexStr.substring(0, msgCharLength);
+ if (i === 0 && message === currency.opReturn.appPrefixesHex.eToken) {
+ // add the extracted eToken prefix to array then exit loop
+ resultArray[i] = currency.opReturn.appPrefixesHex.eToken;
+ break;
+ }
+ else {
+ // this is either an external message or a subsequent cashtab message loop to extract the message
+ resultArray[i] = message;
+ }
+
+ // strip out the parsed message
+ hexStr = hexStr.slice(msgCharLength);
+ hexStrLength = hexStr.length;
+ }
+ return resultArray;
+ }
+
+ async getRecipientPublicKey(
+ XPI,
+ chronik: ChronikClient,
+ recipientAddress: string
+ ): Promise {
+ let recipientAddressHash160: string;
+ try {
+ recipientAddressHash160 = XPI.Address.toHash160(recipientAddress);
+ } catch (err) {
+ console.log(
+ `Error determining XPI.Address.toHash160(${recipientAddress} in getRecipientPublicKey())`,
+ err
+ );
+ }
+
+ let chronikTxHistoryAtAddress: TxHistoryPage;
+ try {
+ // Get 20 txs. If no outgoing txs in those 20 txs, just don't send the tx
+ chronikTxHistoryAtAddress = await chronik
+ .script('p2pkh', recipientAddressHash160)
+ .history(/*page=*/ 0, /*page_size=*/ 20);
+ } catch (err) {
+ console.log(
+ `Error getting await chronik.script('p2pkh', ${recipientAddressHash160}).history();`,
+ err
+ );
+ throw new Error('Error fetching tx history to parse for public key');
+ }
+
+ let recipientPubKeyChronik;
+
+ // Iterate over tx history to find an outgoing tx
+ for (let i = 0; i < chronikTxHistoryAtAddress.txs.length; i += 1) {
+ const { inputs } = chronikTxHistoryAtAddress.txs[i];
+ for (let j = 0; j < inputs.length; j += 1) {
+ const thisInput = inputs[j];
+ const thisInputSendingHash160 = thisInput.outputScript;
+ if (thisInputSendingHash160.includes(recipientAddressHash160)) {
+ // Then this is an outgoing tx, you can get the public key from this tx
+ // Get the public key
+ try {
+ recipientPubKeyChronik =
+ chronikTxHistoryAtAddress.txs[i].inputs[j].inputScript.slice(-66);
+ } catch (err) {
+ throw new Error(
+ 'Cannot send an encrypted message to a wallet with no outgoing transactions'
+ );
+ }
+ return recipientPubKeyChronik;
+ }
+ }
+ }
+ // You get here if you find no outgoing txs in the chronik tx history
+ throw new Error(
+ 'Cannot send an encrypted message to a wallet with no outgoing transactions in the last 20 txs'
+ );
+ }
+
+ async processDecryptMessageOnchain(
+ outputScript,
+ wallet,
+ mnemonic,
+ addressRecepient
+ ): Promise {
+ const privateKeyWIF = await this.getPrivateWifKey(wallet, mnemonic);
+ let chronikClient = null;
+ if (wallet.coin === 'xpi') {
+ chronikClient = new ChronikClient('https://chronik.be.cash/xpi');
+ } else {
+ chronikClient = new ChronikClient('https://chronik.be.cash/xec');
+ }
+ const pubKeyHex = await this.getRecipientPublicKey(
+ this.bchjs,
+ chronikClient,
+ addressRecepient
+ );
+ const messageDecrypted = this.decryptMessageOnchain(
+ outputScript,
+ privateKeyWIF,
+ pubKeyHex
+ );
+ return messageDecrypted;
+ }
+
+ async processEncryptMessageOnchain(
+ plainText,
+ wallet,
+ mnemonic,
+ addressRecepient
+ ) {
+ const privateKeyWIF = await this.getPrivateWifKey(wallet, mnemonic);
+ let chronikClient = null;
+ if (wallet.coin === 'xpi') {
+ chronikClient = new ChronikClient('https://chronik.be.cash/xpi');
+ } else {
+ chronikClient = new ChronikClient('https://chronik.be.cash/xec');
+ }
+ let pubKeyHex = await this.getRecipientPublicKey(
+ this.bchjs,
+ chronikClient,
+ addressRecepient
+ );
+ if (!pubKeyHex) {
+ pubKeyHex = '';
+ }
+ const encryptedMessage = this.encryptMessageOnchain(
+ privateKeyWIF,
+ pubKeyHex,
+ plainText
+ );
+ return encryptedMessage;
+ }
+
+ encryptMessageOnchain = (
+ privateKeyWIF: string,
+ recipientPubKeyHex: string,
+ plainTextMsg: string
+ ): Uint8Array => {
+ let encryptedMsg;
+ try {
+ const sharedKey = this.createSharedKey(privateKeyWIF, recipientPubKeyHex);
+ encryptedMsg = this.encrypt(sharedKey, Buffer.from(plainTextMsg));
+ } catch (error) {
+ console.log('ENCRYPTION ERROR', error);
+ throw error;
+ }
+
+ return encryptedMsg;
+ };
+
+ decryptMessageOnchain(opReturnOutput, privateKeyWIF, publicKeyHex) {
+ let attachedMsg = null;
+ const opReturn = this.parseOpReturn(opReturnOutput);
+ switch (opReturn[0]) {
+ // unencrypted LotusChat
+ case currency.opReturn.appPrefixesHex.lotusChat:
+ attachedMsg = Buffer.from(opReturn[1], 'hex');
+ break;
+ case currency.opReturn.appPrefixesHex.lotusChatEncrypted:
+ // attachedMsg = 'Not yet implemented chat encrypted';
+ const sharedKey = this.createSharedKey(privateKeyWIF, publicKeyHex);
+ const decryptedMessage = this.decrypt(
+ sharedKey,
+ Uint8Array.from(Buffer.from(opReturn[1], 'hex'))
+ );
+ attachedMsg = Buffer.from(decryptedMessage).toString('utf8');
+ break;
+ default:
+ break;
+ }
+ return attachedMsg ? attachedMsg.toString() : null;
+ }
+
+ decrypt = (sharedKey: Buffer, cipherText: Uint8Array) => {
+ // Split shared key
+ const iv = forge.util.createBuffer(sharedKey.slice(0, 16));
+ const key = forge.util.createBuffer(sharedKey.slice(16));
+
+ // Encrypt entries
+ const cipher = forge.cipher.createDecipher('AES-CBC', key);
+ cipher.start({ iv });
+ const rawBuffer = forge.util.createBuffer(cipherText);
+ cipher.update(rawBuffer);
+ cipher.finish();
+ const plainText = Uint8Array.from(
+ Buffer.from(cipher.output.toHex(), 'hex')
+ );
+ return plainText;
+ };
+
+ encrypt = (sharedKey: Buffer, plainText: Uint8Array) => {
+ // Split shared key
+ const iv = forge.util.createBuffer(sharedKey.slice(0, 16));
+ const key = forge.util.createBuffer(sharedKey.slice(16));
+
+ // Encrypt entries
+ const cipher = forge.cipher.createCipher('AES-CBC', key);
+ cipher.start({ iv });
+ const rawBuffer = forge.util.createBuffer(plainText);
+ cipher.update(rawBuffer);
+ cipher.finish();
+ const cipherText = Uint8Array.from(
+ Buffer.from(cipher.output.toHex(), 'hex')
+ );
+
+ return cipherText;
+ };
+
+ createSharedKey = (privateKeyWIF: string, publicKeyHex: string): Buffer => {
+ const publicKeyObj = PublicKey.fromBuffer(Buffer.from(publicKeyHex, 'hex'));
+ const privateKeyObj = PrivateKey.fromWIF(privateKeyWIF);
+
+ const mergedKey = this.constructMergedKey(privateKeyObj, publicKeyObj);
+ // const rawMergedKey = mergedKey.toBuffer(); // this function throws assertion error sometimes
+ const rawMergedKey = this.publicKeyToBuffer(mergedKey);
+ const sharedKey = this.crypto2.Hash.sha256(rawMergedKey);
+ return sharedKey;
+ };
+
+ constructMergedKey = (privateKey, publicKey) => {
+ return PublicKey.fromPoint(publicKey.point.mul(privateKey.toBigNumber()));
+ };
+
+ publicKeyToBuffer = pubKey => {
+ const { x, y, compressed } = pubKey.toObject();
+ let xBuf = Buffer.from(x, 'hex');
+ let yBuf = Buffer.from(y, 'hex');
+ let prefix;
+ let buf;
+ if (!compressed) {
+ prefix = Buffer.from([0x04]);
+ buf = Buffer.concat([prefix, xBuf, yBuf]);
+ } else {
+ let odd = yBuf[yBuf.length - 1] % 2;
+ if (odd) {
+ prefix = Buffer.from([0x03]);
+ } else {
+ prefix = Buffer.from([0x02]);
+ }
+ buf = Buffer.concat([prefix, xBuf]);
+ }
+
+ return buf;
+ };
+}
From b07c162e554f107ec359f93021a8afa9544ee41d Mon Sep 17 00:00:00 2001
From: takYoon
Date: Thu, 23 Mar 2023 15:13:40 +0700
Subject: [PATCH 08/15] Merge branch 'master' into fb-takyoon-message-onchain
* master:
improve performance home card
refactor code
handle some feedback
fix asset to build android
handle some case show get started page not correct
polish ui scan eToken
fix bug scan eToken some case
add command to build android
handle some case scan eToken
change model for tokenInfo base on chronik
handle some feedback about scan & specific amount
# Conflicts:
# src/app/pages/wallet-details/wallet-details.ts
# src/assets/i18n/en.po
---
src/app/components/recipient/recipient.component.html | 1 +
src/app/pages/wallet-details/wallet-details.ts | 7 -------
2 files changed, 1 insertion(+), 7 deletions(-)
diff --git a/src/app/components/recipient/recipient.component.html b/src/app/components/recipient/recipient.component.html
index 8bd34f0b985..5d2be6b1514 100644
--- a/src/app/components/recipient/recipient.component.html
+++ b/src/app/components/recipient/recipient.component.html
@@ -35,6 +35,7 @@
{{unit}}
{{unit}}
+ {{recipient.altAmountStr}} {{alternativeUnit}}