Skip to content

Commit b82dcb1

Browse files
author
Reuben Rodrigues
committed
WIP
1 parent 942d229 commit b82dcb1

File tree

4 files changed

+1651
-1511
lines changed

4 files changed

+1651
-1511
lines changed

test/mainnet/matic.test.ts

Lines changed: 217 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import hre, { ethers } from 'hardhat'
2-
32
import {
43
Controller, ElasticSupplyPool, TenderToken, IMatic, BPool, EIP173Proxy, Matic, ERC20
54
} from '../../typechain'
@@ -16,7 +15,9 @@ import { BigNumber } from '@ethersproject/bignumber'
1615
import { Contract, ContractTransaction } from '@ethersproject/contracts'
1716

1817
import { Signer } from '@ethersproject/abstract-signer'
19-
import { percOf2, sharesToTokens } from '../util/helpers'
18+
import { percOf2, sharesToTokens, buildsubmitCheckpointPaylod, getBlockHeader } from '../util/helpers'
19+
const MerkleTree = require('../util/merkle-tree')
20+
const ethUtils = require('ethereumjs-util')
2021

2122
chai.use(solidity)
2223
const {
@@ -55,14 +56,114 @@ describe('Matic Mainnet Fork Test', () => {
5556
deployer = namedAccs.deployer
5657
})
5758

58-
const STEAK_AMOUNT = '100000'
59+
const STEAK_AMOUNT = '10000000'
5960
const NODE = '0xaC1D6c20cE7F1fBF1915eFc0898D188b9C6A5CeD' // Validator share address
6061
const stakeManagerAddr = '0x5e3ef299fddf15eaa0432e6e66473ace8c13d908'
6162
const rootChainAddr = '0x86E4Dc95c7FBdBf52e33D563BbDB00823894C287'
63+
const childChainURL = 'https://matic-mainnet.chainstacklabs.com'
6264

6365
const maticHolder = '0x2f7e209e0F5F645c7612D7610193Fe268F118b28'
6466
let maticHolderSinger: Signer
6567

68+
const nodeSignerAddr = '0x7b5000af8ab69fd59eb0d4f5762bff57c9c04385'
69+
const otherSignersAddr = [
70+
'0xb79fad4ca981472442f53d16365fdf0305ffd8e9',
71+
'0xf0245f6251bef9447a08766b9da2b07b28ad80b0',
72+
'0x7c7379531b2aee82e4ca06d4175d13b9cbeafd49',
73+
'0x1ca971963bdb4ba2bf337c90660674acff5beb3f',
74+
'0x4f856f79f54592a48c8a1a1fafa1b0a3ac053f99',
75+
'0xbdbd4347b082d9d6bdf2da4555a37ce52a2e2120',
76+
'0xc6869257205e20c2a43cb31345db534aecb49f6e',
77+
'0xe77bbfd8ed65720f187efdd109e38d75eaca7385',
78+
'0x742d13f0b2a19c823bdd362b16305e4704b97a38',
79+
'0xbc6044f4a1688d8b8596a9f7d4659e09985eebe6',
80+
'0x959c65b72147faf3450d8b50a0de57e72ffc5e0d',
81+
'0x5b106f49f30620a07b4fbdcebb1e08b70499c851',
82+
'0xe4cd4c302befddf3d544301369ae3ed1481652fd',
83+
'0x5fe93ddf4490a02257bef079f2498650c97c44de',
84+
'0x8e9700392f9246a6c5b32ee3ecef586f156ed683',
85+
'0xb2dd091ea6e591d62f565d7a18ce2a7640add227',
86+
'0x10ad27a96cdbffc90ab3b83bf695911426a69f5e',
87+
'0x448aa1665fe1fae6d1a00a9209ea62d7dcd81a4b',
88+
'0xc35649ae99be820c7b200a0add09b96d7032d232',
89+
'0x25c32fd6ed7b84435a222084ef3fdbb36252b8de',
90+
'0x5973918275c01f50555d44e92c9d9b353cadad54',
91+
'0x4923de87853e95751a87eafe957a88a564387dac',
92+
'0xb702f1c9154ac9c08da247a8e30ee6f2f3373f41',
93+
'0xeb4f2a75cac4bbcb4d71c252e4cc80eb80bb3a34',
94+
'0x00856730088a5c3191bd26eb482e45229555ce57',
95+
'0xe63727cb2b3a8d6e3a2d1df4990f441938b67a34',
96+
'0x73d378cfeaa5cbe8daed64128ebdc91322aa586b',
97+
'0x28c0d4328520ed7e8657de141eee74a954b07c1f',
98+
'0x7e8024132d07e3e69c9bc2012dffe300b9c5807d',
99+
'0x9c56f33b968f83922bccf6d7689b9c883af9de49',
100+
'0x127685d6dd6683085da4b6a041efcef1681e5c9c',
101+
'0xb8bb158b93c94ed35c1970d610d1e2b34e26652c',
102+
'0x7fcd58c2d53d980b247f1612fdba93e9a76193e6',
103+
'0x02f70172f7f490653665c9bfac0666147c8af1f5',
104+
'0xa3bf7e661822fcc4f2129e93096cbb70dce6d3c9',
105+
'0x6237b2af1238d12248630ce21aa84f0952122232',
106+
'0xf84c74dea96df0ec22e11e7c33996c73fcc2d822',
107+
'0x951c881cab59ed669915a2b04ea5721600794ec3',
108+
'0x30dd252c7c150f26a3a06e4eada9e706db3fa58c',
109+
'0x055bd801ca712b4ddf67db8bc23fb6c8510d52b9',
110+
'0xcdfc898128dbc380a60895c6e8c0975dc07d07e0',
111+
'0x1d25c827abd466387bda00b429fe728627d6eee6',
112+
'0x85517022e380408b698ea0ea379d2b69f907c199',
113+
'0x98c27cc3f0301b6272049dc3f972e2f542780629',
114+
'0x414b4b5a2a0e303b89360eda83598ab7702eae04',
115+
'0x72f93a2740e00112d5f2cef404c0aa16fae21fa4',
116+
'0xe87d858ca83ffc1e8372b57b2d4f8aaaf8156f19',
117+
'0x6a654ca3bfb5cfb23bf30bafbf96b3b6ec26bb0e',
118+
'0x160cdef60e786295728a6ea334c091238e474e01',
119+
'0x42eefcda06ead475cde3731b8eb138e88cd0bac3',
120+
'0x54fab55f18248690264769ef9c0b3c30b8344b8e',
121+
'0x43c7c14d94197a30a44dab27bfb3eee9e05496d4',
122+
'0xe05ae0e76f582817c9e31d9c1a5c02287a31d689',
123+
'0xe05ae0e76f582817c9e31d9c1a5c02287a31d689',
124+
'0x2c74ca71679cf1299936d6104d825c965448907b',
125+
'0x0306b7d3095ab008927166cd648a8ca7dbe53f05',
126+
'0x13dc53fa54e7d662ff305b6c3ef95090c31dc576',
127+
'0x1a578699956c2174b4762de95316b3ad09ba34e9',
128+
'0x48aff66a7a9ce3b8fc4f62c80604bc310edf94cd',
129+
'0xd93622443da1f3e81cde6e2c0e482b4d8084251a',
130+
'0x6b2ed7e4b12a544ca7d215fed85dc16240d64aea',
131+
'0x8cb120478e9503760656c1fcac9c1539158bdb55',
132+
'0xc74d21957b34e4b9bae50e436a2581bd81ed581d',
133+
'0x90b11143a0cb64e067402307bc7f2276dcec8250',
134+
'0xe296cf6511ab951e026c620fb0e266db4d6de4a0',
135+
'0xde8da1ee512529b6c61fe7c769affc160308dea2',
136+
'0x55cc129dad4df3771a37770c6c0a469ff51918c8',
137+
'0x0208652a93baf5f1962849efcf5795eac7439a5e',
138+
'0xb0695fe376b48a3f39040ebbb2192e919c6b8aba',
139+
'0x406c3fef5969b36231bd573adfc34e16f54d23e0',
140+
'0xef46d5fe753c988606e6f703260d816af53b03eb',
141+
'0x62fb676db64f87fd1602048106476c6036d44c92',
142+
'0x4df34fac8313dcd3442064b90e22129ad82b5103',
143+
'0x13a9d78f4712a65678d7735682819b4f4f74253c',
144+
'0x26c80cc193b27d73d2c40943acec77f4da2c5bd8',
145+
'0x62bc6a92f4a4d0f5b4e16967b88db2d9e196c9f9',
146+
'0x28247de2d9829f3080899749b92e34959c06b59c',
147+
'0xa5a2c0eef6ee3e4b0bf79e0c9378d101d3cbec13',
148+
'0x8bbf92f4da9be0478464a077f582abd7b6df193c',
149+
'0x91935751ba30494c4fd276adcf134ecd66f8eca6',
150+
'0xd56fbe3294ea4d73cca99ff8751ce7bd9b688cd5',
151+
'0xd48611f40a37623bbcf9f047b8538177d879bad0',
152+
'0x959a4d857b7071c38878beb9dc77051b5fed1dfd',
153+
'0x3a9df5dfcb4cc102ce20d40434a2b1baca9eafd3',
154+
'0xddc6f0e66a442632f6c4fbf9eacf363170ee2916',
155+
'0x168b2779146ba862b04ca146385645eddb9d592e',
156+
'0x2a998cc0bb43dc510e523fe33c8f1c04bf607a1e',
157+
'0x30523527aced0ed2f5ce1721086d1d282d3af38f',
158+
'0xb5cb4fdb37e9fe8d7b8f473268128dfb4f862f4f',
159+
'0x374c87b673409e13053dbd35ebe868be42beabc5',
160+
'0xea7755c8fca76e6c1ecba0c678c5694ad8a85292',
161+
'0x3aeb7722c208c8f35fef5ec4f2ebf887beb59360',
162+
'0x18f371aeee4e2636df789931c9cd43e5d7b72d66',
163+
'0x00b69ba135b496b7f17fdfcd50d48b86bb397be6',
164+
'0x77ee14d1a9ba7130b686b736a316b5bf1d3ccb36'
165+
]
166+
66167
const testTimeout = 120000
67168

68169
before('deploy Livepeer Tenderizer', async function () {
@@ -72,7 +173,7 @@ describe('Matic Mainnet Fork Test', () => {
72173
method: 'hardhat_reset',
73174
params: [{
74175
forking: {
75-
blockNumber: 12900000,
176+
blockNumber: 13222135,
76177
jsonRpcUrl: process.env.ALCHEMY_URL || 'https://eth-mainnet.alchemyapi.io/v2/s93KFT7TnttkCPdNS2Fg_HAoCpP6dEda'
77178
}
78179
}]
@@ -175,61 +276,118 @@ describe('Matic Mainnet Fork Test', () => {
175276
})
176277
})
177278

178-
// describe('rebase', () => {
179-
// describe('stake increased', () => {
180-
// let increase: BigNumber
181-
// let newStakeMinusFees: BigNumber
182-
// let newStake: BigNumber
183-
// const swappedLPTRewards = ethers.BigNumber.from('0') // TODO: Add test with ETH->LPT Swap
184-
// let totalShares: BigNumber = ethers.utils.parseEther('1')
185-
// const percDiv = ethers.utils.parseEther('1')
186-
187-
// before(async () => {
188-
// const rootChain = new ethers.Contract(rootChainAddr, rootChainAbi, ethers.provider)
189-
190-
191-
// // const stakeAfter = (await bondingManager.pendingStake(Tenderizer.address, currentRound))
192-
// increase = stakeAfter.sub(stakeBefore)
193-
// const liquidityFees = percOf2(increase.add(swappedLPTRewards), liquidityFeesPercent)
194-
// const protocolFees = percOf2(increase.add(swappedLPTRewards), protocolFeesPercent)
195-
// newStake = deposit.add(initialStake).add(increase)
196-
// newStakeMinusFees = newStake.add(swappedLPTRewards).sub(liquidityFees.add(protocolFees))
197-
// tx = await Controller.rebase()
198-
// })
199-
200-
// it('updates currentPrincipal', async () => {
201-
// expect(await Tenderizer.currentPrincipal()).to.eq(newStakeMinusFees)
202-
// })
203-
204-
// it('increases tendertoken balances when rewards are added', async () => {
205-
// // account 0
206-
// const shares = await TenderToken.sharesOf(deployer)
207-
// totalShares = await TenderToken.getTotalShares()
208-
// expect(await TenderToken.balanceOf(deployer)).to.eq(sharesToTokens(shares, totalShares, await TenderToken.totalSupply()))
209-
// })
210-
211-
// it('increases the tenderToken balance of the AMM', async () => {
212-
// const shares = await TenderToken.sharesOf(BPool.address)
213-
// expect(await TenderToken.balanceOf(BPool.address)).to.eq(sharesToTokens(shares, totalShares, await TenderToken.totalSupply()))
214-
// })
215-
216-
// it('changes the weights of the AMM', async () => {
217-
// const tBal = await TenderToken.balanceOf(BPool.address)
218-
// const bal = await MaticToken.balanceOf(BPool.address)
219-
220-
// const acceptableDelta = ethers.BigNumber.from('100')
221-
222-
// const expected = tBal.mul(percDiv).div(tBal.add(bal))
223-
// const actual = await BPool.getNormalizedWeight(TenderToken.address)
224-
// expect(actual.sub(expected).abs()).to.be.lte(acceptableDelta)
225-
// })
226-
227-
// it('should emit RewardsClaimed event from Tenderizer', async () => {
228-
// expect(tx).to.emit(Tenderizer, 'RewardsClaimed')
229-
// .withArgs(increase.add(swappedLPTRewards), newStakeMinusFees, deposit.add(initialStake))
230-
// })
231-
// })
232-
// })
279+
describe('rebase', () => {
280+
describe('stake increased', () => {
281+
let increase: BigNumber
282+
let newStakeMinusFees: BigNumber
283+
let newStake: BigNumber
284+
const swappedLPTRewards = ethers.BigNumber.from('0') // TODO: Add test with ETH->LPT Swap
285+
const totalShares: BigNumber = ethers.utils.parseEther('1')
286+
const percDiv = ethers.utils.parseEther('1')
287+
288+
before(async function () {
289+
this.timeout(testTimeout * 2)
290+
const sharesBefore = await MaticStaking.balanceOf(Tenderizer.address)
291+
let exRate = await MaticStaking.exchangeRate()
292+
const stakeBefore = sharesBefore.mul(exRate).div(EXCHAGE_RATE_PERCEISON)
293+
294+
const rootChain = new ethers.Contract(rootChainAddr, rootChainAbi, ethers.provider)
295+
// Impersonate ownner
296+
const signers = []
297+
await hre.network.provider.request({
298+
method: 'hardhat_impersonateAccount',
299+
params: [nodeSignerAddr]
300+
})
301+
const nodeOwner = await ethers.provider.getSigner(nodeSignerAddr)
302+
signers.push(nodeOwner)
303+
304+
// Impersonate other signers
305+
for (let i = 0; i < otherSignersAddr.length; i++) {
306+
await hre.network.provider.request({
307+
method: 'hardhat_impersonateAccount',
308+
params: [otherSignersAddr[i]]
309+
})
310+
signers.push(await ethers.provider.getSigner(otherSignersAddr[i]))
311+
}
312+
313+
// Get block data from root chain
314+
const childWeb3 = new ethers.providers.JsonRpcProvider(childChainURL)
315+
const lastChildBlock = (await rootChain.getLastChildBlock()).toNumber()
316+
// Get only 10 blocks from child chian
317+
const start = lastChildBlock + 1
318+
const end = lastChildBlock + 11
319+
const headers = []
320+
for (let i = start; i <= end; i++) {
321+
const block = await childWeb3.getBlock(i)
322+
block.number = i
323+
headers.push(getBlockHeader(block))
324+
}
325+
326+
const tree = new MerkleTree(headers)
327+
const root = ethUtils.bufferToHex(tree.getRoot())
328+
// Build data
329+
const { data, sigs } = await buildsubmitCheckpointPaylod(
330+
nodeSignerAddr,
331+
start,
332+
end,
333+
root,
334+
signers,
335+
{
336+
getSigs: true,
337+
allValidators: true,
338+
rewardsRootHash: ethers.constants.HashZero, // Changed from ''
339+
totalStake: 1,
340+
sigPrefix: ''
341+
}
342+
)
343+
// Submit block data
344+
await rootChain.connect(nodeOwner).submitCheckpoint(data, sigs)
345+
346+
const sharesAfter = await MaticStaking.balanceOf(Tenderizer.address)
347+
exRate = await MaticStaking.exchangeRate()
348+
const stakeAfter = sharesAfter.mul(exRate).div(EXCHAGE_RATE_PERCEISON)
349+
increase = stakeAfter.sub(stakeBefore)
350+
console.log(increase)
351+
const liquidityFees = percOf2(increase.add(swappedLPTRewards), liquidityFeesPercent)
352+
const protocolFees = percOf2(increase.add(swappedLPTRewards), protocolFeesPercent)
353+
newStake = deposit.add(initialStake).add(increase)
354+
newStakeMinusFees = newStake.add(swappedLPTRewards).sub(liquidityFees.add(protocolFees))
355+
tx = await Controller.rebase()
356+
})
357+
358+
it('updates currentPrincipal', async () => {
359+
expect(await Tenderizer.currentPrincipal()).to.eq(newStakeMinusFees)
360+
})
361+
362+
// it('increases tendertoken balances when rewards are added', async () => {
363+
// // account 0
364+
// const shares = await TenderToken.sharesOf(deployer)
365+
// totalShares = await TenderToken.getTotalShares()
366+
// expect(await TenderToken.balanceOf(deployer)).to.eq(sharesToTokens(shares, totalShares, await TenderToken.totalSupply()))
367+
// })
368+
369+
// it('increases the tenderToken balance of the AMM', async () => {
370+
// const shares = await TenderToken.sharesOf(BPool.address)
371+
// expect(await TenderToken.balanceOf(BPool.address)).to.eq(sharesToTokens(shares, totalShares, await TenderToken.totalSupply()))
372+
// })
373+
374+
// it('changes the weights of the AMM', async () => {
375+
// const tBal = await TenderToken.balanceOf(BPool.address)
376+
// const bal = await MaticToken.balanceOf(BPool.address)
377+
378+
// const acceptableDelta = ethers.BigNumber.from('100')
379+
380+
// const expected = tBal.mul(percDiv).div(tBal.add(bal))
381+
// const actual = await BPool.getNormalizedWeight(TenderToken.address)
382+
// expect(actual.sub(expected).abs()).to.be.lte(acceptableDelta)
383+
// })
384+
385+
// it('should emit RewardsClaimed event from Tenderizer', async () => {
386+
// expect(tx).to.emit(Tenderizer, 'RewardsClaimed')
387+
// .withArgs(increase.add(swappedLPTRewards), newStakeMinusFees, deposit.add(initialStake))
388+
// })
389+
})
390+
})
233391

234392
// describe('collect fees', () => {
235393
// let fees: BigNumber

test/util/helpers.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { ethers, BigNumber } from 'ethers'
2+
import { ConsoleLogger } from 'ts-generator/dist/logger'
23
import { PERC_DIVISOR } from './constants'
4+
const ethUtils = require('ethereumjs-util')
5+
const Buffer = require('safe-buffer').Buffer
6+
const BN = ethUtils.BN
37

48
export function sharesToTokens (shares: BigNumber, totalShares: BigNumber, totalTokens: BigNumber): BigNumber {
59
if (totalShares.eq(0)) {
@@ -26,3 +30,62 @@ export function percOf (amount: BigNumber, fracNum:BigNumber, fracDenom:BigNumbe
2630
export function percOf2 (amount:BigNumber, fracNum:BigNumber): BigNumber {
2731
return amount.mul(fracNum).div(PERC_DIVISOR)
2832
}
33+
34+
export async function getSigs (wallets: any, votedata: any) {
35+
// avoid any potential side effects
36+
const copyWallets = [...wallets]
37+
38+
copyWallets.sort((w1, w2) => {
39+
return w1._address.localeCompare(w2._address)
40+
})
41+
42+
const h = Buffer.from(votedata)
43+
44+
const signed = []
45+
for (let i = 0; i < copyWallets.length; i++) {
46+
signed.push(await copyWallets[i].provider.getSigner().signMessage(h))
47+
}
48+
return signed
49+
}
50+
51+
export async function encodeSigsForCheckpoint (sigs = []) {
52+
const encodedSigs = []
53+
for (let i = 0; i < sigs.length; i++) {
54+
const buffer = Buffer.from((sigs[i] as string).slice(2), 'hex')
55+
encodedSigs.push([
56+
ethers.BigNumber.from(buffer.slice(0, 32)),
57+
ethers.BigNumber.from(buffer.slice(32, 64)),
58+
ethers.BigNumber.from(buffer.slice(64, 96))
59+
])
60+
}
61+
return encodedSigs
62+
}
63+
64+
export async function buildsubmitCheckpointPaylod (
65+
proposer: string,
66+
start: number,
67+
end: number,
68+
root: any,
69+
wallets: any[],
70+
options = { rewardsRootHash: '', allValidators: false, getSigs: false, totalStake: 1, sigPrefix: '' } // false vars are to show expected vars
71+
) {
72+
const validators = wallets
73+
const abiCoder = new ethers.utils.AbiCoder()
74+
75+
const data = abiCoder.encode(
76+
['address', 'uint256', 'uint256', 'bytes32', 'bytes32', 'uint256'],
77+
[proposer, start, end, root, options.rewardsRootHash, 137]
78+
)
79+
const sigData = Buffer.concat([Buffer.from(options.sigPrefix || '0x01'), Buffer.from(data)])
80+
81+
const sigs = await encodeSigsForCheckpoint((await getSigs(validators, ethUtils.keccak256(sigData))) as any)
82+
return { data, sigs }
83+
}
84+
85+
export function getBlockHeader (block: any) {
86+
const n = new BN(block.number).toArrayLike(Buffer, 'be', 32)
87+
const ts = new BN(block.timestamp).toArrayLike(Buffer, 'be', 32)
88+
const txRoot = ethUtils.toBuffer(block.transactionsRoot)
89+
const receiptsRoot = ethUtils.toBuffer(block.receiptsRoot)
90+
return ethUtils.keccak256(Buffer.concat([n, ts, txRoot, receiptsRoot]))
91+
}

0 commit comments

Comments
 (0)