-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d52643d
commit f473fd4
Showing
2 changed files
with
200 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
import { | ||
ProxyFactory, | ||
ProxyFactory__factory, | ||
TestGovernanceERC20, | ||
TestGovernanceERC20__factory, | ||
} from '../../../typechain'; | ||
import {ProxyCreatedEvent} from '../../../typechain/src/utils/ProxyFactory'; | ||
import {findEvent} from '../../../utils/helpers'; | ||
import { | ||
ERC1967_IMPLEMENTATION_SLOT, | ||
OZ_INITIALIZED_SLOT_POSITION, | ||
readStorage, | ||
} from '../../../utils/storage'; | ||
import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; | ||
import {expect} from 'chai'; | ||
import {ethers} from 'hardhat'; | ||
|
||
const MOCK_ADDRESS = `0x${'0123456789'.repeat(4)}`; | ||
const DEFAULT_INITIALIZATION: [ | ||
string, | ||
string, | ||
string, | ||
{receivers: string[]; amounts: number[]} | ||
] = [ | ||
MOCK_ADDRESS, | ||
'GOV', | ||
'GOV', | ||
{ | ||
receivers: [], | ||
amounts: [], | ||
}, | ||
]; | ||
|
||
describe.only('ProxyFactory', function () { | ||
let deployer: SignerWithAddress; | ||
let proxyFactory: ProxyFactory; | ||
let logic: TestGovernanceERC20; | ||
|
||
before(async () => { | ||
deployer = (await ethers.getSigners())[0]; | ||
|
||
logic = await new TestGovernanceERC20__factory(deployer).deploy( | ||
...DEFAULT_INITIALIZATION | ||
); | ||
proxyFactory = await new ProxyFactory__factory(deployer).deploy( | ||
logic.address | ||
); | ||
}); | ||
|
||
describe('initialization', async () => { | ||
it('points to the right logic contract', async () => { | ||
expect(await proxyFactory.LOGIC()).to.equal(logic.address); | ||
}); | ||
}); | ||
|
||
describe('deployUUPSProxy', async () => { | ||
it('deploys the proxy unitialized if no data is provided', async () => { | ||
const initData: any = []; | ||
|
||
const tx = await proxyFactory.deployUUPSProxy(initData); | ||
const event = await findEvent<ProxyCreatedEvent>(tx, 'ProxyCreated'); | ||
if (!event) { | ||
throw new Error('Failed to get the event'); | ||
} | ||
|
||
const tokenProxy = TestGovernanceERC20__factory.connect( | ||
event.args.proxy, | ||
deployer | ||
); | ||
|
||
// Check that the proxy points to the right logic contract. | ||
expect( | ||
await readStorage(tokenProxy.address, ERC1967_IMPLEMENTATION_SLOT, [ | ||
'address', | ||
]) | ||
).to.equal(logic.address); | ||
|
||
// Check that the proxy is not initialized. | ||
expect( | ||
await readStorage(tokenProxy.address, OZ_INITIALIZED_SLOT_POSITION, [ | ||
'uint8', | ||
]) | ||
).to.equal(0); | ||
|
||
// Check that the DAO address is not set. | ||
expect(await tokenProxy.dao()).to.equal(ethers.constants.AddressZero); | ||
}); | ||
|
||
it('deploys the proxy initialized if data is provided', async () => { | ||
const initData = | ||
TestGovernanceERC20__factory.createInterface().encodeFunctionData( | ||
'initialize', | ||
DEFAULT_INITIALIZATION | ||
); | ||
|
||
const tx = await proxyFactory.deployUUPSProxy(initData); | ||
const event = await findEvent<ProxyCreatedEvent>(tx, 'ProxyCreated'); | ||
if (!event) { | ||
throw new Error('Failed to get the event'); | ||
} | ||
|
||
const tokenProxy = TestGovernanceERC20__factory.connect( | ||
event.args.proxy, | ||
deployer | ||
); | ||
|
||
// Check that the proxy points to the right logic contract. | ||
expect( | ||
await readStorage(tokenProxy.address, ERC1967_IMPLEMENTATION_SLOT, [ | ||
'address', | ||
]) | ||
).to.equal(logic.address); | ||
|
||
// Check that the proxy is initialized. | ||
expect( | ||
await readStorage(tokenProxy.address, OZ_INITIALIZED_SLOT_POSITION, [ | ||
'uint8', | ||
]) | ||
).to.equal(1); | ||
|
||
// Check that the DAO address is set. | ||
expect(await tokenProxy.dao()).to.equal(MOCK_ADDRESS); | ||
}); | ||
}); | ||
|
||
describe('deployMinimalProxy', async () => { | ||
it('deploys the proxy unitialized if no data is provided', async () => { | ||
const initData: any = []; | ||
|
||
const tx = await proxyFactory.deployMinimalProxy(initData); | ||
|
||
const event = await findEvent<ProxyCreatedEvent>(tx, 'ProxyCreated'); | ||
if (!event) { | ||
throw new Error('Failed to get the event'); | ||
} | ||
|
||
const tokenProxy = TestGovernanceERC20__factory.connect( | ||
event.args.proxy, | ||
deployer | ||
); | ||
|
||
// Check that the proxy is not initialized. | ||
expect( | ||
await readStorage(tokenProxy.address, OZ_INITIALIZED_SLOT_POSITION, [ | ||
'uint8', | ||
]) | ||
).to.equal(0); | ||
|
||
// Check that the DAO address is not set. | ||
expect(await tokenProxy.dao()).to.equal(ethers.constants.AddressZero); | ||
}); | ||
|
||
it('deploys the proxy initialized if data is provided', async () => { | ||
const initData = | ||
TestGovernanceERC20__factory.createInterface().encodeFunctionData( | ||
'initialize', | ||
DEFAULT_INITIALIZATION | ||
); | ||
|
||
const tx = await proxyFactory.deployMinimalProxy(initData); | ||
const event = await findEvent<ProxyCreatedEvent>(tx, 'ProxyCreated'); | ||
if (!event) { | ||
throw new Error('Failed to get the event'); | ||
} | ||
|
||
const tokenProxy = TestGovernanceERC20__factory.connect( | ||
event.args.proxy, | ||
deployer | ||
); | ||
|
||
// Check that the proxy is initialized. | ||
expect( | ||
await readStorage(tokenProxy.address, OZ_INITIALIZED_SLOT_POSITION, [ | ||
'uint8', | ||
]) | ||
).to.equal(1); | ||
|
||
// Check that the DAO address is set. | ||
expect(await tokenProxy.dao()).to.equal(MOCK_ADDRESS); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import {defaultAbiCoder} from 'ethers/lib/utils'; | ||
import {ethers} from 'hardhat'; | ||
|
||
// See https://eips.ethereum.org/EIPS/eip-1967 | ||
export const ERC1967_IMPLEMENTATION_SLOT = | ||
'0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc'; // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1) | ||
|
||
export const OZ_INITIALIZED_SLOT_POSITION = 0; | ||
|
||
export async function readStorage( | ||
contractAddress: string, | ||
location: number | string, | ||
types: string[] | ||
): Promise<string> { | ||
return await ethers.provider | ||
.getStorageAt(contractAddress, location) | ||
.then(encoded => defaultAbiCoder.decode(types, encoded)[0]); | ||
} |