Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions __tests__/unit/core-transactions/handlers/__support__/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,23 @@ export const buildMultiSignatureWallet = (): Wallets.Wallet => {

return wallet;
};

export const buildMultiSignatureRecipientWallet = (): Wallets.Wallet => {
const multiSignatureAsset: IMultiSignatureAsset = {
publicKeys: [
Identities.PublicKey.fromPassphrase(passphrases[1]),
Identities.PublicKey.fromPassphrase(passphrases[2]),
Identities.PublicKey.fromPassphrase(passphrases[3]),
],
min: 2,
};

const wallet = new Wallets.Wallet(
Identities.Address.fromMultiSignatureAsset(multiSignatureAsset),
new Services.Attributes.AttributeMap(getWalletAttributeSet()),
);
wallet.setPublicKey(Identities.PublicKey.fromMultiSignatureAsset(multiSignatureAsset));
wallet.setAttribute("multiSignature", multiSignatureAsset);

return wallet;
};
16 changes: 14 additions & 2 deletions __tests__/unit/core-transactions/handlers/two/htlc-lock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import { Mapper, Mocks } from "@packages/core-test-framework";
import { Generators } from "@packages/core-test-framework/src";
import { Factories, FactoryBuilder } from "@packages/core-test-framework/src/factories";
import passphrases from "@packages/core-test-framework/src/internal/passphrases.json";
import { HtlcLockExpiredError, InsufficientBalanceError } from "@packages/core-transactions/src/errors";
import {
HtlcLockExpiredError,
InsufficientBalanceError,
DisabledMultiSignatureSending,
} from "@packages/core-transactions/src/errors";
import { TransactionHandler } from "@packages/core-transactions/src/handlers";
import { TransactionHandlerRegistry } from "@packages/core-transactions/src/handlers/handler-registry";
import { Crypto, Enums, Interfaces, Managers, Transactions, Utils } from "@packages/crypto";
Expand Down Expand Up @@ -229,12 +233,20 @@ describe("Htlc lock", () => {
).toResolve();
});

