@dydxfoundation/governance
Version:
dYdX governance smart contracts
408 lines (407 loc) • 30.6 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const utils_1 = require("ethers/lib/utils");
const constants_1 = require("../../src/lib/constants");
const util_1 = require("../../src/lib/util");
const types_1 = require("../../types");
const describe_contract_1 = require("../helpers/describe-contract");
const evm_1 = require("../helpers/evm");
const keys_1 = require("../helpers/keys");
const signature_helpers_1 = require("../helpers/signature-helpers");
const hre_1 = __importDefault(require("../hre"));
const SAFETY_MODULE_EIP_712_DOMAIN_NAME = 'dYdX Safety Module';
let userKeys;
async function init(ctx) {
userKeys = (0, keys_1.getUserKeys)();
// Give some tokens to stakers and set allowance.
const amount = hre_1.default.ethers.utils.parseEther('100').toString();
for (const user of ctx.users) {
await ctx.dydxToken.connect(ctx.deployer).transfer(user.address, amount);
await ctx.dydxToken.connect(user).approve(ctx.safetyModule.address, amount);
}
}
(0, describe_contract_1.describeContract)('Safety Module Staked DYDX - Power Delegation', init, (ctx) => {
it('User 1 tries to delegate voting power to user 2', async () => {
await ctx.safetyModule.connect(ctx.users[1]).delegateByType(ctx.users[2].address, '0');
const delegatee = await ctx.safetyModule.getDelegateeByType(ctx.users[1].address, '0');
(0, chai_1.expect)(delegatee).to.be.equal(ctx.users[2].address);
});
it('User 1 tries to delegate proposition power to user 3', async () => {
await ctx.safetyModule.connect(ctx.users[1]).delegateByType(ctx.users[3].address, '1');
const delegatee = await ctx.safetyModule.getDelegateeByType(ctx.users[1].address, '1');
(0, chai_1.expect)(delegatee).to.be.equal(ctx.users[3].address);
});
it('User 1 tries to delegate voting power to ZERO_ADDRESS but delegator should remain', async () => {
const tokenBalance = (0, utils_1.parseEther)('1');
// Stake
await ctx.safetyModule.connect(ctx.users[1]).stake(tokenBalance);
// Track current power
const priorPowerUser = await ctx.safetyModule.getPowerCurrent(ctx.users[1].address, '0');
const priorPowerUserZeroAddress = await ctx.safetyModule.getPowerCurrent(constants_1.ZERO_ADDRESS, '0');
(0, chai_1.expect)(priorPowerUser).to.be.equal(tokenBalance, 'user power should equal balance');
(0, chai_1.expect)(priorPowerUserZeroAddress).to.be.equal('0', 'zero address should have zero power');
await (0, chai_1.expect)(ctx.safetyModule.connect(ctx.users[1]).delegateByType(constants_1.ZERO_ADDRESS, '0')).to.be.revertedWith('INVALID_DELEGATEE');
});
it('User 1 stakes 2 DYDX; checks voting and proposition power of user 2 and 3', async () => {
// Setup: user 1 has delegated to ctx.users 2 and 3...
await ctx.safetyModule.connect(ctx.users[1]).delegateByType(ctx.users[2].address, '0');
await ctx.safetyModule.connect(ctx.users[1]).delegateByType(ctx.users[3].address, '1');
const tokenBalance = (0, utils_1.parseEther)('2');
const expectedStaked = (0, utils_1.parseEther)('2');
// Stake
await ctx.safetyModule.connect(ctx.users[1]).stakeFor(ctx.users[1].address, tokenBalance);
const stakedTokenBalanceAfterMigration = await ctx.safetyModule.balanceOf(ctx.users[1].address);
const user1PropPower = await ctx.safetyModule.getPowerCurrent(ctx.users[1].address, '0');
const user1VotingPower = await ctx.safetyModule.getPowerCurrent(ctx.users[1].address, '1');
const user2VotingPower = await ctx.safetyModule.getPowerCurrent(ctx.users[2].address, '0');
const user2PropPower = await ctx.safetyModule.getPowerCurrent(ctx.users[2].address, '1');
const user3VotingPower = await ctx.safetyModule.getPowerCurrent(ctx.users[3].address, '0');
const user3PropPower = await ctx.safetyModule.getPowerCurrent(ctx.users[3].address, '1');
(0, chai_1.expect)(user1PropPower).to.be.equal('0', 'Incorrect prop power for user 1');
(0, chai_1.expect)(user1VotingPower).to.be.equal('0', 'Incorrect voting power for user 1');
(0, chai_1.expect)(user2PropPower).to.be.equal('0', 'Incorrect prop power for user 2');
(0, chai_1.expect)(user2VotingPower).to.be.equal(stakedTokenBalanceAfterMigration, 'Incorrect voting power for user 2');
(0, chai_1.expect)(user3PropPower).to.be.equal(stakedTokenBalanceAfterMigration, 'Incorrect prop power for user 3');
(0, chai_1.expect)(user3VotingPower).to.be.equal('0', 'Incorrect voting power for user 3');
(0, chai_1.expect)(expectedStaked).to.be.equal(stakedTokenBalanceAfterMigration);
});
describe('after user 1 delegates to ctx.users 2 and 3, and stakes 2 DYDX', () => {
beforeEach(async () => {
// Setup: user 1 has delegated to ctx.users 2 and 3 and stakes 2 DYDX...
await ctx.safetyModule.connect(ctx.users[1]).delegateByType(ctx.users[2].address, '0');
await ctx.safetyModule.connect(ctx.users[1]).delegateByType(ctx.users[3].address, '1');
await ctx.safetyModule.connect(ctx.users[1]).stakeFor(ctx.users[1].address, (0, utils_1.parseEther)('2'));
});
it('User 2 stakes 2 DYDX; checks voting and proposition power of user 2', async () => {
const tokenBalance = (0, utils_1.parseEther)('2');
const expectedStakedTokenBalanceAfterStake = (0, utils_1.parseEther)('2');
// Stake
await ctx.safetyModule.connect(ctx.users[2]).stakeFor(ctx.users[2].address, tokenBalance);
const user2VotingPower = await ctx.safetyModule.getPowerCurrent(ctx.users[2].address, '0');
const user2PropPower = await ctx.safetyModule.getPowerCurrent(ctx.users[2].address, '1');
(0, chai_1.expect)(user2PropPower).to.be.equal(expectedStakedTokenBalanceAfterStake, 'Incorrect prop power for user 2');
(0, chai_1.expect)(user2VotingPower).to.be.equal(expectedStakedTokenBalanceAfterStake.mul('2'), 'Incorrect voting power for user 2');
});
it('User 3 stakes 2 DYDX; checks voting and proposition power of user 3', async () => {
// Stake
await ctx.safetyModule.connect(ctx.users[3]).stakeFor(ctx.users[3].address, (0, utils_1.parseEther)('2'));
const user3VotingPower = await ctx.safetyModule.getPowerCurrent(ctx.users[3].address, '0');
const user3PropPower = await ctx.safetyModule.getPowerCurrent(ctx.users[3].address, '1');
(0, chai_1.expect)(user3PropPower.toString()).to.be.equal((0, utils_1.parseEther)('4'), 'Incorrect prop power for user 3');
(0, chai_1.expect)(user3VotingPower.toString()).to.be.equal((0, utils_1.parseEther)('2'), 'Incorrect voting power for user 3');
});
it('User 2 also delegates powers to user 3', async () => {
// Stake
await ctx.safetyModule.connect(ctx.users[2]).stakeFor(ctx.users[2].address, (0, utils_1.parseEther)('2'));
await ctx.safetyModule.connect(ctx.users[3]).stakeFor(ctx.users[3].address, (0, utils_1.parseEther)('2'));
// Delegate
await ctx.safetyModule.connect(ctx.users[2]).delegate(ctx.users[3].address);
(0, chai_1.expect)(await ctx.safetyModule.getPowerCurrent(ctx.users[3].address, '0')).to.be.equal((0, utils_1.parseEther)('4'), 'Incorrect voting power for user 3');
(0, chai_1.expect)(await ctx.safetyModule.getPowerCurrent(ctx.users[3].address, '1')).to.be.equal((0, utils_1.parseEther)('6'), 'Incorrect prop power for user 3');
});
});
it('Checks the delegation at a past block', async () => {
// Setup: user 1 has delegated to ctx.users 2 and 3...
await ctx.safetyModule.connect(ctx.users[1]).delegateByType(ctx.users[2].address, '0');
await ctx.safetyModule.connect(ctx.users[1]).delegateByType(ctx.users[3].address, '1');
// Stake
await ctx.safetyModule.connect(ctx.users[1]).stakeFor(ctx.users[1].address, (0, utils_1.parseEther)('2'));
const blockNumber = await (0, evm_1.latestBlock)();
const user1 = ctx.users[1];
const user2 = ctx.users[2];
const user3 = ctx.users[3];
const user1VotingPower = await ctx.safetyModule.getPowerAtBlock(user1.address, blockNumber, '0');
const user1PropPower = await ctx.safetyModule.getPowerAtBlock(user1.address, blockNumber, '1');
const user2VotingPower = await ctx.safetyModule.getPowerAtBlock(user2.address, blockNumber, '0');
const user2PropPower = await ctx.safetyModule.getPowerAtBlock(user2.address, blockNumber, '1');
const user3VotingPower = await ctx.safetyModule.getPowerAtBlock(user3.address, blockNumber, '0');
const user3PropPower = await ctx.safetyModule.getPowerAtBlock(user3.address, blockNumber, '1');
const expectedUser1DelegatedVotingPower = '0';
const expectedUser1DelegatedPropPower = '0';
const expectedUser2DelegatedVotingPower = (0, utils_1.parseEther)('2');
const expectedUser2DelegatedPropPower = '0';
const expectedUser3DelegatedVotingPower = '0';
const expectedUser3DelegatedPropPower = (0, utils_1.parseEther)('2');
(0, chai_1.expect)(user1VotingPower.toString()).to.be.equal(expectedUser1DelegatedPropPower, 'Incorrect voting power for user 1');
(0, chai_1.expect)(user1PropPower.toString()).to.be.equal(expectedUser1DelegatedVotingPower, 'Incorrect prop power for user 1');
(0, chai_1.expect)(user2VotingPower.toString()).to.be.equal(expectedUser2DelegatedVotingPower, 'Incorrect voting power for user 2');
(0, chai_1.expect)(user2PropPower.toString()).to.be.equal(expectedUser2DelegatedPropPower, 'Incorrect prop power for user 2');
(0, chai_1.expect)(user3VotingPower.toString()).to.be.equal(expectedUser3DelegatedVotingPower, 'Incorrect voting power for user 3');
(0, chai_1.expect)(user3PropPower.toString()).to.be.equal(expectedUser3DelegatedPropPower, 'Incorrect prop power for user 3');
});
it('Ensure that getting the power at the current block is the same as using getPowerCurrent', async () => {
// Setup: user 1 has delegated to ctx.users 2 and 3...
await ctx.safetyModule.connect(ctx.users[1]).delegateByType(ctx.users[2].address, '0');
await ctx.safetyModule.connect(ctx.users[1]).delegateByType(ctx.users[3].address, '1');
// Stake
await ctx.safetyModule.connect(ctx.users[1]).stakeFor(ctx.users[1].address, (0, utils_1.parseEther)('2'));
const currTime = await (0, evm_1.latestBlockTimestamp)();
await (0, evm_1.advanceBlock)(currTime + 1);
const currentBlock = await (0, evm_1.latestBlock)();
const votingPowerAtPreviousBlock = await ctx.safetyModule.getPowerAtBlock(ctx.users[1].address, currentBlock - 1, '0');
const votingPowerCurrent = await ctx.safetyModule.getPowerCurrent(ctx.users[1].address, '0');
const propPowerAtPreviousBlock = await ctx.safetyModule.getPowerAtBlock(ctx.users[1].address, currentBlock - 1, '1');
const propPowerCurrent = await ctx.safetyModule.getPowerCurrent(ctx.users[1].address, '1');
(0, chai_1.expect)(votingPowerAtPreviousBlock.toString()).to.be.equal(votingPowerCurrent.toString(), 'Incorrect voting power for user 1');
(0, chai_1.expect)(propPowerAtPreviousBlock.toString()).to.be.equal(propPowerCurrent.toString(), 'Incorrect voting power for user 1');
});
it("Checks you can't fetch power at a block in the future", async () => {
const currentBlock = await (0, evm_1.latestBlock)();
await (0, chai_1.expect)(ctx.safetyModule.getPowerAtBlock(ctx.users[1].address, currentBlock + 1, '0')).to.be.revertedWith('INVALID_BLOCK_NUMBER');
await (0, chai_1.expect)(ctx.safetyModule.getPowerAtBlock(ctx.users[1].address, currentBlock + 1, '1')).to.be.revertedWith('INVALID_BLOCK_NUMBER');
});
it('User 1 transfers value to himself. Ensures nothing changes in the delegated power', async () => {
const user1VotingPowerBefore = await ctx.safetyModule.getPowerCurrent(ctx.users[1].address, '0');
const user1PropPowerBefore = await ctx.safetyModule.getPowerCurrent(ctx.users[1].address, '1');
const balance = await ctx.safetyModule.balanceOf(ctx.users[1].address);
await ctx.safetyModule.connect(ctx.users[1]).transfer(ctx.users[1].address, balance);
const user1VotingPowerAfter = await ctx.safetyModule.getPowerCurrent(ctx.users[1].address, '0');
const user1PropPowerAfter = await ctx.safetyModule.getPowerCurrent(ctx.users[1].address, '1');
(0, chai_1.expect)(user1VotingPowerBefore.toString()).to.be.equal(user1VotingPowerAfter, 'Incorrect voting power for user 1');
(0, chai_1.expect)(user1PropPowerBefore.toString()).to.be.equal(user1PropPowerAfter, 'Incorrect prop power for user 1');
});
it('User 1 delegates voting power to User 2 via signature', async () => {
const [user1, user2] = ctx.users;
// Calculate expected voting power
const user2VotingPower = await ctx.safetyModule.getPowerCurrent(user2.address, '1');
const expectedVotingPower = (await ctx.safetyModule.getPowerCurrent(user1.address, '1')).add(user2VotingPower);
// Check prior delegatee is still user1
const priorDelegatee = await ctx.safetyModule.getDelegateeByType(user1.address, '0');
(0, chai_1.expect)(priorDelegatee).to.be.equal(user1.address);
// Prepare params to sign message
const chainId = await (0, signature_helpers_1.getChainIdForSigning)();
const nonce = (await ctx.safetyModule.nonces(user1.address)).toString();
const expiration = constants_1.MAX_UINT_AMOUNT;
const msgParams = (0, signature_helpers_1.buildDelegateByTypeParams)(chainId, ctx.safetyModule.address, user2.address, '0', nonce, expiration, SAFETY_MODULE_EIP_712_DOMAIN_NAME);
const ownerPrivateKey = userKeys[0];
const { v, r, s } = (0, signature_helpers_1.getSignatureFromTypedData)(ownerPrivateKey, msgParams);
// Transmit message via delegateByTypeBySig
const tx = await ctx.safetyModule
.connect(user1)
.delegateByTypeBySig(user2.address, '0', nonce, expiration, v, r, s);
await (0, util_1.waitForTx)(tx);
// Check tx success and DelegateChanged
await (0, chai_1.expect)(tx)
.to.emit(ctx.safetyModule, 'DelegateChanged')
.withArgs(user1.address, user2.address, 0);
// Check DelegatedPowerChanged event: ctx.users[1] power should drop to zero
await (0, chai_1.expect)(tx)
.to.emit(ctx.safetyModule, 'DelegatedPowerChanged')
.withArgs(user1.address, 0, 0);
// Check DelegatedPowerChanged event: ctx.users[2] power should increase to expectedVotingPower
await (0, chai_1.expect)(tx)
.to.emit(ctx.safetyModule, 'DelegatedPowerChanged')
.withArgs(user2.address, expectedVotingPower, 0);
// Check internal state
const delegatee = await ctx.safetyModule.getDelegateeByType(user1.address, '0');
(0, chai_1.expect)(delegatee).to.be.equal(user2.address, 'Delegatee should be user 2');
const user2VotingPowerFinal = await ctx.safetyModule.getPowerCurrent(user2.address, '0');
(0, chai_1.expect)(user2VotingPowerFinal).to.be.equal(expectedVotingPower, 'Delegatee should have voting power from user 1');
});
it('User 1 delegates proposition to User 3 via signature', async () => {
const [user1, , user3] = ctx.users;
// Calculate expected proposition power
const user3PropPower = await ctx.safetyModule.getPowerCurrent(user3.address, '1');
const expectedPropPower = (await ctx.safetyModule.getPowerCurrent(user1.address, '1')).add(user3PropPower);
// Check prior proposition delegatee is still user1
const priorDelegatee = await ctx.safetyModule.getDelegateeByType(user1.address, '1');
(0, chai_1.expect)(priorDelegatee).to.be.equal(user1.address, 'expected proposition delegatee to be user1');
// Prepare parameters to sign message
const chainId = await (0, signature_helpers_1.getChainIdForSigning)();
const nonce = (await ctx.safetyModule.nonces(user1.address)).toString();
const expiration = constants_1.MAX_UINT_AMOUNT;
const msgParams = (0, signature_helpers_1.buildDelegateByTypeParams)(chainId, ctx.safetyModule.address, user3.address, '1', nonce, expiration, SAFETY_MODULE_EIP_712_DOMAIN_NAME);
const ownerPrivateKey = userKeys[0];
const { v, r, s } = (0, signature_helpers_1.getSignatureFromTypedData)(ownerPrivateKey, msgParams);
// Transmit tx via delegateByTypeBySig
const tx = await ctx.safetyModule
.connect(user1)
.delegateByTypeBySig(user3.address, '1', nonce, expiration, v, r, s);
// Check tx success and DelegateChanged
await (0, chai_1.expect)(tx)
.to.emit(ctx.safetyModule, 'DelegateChanged')
.withArgs(user1.address, user3.address, 1);
// Check DelegatedPowerChanged event: ctx.users[1] power should drop to zero
await (0, chai_1.expect)(tx)
.to.emit(ctx.safetyModule, 'DelegatedPowerChanged')
.withArgs(user1.address, 0, 1);
// Check DelegatedPowerChanged event: ctx.users[2] power should increase to expectedVotingPower
await (0, chai_1.expect)(tx)
.to.emit(ctx.safetyModule, 'DelegatedPowerChanged')
.withArgs(user3.address, expectedPropPower, 1);
// Check internal state matches events
const delegatee = await ctx.safetyModule.getDelegateeByType(user1.address, '1');
(0, chai_1.expect)(delegatee).to.be.equal(user3.address, 'Delegatee should be user 3');
const user3PropositionPower = await ctx.safetyModule.getPowerCurrent(user3.address, '1');
(0, chai_1.expect)(user3PropositionPower).to.be.equal(expectedPropPower, 'Delegatee should have propostion power from user 1');
});
it('User 2 delegates all to User 4 via signature', async () => {
const [user1, user2, , user4] = ctx.users;
await ctx.safetyModule.connect(user2).delegate(user2.address);
// Calculate expected powers
const user4PropPower = await ctx.safetyModule.getPowerCurrent(user4.address, '1');
const expectedPropPower = (await ctx.safetyModule.getPowerCurrent(user2.address, '1')).add(user4PropPower);
const user1VotingPower = await ctx.safetyModule.balanceOf(user1.address);
const user4VotingPower = await ctx.safetyModule.getPowerCurrent(user4.address, '0');
const user2ExpectedVotingPower = user1VotingPower;
const user4ExpectedVotingPower = (await ctx.safetyModule.getPowerCurrent(user2.address, '0'))
.add(user4VotingPower)
.sub(user1VotingPower); // Delegation does not delegate votes others from other delegations
// Check prior proposition delegatee is still user1
const priorPropDelegatee = await ctx.safetyModule.getDelegateeByType(user2.address, '1');
(0, chai_1.expect)(priorPropDelegatee).to.be.equal(user2.address, 'expected proposition delegatee to be user1');
const priorVotDelegatee = await ctx.safetyModule.getDelegateeByType(user2.address, '0');
(0, chai_1.expect)(priorVotDelegatee).to.be.equal(user2.address, 'expected proposition delegatee to be user1');
// Prepare parameters to sign message
const chainId = await (0, signature_helpers_1.getChainIdForSigning)();
const nonce = (await ctx.safetyModule.nonces(user2.address)).toString();
const expiration = constants_1.MAX_UINT_AMOUNT;
const msgParams = (0, signature_helpers_1.buildDelegateParams)(chainId, ctx.safetyModule.address, user4.address, nonce, expiration, SAFETY_MODULE_EIP_712_DOMAIN_NAME);
const ownerPrivateKey = userKeys[1];
const { v, r, s } = (0, signature_helpers_1.getSignatureFromTypedData)(ownerPrivateKey, msgParams);
// Transmit tx via delegateByTypeBySig
const tx = await ctx.safetyModule
.connect(user2)
.delegateBySig(user4.address, nonce, expiration, v, r, s);
// Check tx success and DelegateChanged for voting
await (0, chai_1.expect)(tx)
.to.emit(ctx.safetyModule, 'DelegateChanged')
.withArgs(user2.address, user4.address, 1);
// Check tx success and DelegateChanged for proposition
await (0, chai_1.expect)(tx)
.to.emit(ctx.safetyModule, 'DelegateChanged')
.withArgs(user2.address, user4.address, 0);
// Check DelegatedPowerChanged event: ctx.users[2] power should drop to zero
await (0, chai_1.expect)(tx)
.to.emit(ctx.safetyModule, 'DelegatedPowerChanged')
.withArgs(user2.address, 0, 1);
// Check DelegatedPowerChanged event: ctx.users[4] power should increase to expectedVotingPower
await (0, chai_1.expect)(tx)
.to.emit(ctx.safetyModule, 'DelegatedPowerChanged')
.withArgs(user4.address, expectedPropPower, 1);
// Check DelegatedPowerChanged event: ctx.users[2] power should drop to zero
await (0, chai_1.expect)(tx)
.to.emit(ctx.safetyModule, 'DelegatedPowerChanged')
.withArgs(user2.address, user2ExpectedVotingPower, 0);
// Check DelegatedPowerChanged event: ctx.users[4] power should increase to expectedVotingPower
await (0, chai_1.expect)(tx)
.to.emit(ctx.safetyModule, 'DelegatedPowerChanged')
.withArgs(user4.address, user4ExpectedVotingPower, 0);
// Check internal state matches events
const propDelegatee = await ctx.safetyModule.getDelegateeByType(user2.address, '1');
(0, chai_1.expect)(propDelegatee).to.be.equal(user4.address, 'Proposition delegatee should be user 4');
const votDelegatee = await ctx.safetyModule.getDelegateeByType(user2.address, '0');
(0, chai_1.expect)(votDelegatee).to.be.equal(user4.address, 'Voting delegatee should be user 4');
const user4PropositionPower = await ctx.safetyModule.getPowerCurrent(user4.address, '1');
(0, chai_1.expect)(user4PropositionPower).to.be.equal(expectedPropPower, 'Delegatee should have propostion power from user 2');
const user4VotingPowerFinal = await ctx.safetyModule.getPowerCurrent(user4.address, '0');
(0, chai_1.expect)(user4VotingPowerFinal).to.be.equal(user4ExpectedVotingPower, 'Delegatee should have votinh power from user 2');
const user2PropositionPower = await ctx.safetyModule.getPowerCurrent(user2.address, '1');
(0, chai_1.expect)(user2PropositionPower).to.be.equal('0', 'User 2 should have zero prop power');
const user2VotingPower = await ctx.safetyModule.getPowerCurrent(user2.address, '0');
(0, chai_1.expect)(user2VotingPower).to.be.equal(user2ExpectedVotingPower, 'User 2 should still have voting power from user 1 delegation');
});
it('User 1 should not be able to delegate with bad signature', async () => {
const [user1, user2] = ctx.users;
// Prepare params to sign message
const chainId = await (0, signature_helpers_1.getChainIdForSigning)();
const nonce = (await ctx.safetyModule.nonces(user1.address)).toString();
const expiration = constants_1.MAX_UINT_AMOUNT;
const msgParams = (0, signature_helpers_1.buildDelegateByTypeParams)(chainId, ctx.safetyModule.address, user2.address, '0', nonce, expiration, SAFETY_MODULE_EIP_712_DOMAIN_NAME);
const ownerPrivateKey = userKeys[0];
const { r, s } = (0, signature_helpers_1.getSignatureFromTypedData)(ownerPrivateKey, msgParams);
// Transmit message via delegateByTypeBySig
await (0, chai_1.expect)(ctx.safetyModule
.connect(user1)
.delegateByTypeBySig(user2.address, '0', nonce, expiration, 0, r, s)).to.be.revertedWith('INVALID_SIGNATURE');
});
it('User 1 should not be able to delegate with bad nonce', async () => {
const [user1, user2] = ctx.users;
// Prepare params to sign message
const chainId = await (0, signature_helpers_1.getChainIdForSigning)();
const expiration = constants_1.MAX_UINT_AMOUNT;
const msgParams = (0, signature_helpers_1.buildDelegateByTypeParams)(chainId, ctx.safetyModule.address, user2.address, '0', constants_1.MAX_UINT_AMOUNT, // bad nonce
expiration, SAFETY_MODULE_EIP_712_DOMAIN_NAME);
const ownerPrivateKey = userKeys[0];
const { v, r, s } = (0, signature_helpers_1.getSignatureFromTypedData)(ownerPrivateKey, msgParams);
// Transmit message via delegateByTypeBySig
await (0, chai_1.expect)(ctx.safetyModule
.connect(user1)
.delegateByTypeBySig(user2.address, '0', constants_1.MAX_UINT_AMOUNT, expiration, v, r, s)).to.be.revertedWith('INVALID_NONCE');
});
it('User 1 should not be able to delegate if signature expired', async () => {
const [user1, user2] = ctx.users;
// Prepare params to sign message
const chainId = await (0, signature_helpers_1.getChainIdForSigning)();
const nonce = (await ctx.safetyModule.nonces(user1.address)).toString();
const expiration = '0';
const msgParams = (0, signature_helpers_1.buildDelegateByTypeParams)(chainId, ctx.safetyModule.address, user2.address, '0', nonce, expiration, SAFETY_MODULE_EIP_712_DOMAIN_NAME);
const ownerPrivateKey = userKeys[2];
const { v, r, s } = (0, signature_helpers_1.getSignatureFromTypedData)(ownerPrivateKey, msgParams);
// Transmit message via delegateByTypeBySig
await (0, chai_1.expect)(ctx.safetyModule
.connect(user1)
.delegateByTypeBySig(user2.address, '0', nonce, expiration, v, r, s)).to.be.revertedWith('INVALID_EXPIRATION');
});
it('User 2 should not be able to delegate all with bad signature', async () => {
const [, user2, , user4] = ctx.users;
// Prepare parameters to sign message
const chainId = await (0, signature_helpers_1.getChainIdForSigning)();
const nonce = (await ctx.safetyModule.nonces(user2.address)).toString();
const expiration = constants_1.MAX_UINT_AMOUNT;
const msgParams = (0, signature_helpers_1.buildDelegateParams)(chainId, ctx.safetyModule.address, user4.address, nonce, expiration, SAFETY_MODULE_EIP_712_DOMAIN_NAME);
const ownerPrivateKey = userKeys[3];
const { r, s } = (0, signature_helpers_1.getSignatureFromTypedData)(ownerPrivateKey, msgParams);
// Transmit tx via delegateBySig
await (0, chai_1.expect)(ctx.safetyModule.connect(user2).delegateBySig(user4.address, nonce, expiration, '0', r, s)).to.be.revertedWith('INVALID_SIGNATURE');
});
it('User 2 should not be able to delegate all with bad nonce', async () => {
const [, user2, , user4] = ctx.users;
// Prepare parameters to sign message
const chainId = await (0, signature_helpers_1.getChainIdForSigning)();
const nonce = constants_1.MAX_UINT_AMOUNT;
const expiration = constants_1.MAX_UINT_AMOUNT;
const msgParams = (0, signature_helpers_1.buildDelegateParams)(chainId, ctx.safetyModule.address, user4.address, nonce, expiration, SAFETY_MODULE_EIP_712_DOMAIN_NAME);
const ownerPrivateKey = userKeys[3];
const { v, r, s } = (0, signature_helpers_1.getSignatureFromTypedData)(ownerPrivateKey, msgParams);
// Transmit tx via delegateByTypeBySig
await (0, chai_1.expect)(ctx.safetyModule.connect(user2).delegateBySig(user4.address, nonce, expiration, v, r, s)).to.be.revertedWith('INVALID_NONCE');
});
it('User 2 should not be able to delegate all if signature expired', async () => {
const [, user2, , user4] = ctx.users;
// Prepare parameters to sign message
const chainId = await (0, signature_helpers_1.getChainIdForSigning)();
const nonce = (await ctx.safetyModule.nonces(user2.address)).toString();
const expiration = '0';
const msgParams = (0, signature_helpers_1.buildDelegateParams)(chainId, ctx.safetyModule.address, user4.address, nonce, expiration, SAFETY_MODULE_EIP_712_DOMAIN_NAME);
const ownerPrivateKey = userKeys[3];
const { v, r, s } = (0, signature_helpers_1.getSignatureFromTypedData)(ownerPrivateKey, msgParams);
// Transmit tx via delegateByTypeBySig
await (0, chai_1.expect)(ctx.safetyModule.connect(user2).delegateBySig(user4.address, nonce, expiration, v, r, s)).to.be.revertedWith('INVALID_EXPIRATION');
});
it('Correct proposal and voting snapshotting on double action in the same block', async () => {
const [sender, receiver] = ctx.users;
// Stake
const initialBalance = (0, utils_1.parseEther)('1');
await ctx.safetyModule.connect(sender).stake(initialBalance);
const receiverPriorPower = await ctx.safetyModule.getPowerCurrent(receiver.address, '0');
const senderPriorPower = await ctx.safetyModule.getPowerCurrent(sender.address, '0');
// Deploy double transfer helper
const doubleTransferHelper = await new types_1.DoubleTransferHelper__factory(ctx.deployer).deploy(ctx.safetyModule.address);
await (0, util_1.waitForTx)(await ctx.safetyModule
.connect(sender)
.transfer(doubleTransferHelper.address, initialBalance));
// Do double transfer
await (0, util_1.waitForTx)(await doubleTransferHelper
.connect(sender)
.doubleSend(receiver.address, (0, utils_1.parseEther)('0.7'), initialBalance.sub((0, utils_1.parseEther)('0.7'))));
const receiverCurrentPower = await ctx.safetyModule.getPowerCurrent(receiver.address, '0');
const senderCurrentPower = await ctx.safetyModule.getPowerCurrent(sender.address, '0');
(0, chai_1.expect)(receiverCurrentPower).to.be.equal(senderPriorPower.add(receiverPriorPower), 'Receiver should have added the sender power after double transfer');
(0, chai_1.expect)(senderCurrentPower).to.be.equal('0', 'Sender power should be zero due transfered all the funds');
});
});