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
78 changes: 77 additions & 1 deletion __tests__/functional/transaction-forging/htlc-lock.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Crypto, Enums, Identities } from "@arkecosystem/crypto";
import { Crypto, Enums, Identities, Utils } from "@arkecosystem/crypto";
import got from "got";
import { TransactionFactory } from "../../helpers/transaction-factory";
import { secrets } from "../../utils/config/testnet/delegates.json";
import * as support from "./__support__";
Expand Down Expand Up @@ -130,4 +131,79 @@ describe("Transaction Forging - HTLC Lock", () => {
await support.snoozeForBlock(1);
await expect(transaction.id).toBeForged();
});

it("should update delegates vote balance using locked balance when voting and unvoting delegates", async () => {
const newWalletPassphrase = "this is a new wallet passphrase";
// Initial Funds
const initialBalance = 100 * 1e8;
const initialFunds = TransactionFactory.transfer(
Identities.Address.fromPassphrase(newWalletPassphrase),
initialBalance,
)
.withPassphrase(secrets[0])
.createOne();

await expect(initialFunds).toBeAccepted();
await support.snoozeForBlock(1);
await expect(initialFunds.id).toBeForged();

const delegateToVote = Identities.PublicKey.fromPassphrase(secrets[9]);
const { body } = await got.get(`http://localhost:4003/api/v2/delegates/${delegateToVote}`);
const parsedBody = JSON.parse(body);
const initialDelegateVoteValance = Utils.BigNumber.make(parsedBody.data.votes);

// Submit a vote
const vote = TransactionFactory.vote(delegateToVote)
.withPassphrase(newWalletPassphrase)
.createOne();

await expect(vote).toBeAccepted();
await support.snoozeForBlock(1);
await expect(vote.id).toBeForged();

const expectedBalanceAfterVote = initialDelegateVoteValance.plus(initialBalance).minus(vote.fee);
await expect(delegateToVote).toHaveVoteBalance(expectedBalanceAfterVote.toString());

// Submit htlc lock transaction
const lockTransaction = TransactionFactory.htlcLock({
secretHash: "0f128d401958b1b30ad0d10406f47f9489321017b4614e6cb993fc63913c5454",
expiration: {
type: EpochTimestamp,
value: Crypto.Slots.getTime() + 1000,
},
})
.withPassphrase(newWalletPassphrase)
.createOne();

await expect(lockTransaction).toBeAccepted();
await support.snoozeForBlock(1);
await expect(lockTransaction.id).toBeForged();

const expectedBalanceAfterLock = expectedBalanceAfterVote.minus(lockTransaction.fee);
await expect(delegateToVote).toHaveVoteBalance(expectedBalanceAfterLock.toString());

// Unvote
const unvote = TransactionFactory.unvote(delegateToVote)
.withPassphrase(newWalletPassphrase)
.createOne();

await expect(unvote).toBeAccepted();
await support.snoozeForBlock(1);
await expect(unvote.id).toBeForged();

const expectedBalanceAfterUnvote = initialDelegateVoteValance;
await expect(delegateToVote).toHaveVoteBalance(expectedBalanceAfterUnvote.toString());

// Vote again
const voteAgain = TransactionFactory.vote(delegateToVote)
.withPassphrase(newWalletPassphrase)
.createOne();

await expect(voteAgain).toBeAccepted();
await support.snoozeForBlock(1);
await expect(voteAgain.id).toBeForged();

const expectedBalanceAfterVoteAgain = expectedBalanceAfterLock.minus(unvote.fee).minus(voteAgain.fee);
await expect(delegateToVote).toHaveVoteBalance(expectedBalanceAfterVoteAgain.toString());
});
});
1 change: 1 addition & 0 deletions packages/core-jest-matchers/src/functional/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ import "./accepted";
import "./forged";
import "./rejected";
import "./unconfirmed";
import "./vote-balance";
35 changes: 35 additions & 0 deletions packages/core-jest-matchers/src/functional/vote-balance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import got from "got";

export {};

declare global {
namespace jest {
// tslint:disable-next-line:interface-name
interface Matchers<R> {
toHaveVoteBalance(voteBalance: string): Promise<R>;
}
}
}

expect.extend({
toHaveVoteBalance: async (publicKey: string, voteBalance: string) => {
let pass: boolean = false;
let fetchedVoteBalance: string;
try {
const { body } = await got.get(`http://localhost:4003/api/v2/delegates/${publicKey}`);

const parsedBody = JSON.parse(body);

fetchedVoteBalance = parsedBody.data.votes;
pass = fetchedVoteBalance === voteBalance;
} catch (e) {} // tslint:disable-line

return {
pass,
message: () =>
`expected delegate ${publicKey} ${
this.isNot ? "not" : ""
} to have vote balance = ${voteBalance}, got ${fetchedVoteBalance}`,
};
},
});
12 changes: 8 additions & 4 deletions packages/core-state/src/wallets/wallet-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -481,15 +481,19 @@ export class WalletManager implements State.IWalletManager {
const vote: string = transaction.asset.votes[0];
const delegate: State.IWallet = this.findByPublicKey(vote.substr(1));
let voteBalance: Utils.BigNumber = delegate.getAttribute("delegate.voteBalance", Utils.BigNumber.ZERO);
const senderLockedBalance: Utils.BigNumber = sender.getAttribute(
"htlc.lockedBalance",
Utils.BigNumber.ZERO,
);

if (vote.startsWith("+")) {
voteBalance = revert
? voteBalance.minus(sender.balance.minus(transaction.fee))
: voteBalance.plus(sender.balance);
? voteBalance.minus(sender.balance.minus(transaction.fee)).minus(senderLockedBalance)
: voteBalance.plus(sender.balance).plus(senderLockedBalance);
} else {
voteBalance = revert
? voteBalance.plus(sender.balance)
: voteBalance.minus(sender.balance.plus(transaction.fee));
? voteBalance.plus(sender.balance).plus(senderLockedBalance)
: voteBalance.minus(sender.balance.plus(transaction.fee)).minus(senderLockedBalance);
}

delegate.setAttribute("delegate.voteBalance", voteBalance);
Expand Down