@vechain/vebetterdao-contracts
Version:
Open-source repository that houses the smart contracts powering the decentralized VeBetterDAO on the VeChain Thor blockchain.
227 lines (226 loc) • 17.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const mocha_1 = require("mocha");
const chai_1 = require("chai");
const fixture_test_1 = require("./fixture.test");
const ethers_1 = require("ethers");
const common_1 = require("../helpers/common");
(0, mocha_1.describe)("VeBetterPassport (Reset Signal Count) - @shard8c", function () {
let veBetterPassport;
let owner;
let otherAccounts;
let appId;
let regularSignaler;
let resetSignaler;
let user;
let appAdmin;
(0, mocha_1.beforeEach)(async function () {
const fixture = await (0, fixture_test_1.setupSignalingFixture)();
veBetterPassport = fixture.veBetterPassport;
owner = fixture.owner;
otherAccounts = fixture.otherAccounts;
appId = fixture.appId;
regularSignaler = fixture.regularSignaler;
appAdmin = fixture.appAdmin;
// Setup a reset signaler with proper role
resetSignaler = otherAccounts[5];
await veBetterPassport.connect(owner).assignSignalerToApp(appId, resetSignaler.address);
await veBetterPassport.connect(owner).grantRole(await veBetterPassport.RESET_SIGNALER_ROLE(), resetSignaler.address);
// Setup a user with signals
user = otherAccounts[6];
await veBetterPassport.connect(owner).registerActionForRound(user.address, appId, 1);
await veBetterPassport.connect(regularSignaler).signalUserWithReason(user.address, "Test");
await veBetterPassport.connect(regularSignaler).signalUserWithReason(user.address, "Test1");
// Verify initial state
(0, chai_1.expect)(await veBetterPassport.signaledCounter(user.address)).to.equal(2);
});
(0, mocha_1.describe)("Reset Signals by Default Admin", function () {
(0, mocha_1.it)("Should allow to reset user signals", async function () {
await (0, chai_1.expect)(veBetterPassport.connect(owner).resetUserSignalsWithReason(user.address, "suspicious activity lifted"))
.to.emit(veBetterPassport, "UserSignalsReset")
.withArgs(user.address, "suspicious activity lifted");
// Verify signals were reset
(0, chai_1.expect)(await veBetterPassport.signaledCounter(user.address)).to.equal(0);
});
(0, mocha_1.it)("Should allow to reset user without signals", async function () {
const userWithoutSignals = otherAccounts[7];
(0, chai_1.expect)(await veBetterPassport.signaledCounter(userWithoutSignals.address)).to.equal(0);
await (0, chai_1.expect)(veBetterPassport.connect(owner).resetUserSignalsWithReason(userWithoutSignals.address, "no signals"))
.to.emit(veBetterPassport, "UserSignalsReset")
.withArgs(userWithoutSignals.address, "no signals");
});
});
(0, mocha_1.describe)("Reset Signals by RESET_SIGNALER_ROLE (internal use)", function () {
(0, mocha_1.it)("Should revert if a caller does not have RESET_SIGNALER_ROLE", async function () {
await (0, chai_1.expect)(veBetterPassport.connect(otherAccounts[7]).resetUserSignalsWithReason(user.address, "no signals")).to
.be.reverted;
});
(0, mocha_1.it)("Should allow to reset user without signals", async function () {
const userWithoutSignals = otherAccounts[7];
(0, chai_1.expect)(await veBetterPassport.signaledCounter(userWithoutSignals.address)).to.equal(0);
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, userWithoutSignals.address)).to.equal(0);
await (0, chai_1.expect)(veBetterPassport
.connect(resetSignaler)
.resetUserSignalsByAppWithReason(userWithoutSignals.address, "no signals"))
.to.emit(veBetterPassport, "UserSignalsResetForApp")
.withArgs(userWithoutSignals.address, appId, "no signals");
});
(0, mocha_1.it)("Should correctly handle resetting signals for passport-linked entities", async function () {
const entity = otherAccounts[9];
const passport = otherAccounts[10];
await veBetterPassport.connect(entity).linkEntityToPassport(passport.address);
await veBetterPassport.connect(passport).acceptEntityLink(entity.address);
await veBetterPassport.connect(owner).registerActionForRound(entity.address, appId, 1);
await veBetterPassport.connect(regularSignaler).signalUserWithReason(entity.address, "Test");
(0, chai_1.expect)(await veBetterPassport.signaledCounter(entity.address)).to.equal(1);
(0, chai_1.expect)(await veBetterPassport.signaledCounter(passport.address)).to.equal(1);
await veBetterPassport.connect(resetSignaler).resetUserSignalsWithReason(entity.address, "linked entity");
(0, chai_1.expect)(await veBetterPassport.signaledCounter(entity.address)).to.equal(0);
(0, chai_1.expect)(await veBetterPassport.signaledCounter(passport.address)).to.equal(0);
});
(0, mocha_1.it)("Should allow resetting signals for a user with zero signals", async function () {
const userWithZeroSignals = otherAccounts[13];
// Verify the user starts with 0 signals
(0, chai_1.expect)(await veBetterPassport.signaledCounter(userWithZeroSignals.address)).to.equal(0);
// Reset the signals
await (0, chai_1.expect)(veBetterPassport
.connect(resetSignaler)
.resetUserSignalsWithReason(userWithZeroSignals.address, "preventative reset"))
.to.emit(veBetterPassport, "UserSignalsReset")
.withArgs(userWithZeroSignals.address, "preventative reset");
(0, chai_1.expect)(await veBetterPassport.signaledCounter(userWithZeroSignals.address)).to.equal(0);
});
(0, mocha_1.it)("Should allow a reset signaler to reset their own signals", async function () {
await veBetterPassport.connect(regularSignaler).signalUserWithReason(resetSignaler.address, "Suspicious activity");
(0, chai_1.expect)(await veBetterPassport.signaledCounter(resetSignaler.address)).to.equal(1);
await (0, chai_1.expect)(veBetterPassport
.connect(resetSignaler)
.resetUserSignalsWithReason(resetSignaler.address, "clearing my own record"))
.to.emit(veBetterPassport, "UserSignalsReset")
.withArgs(resetSignaler.address, "clearing my own record");
(0, chai_1.expect)(await veBetterPassport.signaledCounter(resetSignaler.address)).to.equal(0);
});
});
(0, mocha_1.describe)("Reset Signals by SIGNALER_ROLE (for app admins)", function () {
(0, mocha_1.it)("Should revert if a caller does not have SIGNALER_ROLE", async function () {
await (0, chai_1.expect)(veBetterPassport.connect(otherAccounts[7]).resetUserSignalsByAppWithReason(user.address, "no signals")).to.be.reverted;
});
(0, mocha_1.it)("Should revert if random user tries to assign signaler role", async function () {
await (0, chai_1.expect)(veBetterPassport.connect(otherAccounts[7]).assignSignalerToAppByAppAdmin(appId, otherAccounts[7].address)).to.be.reverted;
});
(0, mocha_1.it)("Should revert if random user tries to remove signaler role", async function () {
await (0, chai_1.expect)(veBetterPassport.connect(otherAccounts[7]).removeSignalerFromApp(otherAccounts[7].address)).to.be
.reverted;
});
(0, mocha_1.it)("Should allow a signaler to reset signals", async function () {
const randomUser = otherAccounts[14];
await veBetterPassport.connect(appAdmin).assignSignalerToAppByAppAdmin(appId, regularSignaler.address);
await veBetterPassport.connect(regularSignaler).signalUserWithReason(randomUser.address, "Suspicious activity");
(0, chai_1.expect)(await veBetterPassport.signaledCounter(randomUser.address)).to.equal(1);
await (0, chai_1.expect)(veBetterPassport
.connect(regularSignaler)
.resetUserSignalsByAppWithReason(randomUser.address, "clearing a record"))
.to.emit(veBetterPassport, "UserSignalsResetForApp")
.withArgs(randomUser.address, appId, "clearing a record");
(0, chai_1.expect)(await veBetterPassport.signaledCounter(randomUser.address)).to.equal(0);
});
(0, mocha_1.it)("Should allow app admin to assign signaler role, then is able to revoke it, then is able to assign it again", async function () {
const newSignaler = otherAccounts[8];
await veBetterPassport.connect(appAdmin).assignSignalerToAppByAppAdmin(appId, newSignaler.address);
(0, chai_1.expect)(await veBetterPassport.appOfSignaler(newSignaler.address)).to.equal(appId);
(0, chai_1.expect)(await veBetterPassport.hasRole(await veBetterPassport.SIGNALER_ROLE(), newSignaler.address)).to.be.true;
await veBetterPassport.connect(appAdmin).removeSignalerFromAppByAppAdmin(newSignaler.address);
(0, chai_1.expect)(await veBetterPassport.appOfSignaler(newSignaler.address)).to.equal(ethers_1.ethers.ZeroHash);
(0, chai_1.expect)(await veBetterPassport.hasRole(await veBetterPassport.SIGNALER_ROLE(), newSignaler.address)).to.be.false;
await veBetterPassport.connect(appAdmin).assignSignalerToAppByAppAdmin(appId, newSignaler.address);
(0, chai_1.expect)(await veBetterPassport.appOfSignaler(newSignaler.address)).to.equal(appId);
(0, chai_1.expect)(await veBetterPassport.hasRole(await veBetterPassport.SIGNALER_ROLE(), newSignaler.address)).to.be.true;
});
(0, mocha_1.it)("Should should be able to be reset by DEFAULT ADMIN and SIGNALER_ROLE", async function () {
const badWallet = otherAccounts[11];
const defaultWalletSignaler = otherAccounts[12];
await veBetterPassport.connect(regularSignaler).signalUserWithReason(badWallet.address, "Test");
await veBetterPassport.connect(regularSignaler).signalUserWithReason(badWallet.address, "Test");
(0, chai_1.expect)(await veBetterPassport.signaledCounter(badWallet.address)).to.equal(2);
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, badWallet.address)).to.equal(2);
await veBetterPassport
.connect(owner)
.grantRole(await veBetterPassport.RESET_SIGNALER_ROLE(), defaultWalletSignaler.address);
await veBetterPassport.connect(defaultWalletSignaler).resetUserSignalsWithReason(badWallet.address, "Test");
(0, chai_1.expect)(await veBetterPassport.signaledCounter(badWallet.address)).to.equal(0);
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, badWallet.address)).to.equal(2); // reset signal count should not be affected by default admin signaler
await veBetterPassport.connect(regularSignaler).resetUserSignalsByAppWithReason(badWallet.address, "Test");
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, badWallet.address)).to.equal(0);
});
(0, mocha_1.it)("Should handle underflow protection when resetting app signals for an entity with passport", async function () {
// Setup entity and passport
const entity = otherAccounts[13];
const passport = otherAccounts[14];
// Link entity to passport
await (0, common_1.linkEntityToPassportWithSignature)(veBetterPassport, passport, entity, 100000);
// Signal the entity to accumulate some signals
await veBetterPassport.connect(regularSignaler).signalUserWithReason(entity.address, "Test signal 1");
await veBetterPassport.connect(regularSignaler).signalUserWithReason(entity.address, "Test signal 2");
// Verify signals are correctly assigned to both entity and passport
(0, chai_1.expect)(await veBetterPassport.signaledCounter(entity.address)).to.equal(2);
(0, chai_1.expect)(await veBetterPassport.signaledCounter(passport.address)).to.equal(2);
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, entity.address)).to.equal(2);
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, passport.address)).to.equal(2);
// Reset passport signals directly to create an inconsistency
// This creates the condition where passport has 0 signals but entity still has app signals
await veBetterPassport.connect(owner).resetUserSignalsWithReason(passport.address, "Resetting passport signals");
// Verify passport general signals are now 0, but app signals still exist
(0, chai_1.expect)(await veBetterPassport.signaledCounter(passport.address)).to.equal(0);
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, passport.address)).to.equal(2);
// Now reset entity app signals - this would have triggered underflow in passport signals before the fix
// Commit fix: https://github.com/vechain/b3tr/pull/2139/commits/8a1447fc11081947c61e48caab077c7c8311e9ff
await veBetterPassport
.connect(regularSignaler)
.resetUserSignalsByAppWithReason(entity.address, "Resetting entity app signals");
// Verify entity app signals are reset
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, entity.address)).to.equal(0);
// Verify passport counter remains at 0 (not underflowed to a large number)
(0, chai_1.expect)(await veBetterPassport.signaledCounter(passport.address)).to.equal(0);
// Verify passport app signals are also reset
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, passport.address)).to.equal(0);
});
(0, mocha_1.it)("Should handle underflow protection when removing entity link from passport", async function () {
// Setup entity and passport
const entity = otherAccounts[13];
const passport = otherAccounts[14];
// Link entity to passport
await (0, common_1.linkEntityToPassportWithSignature)(veBetterPassport, passport, entity, 100000);
// Signal the entity to accumulate some signals
await veBetterPassport.connect(regularSignaler).signalUserWithReason(entity.address, "Test signal 1");
await veBetterPassport.connect(regularSignaler).signalUserWithReason(entity.address, "Test signal 2");
// Verify signals correctly assigned to both entity and passport
(0, chai_1.expect)(await veBetterPassport.signaledCounter(entity.address)).to.equal(2);
(0, chai_1.expect)(await veBetterPassport.signaledCounter(passport.address)).to.equal(2);
// Verify app signals are also correctly assigned
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, entity.address)).to.equal(2);
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, passport.address)).to.equal(2);
// Reset passport signals directly, creating an inconsistency
await veBetterPassport.connect(owner).resetUserSignalsWithReason(passport.address, "Resetting passport signals");
// Manually reset passport app signals to 0 (this would normally be done by app-specific reset)
// This creates the potential underflow condition for app signals
await veBetterPassport
.connect(regularSignaler)
.resetUserSignalsByAppWithReason(passport.address, "Reset app signals");
// Verify passport signals are now 0, but entity still has signals
(0, chai_1.expect)(await veBetterPassport.signaledCounter(passport.address)).to.equal(0);
(0, chai_1.expect)(await veBetterPassport.signaledCounter(entity.address)).to.equal(2);
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, passport.address)).to.equal(0);
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, entity.address)).to.equal(2);
// Remove entity link from passport - this calls removeEntitySignalsFromPassport internally
// This would have failed before the fix with "VM Exception: underflow"
// Commit fix: https://github.com/vechain/b3tr/pull/2139/commits/8a1447fc11081947c61e48caab077c7c8311e9ff
await veBetterPassport.connect(entity).removeEntityLink(entity.address);
// Verify passport counters remain at 0 (not underflowed)
(0, chai_1.expect)(await veBetterPassport.signaledCounter(passport.address)).to.equal(0);
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, passport.address)).to.equal(0);
// Entity signals should be unchanged since they're not affected by the link removal
(0, chai_1.expect)(await veBetterPassport.signaledCounter(entity.address)).to.equal(2);
(0, chai_1.expect)(await veBetterPassport.appSignalsCounter(appId, entity.address)).to.equal(2);
});
});
});