mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-04-29 04:05:21 +08:00
test(pox-4-tests): Add StackAggregationCommitCommand authorization-based
This commit is contained in:
committed by
Nikos Baxevanis
parent
ed447864b7
commit
43c39605f5
@@ -88,6 +88,7 @@ it("statefully interacts with PoX-4", async () => {
|
||||
isStacking: false,
|
||||
hasDelegated: false,
|
||||
lockedAddresses: [],
|
||||
amountToCommit: 0,
|
||||
poolMembers: [],
|
||||
delegatedTo: "",
|
||||
delegatedMaxAmount: 0,
|
||||
|
||||
@@ -50,6 +50,7 @@ export type Wallet = {
|
||||
isStacking: boolean;
|
||||
hasDelegated: boolean;
|
||||
lockedAddresses: StxAddress[];
|
||||
amountToCommit: number;
|
||||
poolMembers: StxAddress[];
|
||||
delegatedTo: StxAddress;
|
||||
delegatedMaxAmount: number;
|
||||
|
||||
@@ -11,6 +11,7 @@ import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand";
|
||||
import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand";
|
||||
import { DelegateStackIncreaseCommand } from "./pox_DelegateStackIncreaseCommand";
|
||||
import { DelegateStackExtendCommand } from "./pox_DelegateStackExtendCommand";
|
||||
import { StackAggregationCommitCommand } from "./pox_StackAggregationCommitCommand";
|
||||
|
||||
export function PoxCommands(
|
||||
wallets: Map<StxAddress, Wallet>,
|
||||
@@ -74,6 +75,24 @@ export function PoxCommands(
|
||||
r.amount,
|
||||
)
|
||||
),
|
||||
// StackAggregationCommitCommand
|
||||
fc.record({
|
||||
wallet: fc.constantFrom(...wallets.values()),
|
||||
authId: fc.nat(),
|
||||
currentCycle: fc.constant(currentCycle(network)),
|
||||
}).map((
|
||||
r: {
|
||||
wallet: Wallet;
|
||||
authId: number;
|
||||
currentCycle: number;
|
||||
},
|
||||
) =>
|
||||
new StackAggregationCommitCommand(
|
||||
r.wallet,
|
||||
r.authId,
|
||||
r.currentCycle,
|
||||
)
|
||||
),
|
||||
// RevokeDelegateStxCommand
|
||||
fc.record({
|
||||
wallet: fc.constantFrom(...wallets.values()),
|
||||
|
||||
@@ -103,11 +103,13 @@ export class DelegateStackIncreaseCommand implements PoxCommand {
|
||||
|
||||
// Get the Stacker's wallet from the model and update it with the new state.
|
||||
const stackerWallet = model.wallets.get(this.stacker.stxAddress)!;
|
||||
const operatorWallet = model.wallets.get(this.operator.stxAddress)!
|
||||
// Update model so that we know this stacker has increased the stacked amount.
|
||||
// Update locked and unlocked fields in the model.
|
||||
stackerWallet.amountLocked = newTotalLocked;
|
||||
stackerWallet.amountUnlocked = stackerWallet.amountUnlocked -
|
||||
this.increaseBy;
|
||||
operatorWallet.amountToCommit += this.increaseBy
|
||||
|
||||
// Log to console for debugging purposes. This is not necessary for the
|
||||
// test to pass but it is useful for debugging and eyeballing the test.
|
||||
|
||||
@@ -157,6 +157,7 @@ export class DelegateStackStxCommand implements PoxCommand {
|
||||
// the stacker's funds are locked when calling delegate-stack-extend,
|
||||
// delegate-stack-increase
|
||||
operatorWallet.lockedAddresses.push(stackerWallet.stxAddress);
|
||||
operatorWallet.amountToCommit += Number(this.amountUstx)
|
||||
|
||||
// Log to console for debugging purposes. This is not necessary for the
|
||||
// test to pass but it is useful for debugging and eyeballing the test.
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
import {
|
||||
logCommand,
|
||||
PoxCommand,
|
||||
Real,
|
||||
Stub,
|
||||
Wallet,
|
||||
} from "./pox_CommandModel.ts";
|
||||
import { poxAddressToTuple } from "@stacks/stacking";
|
||||
import { expect } from "vitest";
|
||||
import { Cl } from "@stacks/transactions";
|
||||
|
||||
/**
|
||||
* The `StackAggregationCommitCommand` allows an operator commits partially
|
||||
* stacked STX and allocate a new PoX reward address slot. This allows a
|
||||
* stacker to lock fewer STX than the minimal threshold in multiple transactions,
|
||||
* so long as:
|
||||
* 1. The pox-addr is the same.
|
||||
* 2. This "commit" transaction is called _before_ the PoX anchor block.
|
||||
*
|
||||
* Constraints for running this command include:
|
||||
* - The Operator must have locked STX on behalf of at least one stacker.
|
||||
* - The total amount previously locked by the Operator on behalf of the
|
||||
* stackers has to be greater than the uSTX threshold.
|
||||
* - All of the Stackers must have delegated to the same pox address.
|
||||
*/
|
||||
export class StackAggregationCommitCommand implements PoxCommand {
|
||||
readonly operator: Wallet;
|
||||
readonly authId: number;
|
||||
readonly currentCycle: number;
|
||||
|
||||
/**
|
||||
* Constructs a `StackAggregationCommitCommand` to lock uSTX for stacking.
|
||||
*
|
||||
* @param operator - Represents the `Operator`'s wallet.
|
||||
* @param authId - Unique `auth-id` for the authorization.
|
||||
* @param currentCycle - The current reward cycle.
|
||||
*/
|
||||
constructor(
|
||||
operator: Wallet,
|
||||
authId: number,
|
||||
currentCycle: number,
|
||||
) {
|
||||
this.operator = operator;
|
||||
this.authId = authId;
|
||||
this.currentCycle = currentCycle;
|
||||
}
|
||||
|
||||
check(model: Readonly<Stub>): boolean {
|
||||
// Constraints for running this command include:
|
||||
// - The Operator must have locked STX on behalf of at least one stacker.
|
||||
// - The total amount previously locked by the Operator on behalf of the
|
||||
// stackers has to be greater than the uSTX threshold.
|
||||
// - All of the Stackers must have delegated to the same pox address.
|
||||
let sameDelegatedPoxAddrAllStackers = true;
|
||||
const firstDelegatedPoxAddress = this.operator.lockedAddresses.length > 0
|
||||
? model.wallets.get(this.operator.lockedAddresses[0])!.delegatedPoxAddress
|
||||
: this.operator.btcAddress;
|
||||
|
||||
this.operator.lockedAddresses.forEach((stacker) => {
|
||||
if (
|
||||
model.wallets.get(stacker)!.delegatedPoxAddress !==
|
||||
firstDelegatedPoxAddress
|
||||
) sameDelegatedPoxAddrAllStackers = false;
|
||||
});
|
||||
|
||||
return this.operator.lockedAddresses.length > 0 &&
|
||||
this.operator.amountToCommit >= model.stackingMinimum &&
|
||||
sameDelegatedPoxAddrAllStackers;
|
||||
}
|
||||
|
||||
run(model: Stub, real: Real): void {
|
||||
model.trackCommandRun(this.constructor.name);
|
||||
|
||||
const committedAmount = this.operator.amountToCommit;
|
||||
|
||||
const { result: setSignature } = real.network.callPublicFn(
|
||||
"ST000000000000000000002AMW42H.pox-4",
|
||||
"set-signer-key-authorization",
|
||||
[
|
||||
// (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32))))
|
||||
poxAddressToTuple(this.operator.btcAddress),
|
||||
// (period uint)
|
||||
Cl.uint(1),
|
||||
// (reward-cycle uint)
|
||||
Cl.uint(this.currentCycle + 1),
|
||||
// (topic (string-ascii 14))
|
||||
Cl.stringAscii("agg-commit"),
|
||||
// (signer-key (buff 33))
|
||||
Cl.bufferFromHex(this.operator.signerPubKey),
|
||||
// (allowed bool)
|
||||
Cl.bool(true),
|
||||
// (max-amount uint)
|
||||
Cl.uint(this.operator.amountToCommit),
|
||||
// (auth-id uint)
|
||||
Cl.uint(this.authId),
|
||||
],
|
||||
this.operator.stxAddress,
|
||||
);
|
||||
expect(setSignature).toBeOk(Cl.bool(true));
|
||||
|
||||
// Act
|
||||
const stackAggregationCommit = real.network.callPublicFn(
|
||||
"ST000000000000000000002AMW42H.pox-4",
|
||||
"stack-aggregation-commit",
|
||||
[
|
||||
// (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32))))
|
||||
poxAddressToTuple(this.operator.btcAddress),
|
||||
// (reward-cycle uint)
|
||||
Cl.uint(this.currentCycle + 1),
|
||||
// (signer-sig (optional (buff 65)))
|
||||
Cl.none(),
|
||||
// (signer-key (buff 33))
|
||||
Cl.bufferFromHex(this.operator.signerPubKey),
|
||||
// (max-amount uint)
|
||||
Cl.uint(committedAmount),
|
||||
// (auth-id uint)
|
||||
Cl.uint(this.authId),
|
||||
],
|
||||
this.operator.stxAddress,
|
||||
);
|
||||
|
||||
// Assert
|
||||
expect(stackAggregationCommit.result).toBeOk(Cl.bool(true));
|
||||
|
||||
const operatorWallet = model.wallets.get(this.operator.stxAddress)!;
|
||||
|
||||
operatorWallet.amountToCommit -= committedAmount;
|
||||
|
||||
// Log to console for debugging purposes. This is not necessary for the
|
||||
// test to pass but it is useful for debugging and eyeballing the test.
|
||||
logCommand(`✓ ${this.operator.label}`, "stack-aggregation-commit", 'amount committed', committedAmount.toString());
|
||||
}
|
||||
|
||||
toString() {
|
||||
// fast-check will call toString() in case of errors, e.g. property failed.
|
||||
// It will then make a minimal counterexample, a process called 'shrinking'
|
||||
// https://github.com/dubzzz/fast-check/issues/2864#issuecomment-1098002642
|
||||
return `${this.operator.label} stack-aggregation-commit auth-id ${this.authId} for reward cycle ${this.currentCycle}`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user