Skip to content

Commit

Permalink
Remove hardhat imports from exported library code (gnosis/gp-v2-contr…
Browse files Browse the repository at this point in the history
…acts#507)

Fixes part of #506

This PR removes the `import "hardhat*"` statements from the TypeScript library code, as its a `devDependency`, and as such not available to dependent pacakges.

### Test Plan

Release `alpha.13` and see if it resolves the issues. We may need to also switch the `target` library in the TS config, but I'm hopeful that we won't have to.
  • Loading branch information
nlordell authored Mar 11, 2021
1 parent 467b35c commit 520a561
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 20 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gnosis.pm/gp-v2-contracts",
"version": "0.0.1-alpha.12",
"version": "0.0.1-alpha.13",
"license": "LGPL-3.0-or-later",
"scripts": {
"build": "tsc && hardhat compile",
Expand Down
50 changes: 35 additions & 15 deletions src/ts/proxy.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
// defined in https://eips.ethereum.org/EIPS/eip-1967
import { BigNumber, BytesLike, Contract, ethers } from "ethers";

import { BigNumber, Contract } from "ethers";
import { ethers } from "hardhat";
import Proxy from "hardhat-deploy/extendedArtifacts/EIP173Proxy.json";

// The proxy contract used by hardhat-deploy implements EIP-1967 (Standard Proxy
// Storage Slot). See <https://eips.ethereum.org/EIPS/eip-1967>.
function slot(string: string) {
/**
* Compute an EIP-1967 slot for the specified name. The proxy contract used by
* `hardhat-deploy` implements EIP-1967 (Standard Proxy Storage Slot).
*
* <https://eips.ethereum.org/EIPS/eip-1967>.
*/
function slot(name: string): BytesLike {
return ethers.utils.defaultAbiCoder.encode(
["bytes32"],
[BigNumber.from(ethers.utils.id(string)).sub(1)],
[BigNumber.from(ethers.utils.id(name)).sub(1)],
);
}

const IMPLEMENTATION_STORAGE_SLOT = slot("eip1967.proxy.implementation");
const OWNER_STORAGE_SLOT = slot("eip1967.proxy.admin");

Expand All @@ -22,10 +23,13 @@ const OWNER_STORAGE_SLOT = slot("eip1967.proxy.admin");
* @param proxy Address of the proxy contract.
* @returns The address of the contract storing the proxy implementation.
*/
export async function implementationAddress(proxy: string): Promise<string> {
export async function implementationAddress(
provider: ethers.providers.Provider,
proxy: string,
): Promise<string> {
const [implementation] = ethers.utils.defaultAbiCoder.decode(
["address"],
await ethers.provider.getStorageAt(proxy, IMPLEMENTATION_STORAGE_SLOT),
await provider.getStorageAt(proxy, IMPLEMENTATION_STORAGE_SLOT),
);
return implementation;
}
Expand All @@ -37,25 +41,41 @@ export async function implementationAddress(proxy: string): Promise<string> {
* @param proxy Address of the proxy contract.
* @returns The address of the administrator of the proxy.
*/
export async function ownerAddress(proxy: string): Promise<string> {
export async function ownerAddress(
provider: ethers.providers.Provider,
proxy: string,
): Promise<string> {
const [owner] = ethers.utils.defaultAbiCoder.decode(
["address"],
await ethers.provider.getStorageAt(proxy, OWNER_STORAGE_SLOT),
await provider.getStorageAt(proxy, OWNER_STORAGE_SLOT),
);
return owner;
}

/**
* EIP-173 proxy ABI in "human-readable ABI" format. The proxy used by the
* deployment plugin implements this interface, and copying it here avoids
* pulling in `hardhat` as a dependency for just this ABI.
*
* <https://eips.ethereum.org/EIPS/eip-173#specification>
*/
export const EIP173_PROXY_ABI = [
"event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)",
"function owner() view external returns(address)",
"function transferOwnership(address newOwner) external",
"function supportsInterface(bytes4 interfaceID) external view returns (bool)",
];

/**
* Returns the proxy interface for the specified address.
*
* @param contract The proxy contract to return a proxy interface for.
* @returns A Ethers.js contract instance for interacting with the proxy.
*/
export function proxyInterface(contract: Contract): Contract {
const { abi } = Proxy;
return new Contract(
contract.address,
abi,
EIP173_PROXY_ABI,
contract.signer ?? contract.provider,
);
}
8 changes: 4 additions & 4 deletions test/e2e/deployment.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect } from "chai";
import { Contract, Wallet } from "ethers";
import { artifacts } from "hardhat";
import { artifacts, ethers } from "hardhat";
import Proxy from "hardhat-deploy/extendedArtifacts/EIP173Proxy.json";

import {
Expand Down Expand Up @@ -50,7 +50,7 @@ describe("E2E: Deployment", () => {
it("authenticator", async () => {
expect(
await builtAndDeployedMetadataCoincide(
await implementationAddress(authenticator.address),
await implementationAddress(ethers.provider, authenticator.address),
"GPv2AllowListAuthentication",
),
).to.be.true;
Expand Down Expand Up @@ -80,7 +80,7 @@ describe("E2E: Deployment", () => {
it("proxy", async () => {
expect(
deterministicDeploymentAddress(Proxy, [
await implementationAddress(authenticator.address),
await implementationAddress(ethers.provider, authenticator.address),
authenticator.interface.encodeFunctionData("initializeManager", [
manager.address,
]),
Expand All @@ -91,7 +91,7 @@ describe("E2E: Deployment", () => {

it("implementation", async () => {
expect(await contractAddress("GPv2AllowListAuthentication")).to.equal(
await implementationAddress(authenticator.address),
await implementationAddress(ethers.provider, authenticator.address),
);
});
});
Expand Down

0 comments on commit 520a561

Please sign in to comment.