it("should not throw - multi sign", async () => {
it("should not throw - multi sign if and multiSignatureSendingEnabled=true", async () => {
Managers.configManager.getMilestone().multiSignatureSendingEnabled = true;
await expect(
handler.throwIfCannotBeApplied(multiSignatureHtlcLockTransaction, multiSignatureWallet),
).toResolve();
});

it("should throw - multi sign if and multiSignatureSendingEnabled=false", async () => {
Managers.configManager.getMilestone().multiSignatureSendingEnabled = false;
await expect(
handler.throwIfCannotBeApplied(multiSignatureHtlcLockTransaction, multiSignatureWallet),
).rejects.toThrow(DisabledMultiSignatureSending);
});

it("should throw if asset is undefined", async () => {
htlcLockTransaction.data.asset = undefined;

Expand Down
12 changes: 10 additions & 2 deletions __tests__/unit/core-transactions/handlers/two/ipfs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Factories, FactoryBuilder } from "@packages/core-test-framework/src/fac
import passphrases from "@packages/core-test-framework/src/internal/passphrases.json";
import { Mempool } from "@packages/core-transaction-pool";
import { MempoolIndexes } from "@packages/core-transactions/src/enums";
import { InsufficientBalanceError, IpfsHashAlreadyExists } from "@packages/core-transactions/src/errors";
import { InsufficientBalanceError, IpfsHashAlreadyExists, DisabledMultiSignatureSending } from "@packages/core-transactions/src/errors";
import { TransactionHandler } from "@packages/core-transactions/src/handlers";
import { TransactionHandlerRegistry } from "@packages/core-transactions/src/handlers/handler-registry";
import { Crypto, Enums, Interfaces, Managers, Transactions, Utils } from "@packages/crypto";
Expand Down Expand Up @@ -309,12 +309,20 @@ describe("Ipfs", () => {
).toResolve();
});

it("should not throw - multi sign", async () => {
it("should not throw - multi sign if and multiSignatureSendingEnabled=true", async () => {
Managers.configManager.getMilestone().multiSignatureSendingEnabled = true;
await expect(
handler.throwIfCannotBeApplied(multiSignatureIpfsTransaction, multiSignatureWallet),
).toResolve();
});

it("should throw - multi sign if and multiSignatureSendingEnabled=false", async () => {
Managers.configManager.getMilestone().multiSignatureSendingEnabled = false;
await expect(
handler.throwIfCannotBeApplied(multiSignatureIpfsTransaction, multiSignatureWallet),
).rejects.toThrow(DisabledMultiSignatureSending);
});

it("should throw if wallet has insufficient funds", async () => {
senderWallet.setBalance(Utils.BigNumber.ZERO);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { StateStore } from "@packages/core-state/src/stores/state";
import { Generators } from "@packages/core-test-framework/src";
import { Factories, FactoryBuilder } from "@packages/core-test-framework/src/factories";
import passphrases from "@packages/core-test-framework/src/internal/passphrases.json";
import { InsufficientBalanceError } from "@packages/core-transactions/src/errors";
import { InsufficientBalanceError, DisabledMultiSignatureSending, DisabledMultiSignatureReceiving } from "@packages/core-transactions/src/errors";
import { TransactionHandler } from "@packages/core-transactions/src/handlers";
import { TransactionHandlerRegistry } from "@packages/core-transactions/src/handlers/handler-registry";
import { Crypto, Enums, Interfaces, Managers, Transactions, Utils } from "@packages/crypto";
Expand All @@ -18,6 +18,7 @@ import {
buildMultiSignatureWallet,
buildRecipientWallet,
buildSecondSignatureWallet,
buildMultiSignatureRecipientWallet,
buildSenderWallet,
initApp,
} from "../__support__/app";
Expand All @@ -26,6 +27,7 @@ let app: Application;
let senderWallet: Wallets.Wallet;
let secondSignatureWallet: Wallets.Wallet;
let multiSignatureWallet: Wallets.Wallet;
let multiSignatureRecipientWallet: Wallets.Wallet;
let recipientWallet: Wallets.Wallet;
let walletRepository: Contracts.State.WalletRepository;
let factoryBuilder: FactoryBuilder;
Expand Down Expand Up @@ -59,11 +61,13 @@ beforeEach(() => {
senderWallet = buildSenderWallet(factoryBuilder);
secondSignatureWallet = buildSecondSignatureWallet(factoryBuilder);
multiSignatureWallet = buildMultiSignatureWallet();
multiSignatureRecipientWallet = buildMultiSignatureRecipientWallet();
recipientWallet = buildRecipientWallet(factoryBuilder);

walletRepository.index(senderWallet);
walletRepository.index(secondSignatureWallet);
walletRepository.index(multiSignatureWallet);
walletRepository.index(multiSignatureRecipientWallet);
walletRepository.index(recipientWallet);
});

Expand Down Expand Up @@ -156,12 +160,22 @@ describe("MultiPaymentTransaction", () => {
).toResolve();
});

it("should not throw - multi sign", async () => {
it("should not throw - multi sign if and multiSignatureSendingEnabled=true", async () => {
Managers.configManager.getMilestone().multiSignatureSendingEnabled = true;
await expect(
handler.throwIfCannotBeApplied(multiSignatureMultiPaymentTransaction, multiSignatureWallet),
).toResolve();
});

it("should throw - multi sign if and multiSignatureSendingEnabled=false", async () => {
Managers.configManager.getMilestone().multiSignatureSendingEnabled = false;
await expect(
handler.throwIfCannotBeApplied(multiSignatureMultiPaymentTransaction, multiSignatureWallet),
).rejects.toThrow(
DisabledMultiSignatureSending,
);
});

it("should throw if asset is undefined", async () => {
multiPaymentTransaction.data.asset = undefined;

Expand All @@ -183,6 +197,35 @@ describe("MultiPaymentTransaction", () => {
InsufficientBalanceError,
);
});

it("should not throw if recipient is multisignature wallet and multiSignatureReceivingEnabled=true", async () => {
Managers.configManager.getMilestone().multiSignatureReceivingEnabled = true;
const multiPaymentTransaction = BuilderFactory.multiPayment()
.addPayment("ARYJmeYHSUTgbxaiqsgoPwf6M3CYukqdKN", "10")
.addPayment("AFyjB5jULQiYNsp37wwipCm9c7V1xEzTJD", "20")
.addPayment(multiSignatureRecipientWallet.getAddress(), "20")
.nonce("1")
.sign(passphrases[0])
.build();

await expect(handler.throwIfCannotBeApplied(multiPaymentTransaction, senderWallet)).toResolve();
});

it("should throw if recipient is multisignature wallet and multiSignatureReceivingEnabled=false", async () => {
Managers.configManager.getMilestone().multiSignatureReceivingEnabled = false;
const multiPaymentTransaction = BuilderFactory.multiPayment()
.addPayment("ARYJmeYHSUTgbxaiqsgoPwf6M3CYukqdKN", "10")
.addPayment("AFyjB5jULQiYNsp37wwipCm9c7V1xEzTJD", "20")
.addPayment(multiSignatureRecipientWallet.getAddress(), "20")
.nonce("1")
.sign(passphrases[0])
.build();

await expect(handler.throwIfCannotBeApplied(multiPaymentTransaction, senderWallet)).rejects.toThrow(
DisabledMultiSignatureReceiving,
);
});

});

describe("apply", () => {
Expand Down
48 changes: 47 additions & 1 deletion __tests__/unit/core-transactions/handlers/two/transfer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
ColdWalletError,
InsufficientBalanceError,
SenderWalletMismatchError,
DisabledMultiSignatureReceiving,
DisabledMultiSignatureSending,
} from "@packages/core-transactions/src/errors";
import { TransactionHandler } from "@packages/core-transactions/src/handlers";
import { TransactionHandlerRegistry } from "@packages/core-transactions/src/handlers/handler-registry";
Expand All @@ -24,6 +26,7 @@ import {
buildMultiSignatureWallet,
buildRecipientWallet,
buildSecondSignatureWallet,
buildMultiSignatureRecipientWallet,
buildSenderWallet,
initApp,
} from "../__support__/app";
Expand All @@ -32,6 +35,7 @@ let app: Application;
let senderWallet: Wallets.Wallet;
let secondSignatureWallet: Wallets.Wallet;
let multiSignatureWallet: Wallets.Wallet;
let multiSignatureRecipientWallet: Wallets.Wallet;
let recipientWallet: Wallets.Wallet;
let walletRepository: Contracts.State.WalletRepository;
let factoryBuilder: FactoryBuilder;
Expand Down Expand Up @@ -59,11 +63,13 @@ beforeEach(() => {
senderWallet = buildSenderWallet(factoryBuilder);
secondSignatureWallet = buildSecondSignatureWallet(factoryBuilder);
multiSignatureWallet = buildMultiSignatureWallet();
multiSignatureRecipientWallet = buildMultiSignatureRecipientWallet();
recipientWallet = buildRecipientWallet(factoryBuilder);

walletRepository.index(senderWallet);
walletRepository.index(secondSignatureWallet);
walletRepository.index(multiSignatureWallet);
walletRepository.index(multiSignatureRecipientWallet);
walletRepository.index(recipientWallet);
});

Expand Down Expand Up @@ -116,6 +122,7 @@ describe("TransferTransaction", () => {

afterEach(async () => {
Managers.configManager.set("network.pubKeyHash", pubKeyHash);

});

describe("bootstrap", () => {
Expand All @@ -142,12 +149,23 @@ describe("TransferTransaction", () => {
).toResolve();
});

it("should not throw - multi sign", async () => {
it("should not throw - multi sign if and multiSignatureSendingEnabled=true", async () => {
Managers.configManager.getMilestone().multiSignatureSendingEnabled = true;
await expect(
handler.throwIfCannotBeApplied(multiSignatureTransferTransaction, multiSignatureWallet),
).toResolve();
});


it("should throw - multi sign if and multiSignatureSendingEnabled=false", async () => {
Managers.configManager.getMilestone().multiSignatureSendingEnabled = false;
await expect(
handler.throwIfCannotBeApplied(multiSignatureTransferTransaction, multiSignatureWallet),
).rejects.toThrow(
DisabledMultiSignatureSending,
);
});

it("should throw", async () => {
transferTransaction.data.senderPublicKey = "a".repeat(66);
await expect(handler.throwIfCannotBeApplied(transferTransaction, senderWallet)).rejects.toThrow(
Expand Down Expand Up @@ -185,6 +203,34 @@ describe("TransferTransaction", () => {
);
});

it("should pass if recipient is multi signature wallet and multiSignatureReceivingEnabled=true", async () => {
Managers.configManager.getMilestone().multiSignatureReceivingEnabled = true;

transferTransaction = BuilderFactory.transfer()
.recipientId(multiSignatureRecipientWallet.getAddress())
.amount("10000000")
.sign(passphrases[0])
.nonce("1")
.build();

await expect(handler.throwIfCannotBeApplied(transferTransaction, senderWallet)).toResolve();
});

it("should throw if recipient is multi signature wallet and multiSignatureReceivingEnabled=false", async () => {
Managers.configManager.getMilestone().multiSignatureReceivingEnabled = false;

transferTransaction = BuilderFactory.transfer()
.recipientId(multiSignatureRecipientWallet.getAddress())
.amount("10000000")
.sign(passphrases[0])
.nonce("1")
.build();

await expect(handler.throwIfCannotBeApplied(transferTransaction, senderWallet)).rejects.toThrow(
DisabledMultiSignatureReceiving,
);
});

it("should not throw if recipient is cold wallet", async () => {
const coldWallet: Wallets.Wallet = factoryBuilder
.get("Wallet")
Expand Down
11 changes: 10 additions & 1 deletion __tests__/unit/core-transactions/handlers/two/vote.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
InsufficientBalanceError,
NoVoteError,
UnvoteMismatchError,
DisabledMultiSignatureSending,
VotedForNonDelegateError,
} from "@packages/core-transactions/src/errors";
import { TransactionHandler } from "@packages/core-transactions/src/handlers";
Expand Down Expand Up @@ -297,12 +298,20 @@ describe("VoteTransaction", () => {
).toResolve();
});

it("should not throw - multi sign vote", async () => {
it("should not throw - multi sign if and multiSignatureSendingEnabled=true", async () => {
Managers.configManager.getMilestone().multiSignatureSendingEnabled = true;
await expect(
handler.throwIfCannotBeApplied(multiSignatureVoteTransaction, multiSignatureWallet),
).toResolve();
});

it("should throw - multi sign if and multiSignatureSendingEnabled=false", async () => {
Managers.configManager.getMilestone().multiSignatureSendingEnabled = false;
await expect(
handler.throwIfCannotBeApplied(multiSignatureVoteTransaction, multiSignatureWallet),
).rejects.toThrow(DisabledMultiSignatureSending);
});

it("should not throw if the unvote is valid and the wallet has voted", async () => {
senderWallet.setAttribute("vote", delegateWallet1.getPublicKey());
await expect(handler.throwIfCannotBeApplied(unvoteTransaction, senderWallet)).toResolve();
Expand Down
2 changes: 2 additions & 0 deletions packages/core-test-framework/src/app/generators/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ export class CryptoGenerator extends Generator {
blockBurnAddress: true,
blsPublicKeyRegistrationEnabled: true,
multiSignatureRegistrationEnabled: true,
multiSignatureSendingEnabled: true,
multiSignatureReceivingEnabled: true,
},
{
height: rewardHeight,
Expand Down
13 changes: 13 additions & 0 deletions packages/core-transactions/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,19 @@ export class UnsupportedMultiSignatureTransactionError extends TransactionError
}
}

export class DisabledMultiSignatureSending extends TransactionError {
public constructor() {
super(`Failed to apply transaction, because sending from multi signature wallets is disabled.`);
}
}

export class DisabledMultiSignatureReceiving extends TransactionError {
public constructor() {
super(`Failed to apply transaction, because receiving on multi signature wallets is disabled.`);
}
}


export class InvalidSecondSignatureError extends TransactionError {
public constructor() {
super(`Failed to apply transaction, because the second signature could not be verified.`);
Expand Down
13 changes: 13 additions & 0 deletions packages/core-transactions/src/handlers/one/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { Interfaces, Managers, Transactions } from "@arkecosystem/crypto";

import { isRecipientOnActiveNetwork } from "../../utils";
import { TransactionHandler, TransactionHandlerConstructor } from "../transaction";
import {
DisabledMultiSignatureReceiving,
} from "../../errors";

// todo: revisit the implementation, container usage and arguments after core-database rework
// todo: replace unnecessary function arguments with dependency injection to avoid passing around references
Expand Down Expand Up @@ -30,6 +33,16 @@ export class TransferTransactionHandler extends TransactionHandler {
transaction: Interfaces.ITransaction,
sender: Contracts.State.Wallet,
): Promise<void> {
Utils.assert.defined<string>(transaction.data.recipientId);
const recipient: Contracts.State.Wallet = this.walletRepository.findByAddress(transaction.data.recipientId);

if (recipient.hasMultiSignature()) {
const milestone = Managers.configManager.getMilestone();
if (milestone.multiSignatureReceivingEnabled !== true) {
throw new DisabledMultiSignatureReceiving();
}
}

return super.throwIfCannotBeApplied(transaction, sender);
}

Expand Down
Loading
Loading