Skip to content

Commit

Permalink
fix #1490
Browse files Browse the repository at this point in the history
  • Loading branch information
bassemmagdy committed Sep 9, 2021
1 parent 6751385 commit 586fac6
Show file tree
Hide file tree
Showing 30 changed files with 357 additions and 256 deletions.
3 changes: 1 addition & 2 deletions __tests__/views/forms/FormTransferTransaction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,7 @@ describe('FormTransferTransaction', () => {
});

// act
const tx = vm.getTransactions();

const tx = await vm.getTransactions();
// assert
expect(Number(amount) * Math.pow(10, networkMock.currency.divisibility)).toBe(tx[0].mosaics[0].amount.compact());
});
Expand Down
9 changes: 6 additions & 3 deletions src/components/MaxFeeAndSubmit/MaxFeeAndSubmit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
:fast-fee="fastFee"
/>
<div v-if="!hideSubmit" class="ml-2">
<button
type="submit"
<Button
:class="'centered-button button-style submit-button ' + submitButtonClasses"
:disabled="disableSubmit"
:loading="loading"
@click="$emit('button-clicked')"
>
{{ $t(submitButtonText) }}
</button>
</Button>
</div>
</div>
</template>
Expand Down Expand Up @@ -75,6 +75,9 @@ export default class MaxFeeAndSubmit extends Vue {
* Submit button classes
*/
@Prop({ default: 'inverted-button' }) submitButtonClasses: string;
@Prop({ default: false }) loading: boolean;
@Prop({
default: 0,
})
Expand Down
165 changes: 95 additions & 70 deletions src/services/TransactionCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,25 @@ import {
Account,
AggregateTransaction,
Deadline,
DeadlineService,
LockFundsTransaction,
Mosaic,
MosaicId,
NetworkType,
PublicAccount,
RepositoryFactory,
SignedTransaction,
Transaction,
TransactionFees,
UInt64,
} from 'symbol-sdk';
import { Signer } from '@/store/Account';
import { NetworkConfigurationModel } from '@/core/database/entities/NetworkConfigurationModel';
import { Observable, of } from 'rxjs';
import { from, Observable, of } from 'rxjs';
import { AccountTransactionSigner, TransactionAnnouncerService, TransactionSigner } from '@/services/TransactionAnnouncerService';
import { BroadcastResult } from '@/core/transactions/BroadcastResult';
import { flatMap, map } from 'rxjs/operators';
import { AppStore } from '@/app/AppStore';

export enum TransactionCommandMode {
SIMPLE = 'SIMPLE',
Expand Down Expand Up @@ -62,30 +65,35 @@ export class TransactionCommand {
this.tempTransactionSigner = new AccountTransactionSigner(this.tempAccount);
}

public sign(service: TransactionAnnouncerService, account: TransactionSigner): Observable<Observable<SignedTransaction>[]> {
return this.resolveTransactions(account).pipe(
public async sign(
service: TransactionAnnouncerService,
account: TransactionSigner,
): Promise<Observable<Observable<SignedTransaction>[]>> {
return of(await this.resolveTransactions(account)).pipe(
flatMap((transactions) => {
return of(transactions.map((t) => account.signTransaction(t, this.generationHash)));
return of(transactions.map((t) => account.signTransaction(t, this.generationHash))).toPromise();
}),
);
}

public announce(service: TransactionAnnouncerService, account: TransactionSigner): Observable<Observable<BroadcastResult>[]> {
return this.resolveTransactions(account).pipe(
flatMap((transactions) => {
const signedTransactions = transactions.map((t) => account.signTransaction(t, this.generationHash));
if (!signedTransactions.length) {
return of([]);
}
if (this.mode == TransactionCommandMode.MULTISIGN) {
return of([this.announceHashAndAggregateBonded(service, signedTransactions)]);
} else if (this.mode == TransactionCommandMode.CHAINED_BINARY) {
return of([this.announceChainedBinary(service, signedTransactions)]);
} else {
return of(this.announceSimple(service, signedTransactions));
}
}),
);
public async announce(service: TransactionAnnouncerService, account: TransactionSigner): Promise<Observable<BroadcastResult>[]> {
return of(await this.resolveTransactions(account))
.pipe(
flatMap((transactions) => {
const signedTransactions = transactions.map((t) => account.signTransaction(t, this.generationHash));
if (!signedTransactions.length) {
return of([]);
}
if (this.mode == TransactionCommandMode.MULTISIGN) {
return of([this.announceHashAndAggregateBonded(service, signedTransactions)]);
} else if (this.mode == TransactionCommandMode.CHAINED_BINARY) {
return of([this.announceChainedBinary(service, signedTransactions)]);
} else {
return of(this.announceSimple(service, signedTransactions));
}
}),
)
.toPromise();
}

private announceChainedBinary(
Expand Down Expand Up @@ -125,67 +133,79 @@ export class TransactionCommand {
return signedTransactions.map((o) => o.pipe(flatMap((s) => service.announce(s))));
}

public getTotalMaxFee(): Observable<UInt64> {
return this.resolveTransactions().pipe(
map((ts) => ts.reduce((partial, current) => partial.add(current.maxFee), UInt64.fromUint(0))),
public async getTotalMaxFee(): Promise<Observable<UInt64>> {
const resolvedTransactions = await this.resolveTransactions();
of(resolvedTransactions).pipe(
map((ts) => {
ts.reduce((partial, current) => partial.add(current.maxFee), UInt64.fromUint(0));
}),
);
return of(resolvedTransactions).pipe(map((ts) => ts.reduce((partial, current) => partial.add(current.maxFee), UInt64.fromUint(0))));
}

public resolveTransactions(account: TransactionSigner = this.tempTransactionSigner): Observable<Transaction[]> {
if (!this.stageTransactions.length) {
return of([]);
public async resolveTransactions(account: TransactionSigner = this.tempTransactionSigner): Promise<Transaction[]> {
if (!this.stageTransactions || !this.stageTransactions.length) {
return from([]).toPromise();
}
const maxFee = this.stageTransactions.sort((a, b) => a.maxFee.compare(b.maxFee))[0].maxFee;
if (this.mode === TransactionCommandMode.SIMPLE || this.mode === TransactionCommandMode.CHAINED_BINARY) {
return of(this.stageTransactions.map((t) => this.calculateSuggestedMaxFee(t)));
} else {
const currentSigner = PublicAccount.createFromPublicKey(this.signerPublicKey, this.networkType);
if (this.mode === TransactionCommandMode.AGGREGATE) {
const aggregate = this.calculateSuggestedMaxFee(
AggregateTransaction.createComplete(
Deadline.create(this.epochAdjustment),
this.stageTransactions.map((t) => t.toAggregate(currentSigner)),
this.networkType,
[],
maxFee,
),
);
return of([aggregate]);
if (this.stageTransactions && this.stageTransactions.length) {
const maxFee = this.stageTransactions.sort((a, b) => a.maxFee.compare(b.maxFee))[0].maxFee;
if (this.mode === TransactionCommandMode.SIMPLE || this.mode === TransactionCommandMode.CHAINED_BINARY) {
return of(this.stageTransactions.map((t) => this.calculateSuggestedMaxFee(t))).toPromise();
} else {
// use attached signer (multisig account) if exists
const signedInnerTransactions = this.stageTransactions.map((t) => {
return t.signer === undefined ? t.toAggregate(currentSigner) : t.toAggregate(t.signer);
});
const currentSigner = PublicAccount.createFromPublicKey(this.signerPublicKey, this.networkType);
if (this.mode === TransactionCommandMode.AGGREGATE) {
const aggregateDeadline = await this.createDeadline();
const aggregate = this.calculateSuggestedMaxFee(
AggregateTransaction.createComplete(
aggregateDeadline,
this.stageTransactions.map((t) => t.toAggregate(currentSigner)),
this.networkType,
[],
maxFee,
),
);
return of([aggregate]).toPromise();
} else {
// use attached signer (multisig account) if exists
const signedInnerTransactions = this.stageTransactions.map((t) => {
return t.signer === undefined ? t.toAggregate(currentSigner) : t.toAggregate(t.signer);
});
const bondedDeadline = await this.createDeadline(48);
const aggregate = this.calculateSuggestedMaxFee(
AggregateTransaction.createBonded(bondedDeadline, signedInnerTransactions, this.networkType, [], maxFee),
);
const hashLockDeadline = await this.createDeadline(6);

const aggregate = this.calculateSuggestedMaxFee(
AggregateTransaction.createBonded(
Deadline.create(this.epochAdjustment, 48),
signedInnerTransactions,
this.networkType,
[],
maxFee,
),
);
return account.signTransaction(aggregate, this.generationHash).pipe(
map((signedAggregateTransaction) => {
const hashLock = this.calculateSuggestedMaxFee(
LockFundsTransaction.create(
Deadline.create(this.epochAdjustment, 6),
new Mosaic(this.networkMosaic, UInt64.fromNumericString(this.networkConfiguration.lockedFundsPerAggregate)),
UInt64.fromUint(5760),
signedAggregateTransaction,
this.networkType,
maxFee,
),
);
return [hashLock, aggregate];
}),
);
return account
.signTransaction(aggregate, this.generationHash)
.pipe(
map((signedAggregateTransaction) => {
const hashLock = this.calculateSuggestedMaxFee(
LockFundsTransaction.create(
hashLockDeadline,
new Mosaic(
this.networkMosaic,
UInt64.fromNumericString(this.networkConfiguration.lockedFundsPerAggregate),
),
UInt64.fromUint(5760),
signedAggregateTransaction,
this.networkType,
maxFee,
),
);
return [hashLock, aggregate];
}),
)
.toPromise();
}
}
}
}

public calculateSuggestedMaxFee(transaction: Transaction): Transaction {
if (!transaction) {
return undefined;
}
const feeMultiplier = this.resolveFeeMultipler(transaction);
if (!feeMultiplier) {
return transaction;
Expand Down Expand Up @@ -223,4 +243,9 @@ export class TransactionCommand {
}
return undefined;
}
private async createDeadline(deadlineInHours = 2): Promise<Deadline> {
const repositoryFactory: RepositoryFactory = AppStore.getters['network/repositoryFactory'] as RepositoryFactory;
const deadline = await (await DeadlineService.create(repositoryFactory)).createDeadlineUsingServerTime(deadlineInHours);
return deadline;
}
}
6 changes: 3 additions & 3 deletions src/store/Metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
*
*/

import { Address, Deadline, MetadataType, Transaction, UInt64 } from 'symbol-sdk';
import { Address, DeadlineService, MetadataType, Transaction, UInt64 } from 'symbol-sdk';
import * as _ from 'lodash';
import Vue from 'vue';

Expand Down Expand Up @@ -155,19 +155,19 @@ export default {
async RESOLVE_METADATA_TRANSACTIONS({ commit, rootGetters }, metadataType: MetadataType) {
const currentSignerAddress = rootGetters['account/currentSignerAddress'];
const repositoryFactory = rootGetters['network/repositoryFactory'];
const epochAdjustment = rootGetters['network/epochAdjustment'];
const networkType = rootGetters['network/networkType'];
const metadataForm: MetadataFormState = rootGetters['metadata/metadataForm'];

if (!currentSignerAddress) {
return;
}
const deadline = await (await DeadlineService.create(repositoryFactory)).createDeadlineUsingServerTime();

const metadataService = new MetadataService();
const metadataTransaction = await metadataService
.metadataTransactionObserver(
repositoryFactory,
Deadline.create(epochAdjustment),
deadline,
networkType,
currentSignerAddress,
metadataForm.targetAddress,
Expand Down
6 changes: 6 additions & 0 deletions src/store/Network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
RepositoryFactory,
RepositoryFactoryHttp,
TransactionFees,
DeadlineService,
} from 'symbol-sdk';
import Vue from 'vue';
// internal dependencies
Expand Down Expand Up @@ -538,6 +539,11 @@ export default {
const peerNodes: NodeInfo[] = await nodeRepository.getNodePeers().toPromise();
commit('peerNodes', _.uniqBy(peerNodes, 'host'));
},
async GET_TRANSACTION_DEADLINE({ getters }, deadlineInHours = 2) {
const repositoryFactory: RepositoryFactory = getters['repositoryFactory'] as RepositoryFactory;
const deadline = await (await DeadlineService.create(repositoryFactory)).createDeadlineUsingServerTime(deadlineInHours);
return deadline;
},
// TODO :: re-apply that behavior if red screen issue fixed
// load nodes that eligible for delegate harvesting
// async LOAD_HARVESTING_PEERS({ commit, getters }) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
v-model="formItems.maxFee"
:submit-button-text="submitButtonText"
:submit-button-classes="submitButtonClasses"
:loading="preparingTransactions"
@button-clicked="handleSubmit(onSubmit)"
/>
</form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,18 +171,18 @@ export class FormAccountRestrictionTransactionTs extends FormTransactionBase {
* Getter for transactions that will be staged
* @throws {Error} If not overloaded in derivate component
*/
protected getTransactions(): Transaction[] {
return [this.createTransaction(this.restrictionTxType)];
protected async getTransactions(): Promise<Transaction[]> {
return [await this.createTransaction(this.restrictionTxType)];
}

private createTransaction(restrictionTxType: AccountRestrictionTxType): Transaction {
private async createTransaction(restrictionTxType: AccountRestrictionTxType): Promise<Transaction> {
switch (this.restrictionTxType) {
case AccountRestrictionTxType.ADDRESS: {
const toBeAdded = this.isDeleteMode ? [] : [this.instantiatedRecipient];
const toBeDeleted = this.isDeleteMode ? [this.instantiatedRecipient] : [];

const deadline = await this.createDeadline();
return AccountRestrictionTransaction.createAddressRestrictionModificationTransaction(
this.createDeadline(),
deadline,
RestrictionFlagMapping.toRestrictionFlag(
restrictionTxType,
this.formItems.direction,
Expand All @@ -197,9 +197,9 @@ export class FormAccountRestrictionTransactionTs extends FormTransactionBase {
case AccountRestrictionTxType.MOSAIC: {
const toBeAdded = this.isDeleteMode ? [] : [new MosaicId(this.formItems.mosaicIdRaw)];
const toBeDeleted = this.isDeleteMode ? [new MosaicId(this.formItems.mosaicIdRaw)] : [];

const deadline = await this.createDeadline();
return AccountRestrictionTransaction.createMosaicRestrictionModificationTransaction(
this.createDeadline(),
deadline,
RestrictionFlagMapping.toRestrictionFlag(
restrictionTxType,
this.formItems.direction,
Expand All @@ -214,9 +214,9 @@ export class FormAccountRestrictionTransactionTs extends FormTransactionBase {
case AccountRestrictionTxType.TRANSACTION_TYPE: {
const toBeAdded = this.isDeleteMode ? [] : [this.formItems.transactionType];
const toBeDeleted = this.isDeleteMode ? [this.formItems.transactionType] : [];

const deadline = await this.createDeadline();
return AccountRestrictionTransaction.createOperationRestrictionModificationTransaction(
this.createDeadline(),
deadline,
RestrictionFlagMapping.toRestrictionFlag(
restrictionTxType,
this.formItems.direction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,15 @@
@button-clicked="handleSubmit(onClickSendAggregate)"
/>
<div class="send-button">
<button
<Button
class="full-width-centered-button button-style inverted-button fat-button"
style="cursor: pointer;"
type="submit"
:disabled="!simpleAggregateTransaction.length"
@click="handleSubmit(onSubmit)"
:loading="preparingTransactions || aggregateSubmitFlag"
@click="handleSubmit(Submit)"
>
{{ $t('aggregate_send') }}
</button>
</Button>
</div>
</div>
</form>
Expand All @@ -85,6 +85,7 @@
v-if="hasConfirmationModal"
:command="command"
:visible="hasConfirmationModal"
:loading="preparingTransactions"
@success="onConfirmationSuccess"
@error="onConfirmationError"
@close="onConfirmationCancel"
Expand Down
Loading

0 comments on commit 586fac6

Please sign in to comment.