Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always deploy with governor as admin and transfer ownership after #173

Merged
merged 5 commits into from
Aug 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { HardhatUserConfig } from 'hardhat/types';
import { HARDHAT_ACCOUNTS } from './hardhatAccounts.js';
import 'hardhat-artifactor';
import 'hardhat-gas-reporter'
import '@typechain/hardhat';
Expand All @@ -25,6 +26,11 @@ subtask('typechain-generate-types',

const config: HardhatUserConfig = {
defaultNetwork: 'hardhat',
networks: {
'hardhat': {
accounts: HARDHAT_ACCOUNTS,
}
},
solidity: {
compilers: [{
version: '0.8.5',
Expand Down
48 changes: 48 additions & 0 deletions hardhatAccounts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
exports.HARDHAT_PK_0 = '0000000000000000000000000000000000000000000000000000000000000010';


exports.HARDHAT_PK_1 = '0000000000000000000000000000000000000000000000000000000000000001';
exports.HARDHAT_PK_2 = '0000000000000000000000000000000000000000000000000000000000000002';

exports.HARDHAT_ACCOUNTS = [
{
privateKey: '0000000000000000000000000000000000000000000000000000000000000010',
balance: '1000000000000000000000',
},
{
privateKey: '0000000000000000000000000000000000000000000000000000000000000001',
balance: '1000000000000000000000',
},
{
privateKey: '0000000000000000000000000000000000000000000000000000000000000002',
balance: '1000000000000000000000',
},
{
privateKey: '0000000000000000000000000000000000000000000000000000000000000003',
balance: '1000000000000000000000',
},
{
privateKey: '0000000000000000000000000000000000000000000000000000000000000004',
balance: '1000000000000000000000',
},
{
privateKey: '0000000000000000000000000000000000000000000000000000000000000005',
balance: '1000000000000000000000',
},
{
privateKey: '0000000000000000000000000000000000000000000000000000000000000006',
balance: '1000000000000000000000',
},
{
privateKey: '0000000000000000000000000000000000000000000000000000000000000007',
balance: '1000000000000000000000',
},
{
privateKey: '0000000000000000000000000000000000000000000000000000000000000008',
balance: '1000000000000000000000',
},
{
privateKey: '0000000000000000000000000000000000000000000000000000000000000009',
balance: '1000000000000000000000',
},
];
11 changes: 8 additions & 3 deletions packages/bridges/src/SignatureBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export class SignatureBridge {
const initialGovernor = initialGovernors[chainID];

// Create the bridgeSide
const bridgeInstance = await SignatureBridgeSide.createBridgeSide(initialGovernor, deployers[chainID]);
const bridgeInstance = await SignatureBridgeSide.createBridgeSide(deployers[chainID]);

const handler = await AnchorHandler.createAnchorHandler(
bridgeInstance.contract.address,
Expand All @@ -129,8 +129,6 @@ export class SignatureBridge {
);
await bridgeInstance.setAnchorHandler(handler);

bridgeSides.set(chainID, bridgeInstance);

// Create Treasury and TreasuryHandler
const treasuryHandler = await TreasuryHandler.createTreasuryHandler(
bridgeInstance.contract.address,
Expand Down Expand Up @@ -216,8 +214,15 @@ export class SignatureBridge {
chainGroupedAnchors.push(anchorInstance);
anchors.set(SignatureBridge.createAnchorIdString({ anchorSize, chainId: chainID }), anchorInstance);
}

// Transfer ownership of the bridge to the initialGovernor
const tx = await bridgeInstance.transferOwnership(initialGovernor, 0);
await tx.wait();

await SignatureBridge.setPermissions(bridgeInstance, chainGroupedAnchors);
createdAnchors.push(chainGroupedAnchors);

bridgeSides.set(chainID, bridgeInstance);
}

// All anchors created, massage data to group anchors which should be linked together
Expand Down
92 changes: 58 additions & 34 deletions packages/bridges/src/SignatureBridgeSide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { IAnchor, IBridgeSide, Proposal } from '@webb-tools/interfaces';
import { TreasuryHandler } from '@webb-tools/tokens';
import { getChainIdType } from '@webb-tools/utils';
import { signMessage, toHex } from '@webb-tools/sdk-core';
import EC from 'elliptic';
const ec = new EC.ec('secp256k1');

type SystemSigningFn = (data: any) => Promise<string>;

export class SignatureBridgeSide implements IBridgeSide {
contract: SignatureBridge;
Expand All @@ -18,60 +18,84 @@ export class SignatureBridgeSide implements IBridgeSide {
tokenHandler: TokenWrapperHandler;
treasuryHandler: TreasuryHandler;
proposals: Proposal[];
signingSystemSignFn: (data: any) => Promise<string>;
signingSystemSignFn: SystemSigningFn;

ANCHOR_HANDLER_MISSING_ERROR = new Error('Cannot connect an anchor without a handler');
TOKEN_HANDLER_MISSING_ERROR = new Error('Cannot connect to a token wrapper without a handler');
TREASURY_HANDLER_MISSING_ERROR = new Error('Cannot connect to treasury without handler');

private constructor(
contract: SignatureBridge,
governor: ethers.Wallet | string,
signer: ethers.Signer,
signingSystemSignFn?: (data: any) => Promise<string>
systemSigningFn: SystemSigningFn,
) {
this.contract = contract;
this.admin = signer;
this.governor = governor;
this.anchorHandler = null;
this.tokenHandler = null;
this.treasuryHandler = null;
this.proposals = [];
if (signingSystemSignFn) {
// The signing system here is an asynchronous function that
// potentially dispatches a message for a signature and waits
// to receive it. It is potentially a long-running process.
this.signingSystemSignFn = signingSystemSignFn;
} else {
if (typeof governor === 'string') {
throw new Error('Cannot sign with signing system without a governor wallet');
}

this.signingSystemSignFn = (data: any) => {
return Promise.resolve(signMessage(governor, data));
};
}

this.signingSystemSignFn = systemSigningFn
}

/**
* When a bridgeSide is created, the admin is set as the governor.
* Ownership of the bridge can then be transferred to another entity.
*
* @param admin - The deployer and governor upon creation.
*/
public static async createBridgeSide(
initialGovernor: ethers.Wallet | string,
admin: ethers.Signer,
signingSystemSignFn?: (data: any) => Promise<string>
admin: ethers.Wallet
): Promise<SignatureBridgeSide> {
const bridgeFactory = new SignatureBridge__factory(admin);
const deployedBridge = (typeof initialGovernor === 'string')
? await bridgeFactory.deploy(initialGovernor, 0)
: await bridgeFactory.deploy(initialGovernor.address, 0);
const deployedBridge = await bridgeFactory.deploy(admin.address, 0);
await deployedBridge.deployed();
const bridgeSide = (typeof initialGovernor === 'string')
? new SignatureBridgeSide(deployedBridge, initialGovernor, admin, signingSystemSignFn)
: new SignatureBridgeSide(deployedBridge, initialGovernor, admin, signingSystemSignFn);
const bridgeSide = new SignatureBridgeSide(deployedBridge, (data: any) => {
return Promise.resolve(signMessage(admin,data));
});
bridgeSide.admin = admin;
bridgeSide.governor = admin;
return bridgeSide;
}

public static async connect(address: string, governor: ethers.Wallet, admin: ethers.Wallet) {
const deployedBridge = SignatureBridge__factory.connect(address, admin);
const bridgeSide = new SignatureBridgeSide(deployedBridge, governor, admin);
/**
* When an existing SignatureBridge is connected, the governor must be configured.
* In the case of connectMocked, a wallet address is passed which will act as the governor.
*
* connectMocked is particularly useful for integration testing
*
* @param contractAddress - The contract address of the SignatureBridge contract instance.
* @param mockedGovernor - The ethers.Wallet which will sign messages before execution on the bridgeSide.
*/
public static async connectMocked(contractAddress: string, mockedGovernor: ethers.Wallet) {
const deployedBridge = SignatureBridge__factory.connect(contractAddress, mockedGovernor);
const bridgeSide = new SignatureBridgeSide(deployedBridge, (data: string) => {
return Promise.resolve(signMessage(mockedGovernor,data));
});
bridgeSide.governor = mockedGovernor;
bridgeSide.admin = mockedGovernor;
return bridgeSide;
}

/**
* When an existing SignatureBridge is connected, the governor must be configured.
* In the case of connectGovernor, a network is passed for querying the chain as well
* as a signing function which can keep this class generic.
*
* connectGovernor is necessary for interacting with this class when the private key
* of the governor is unavailable, but signed proposals are available.
*
* @param contractAddress - The contract address of the SignatureBridge contract instance.
* @param provider - The network which the contract address exists upon.
* @param systemSigningFn - a function which will produce a signature that verifies as
* coming from the configured governor on chain.
*/
public static async connectGovernor(
contractAddress: string,
provider: ethers.providers.Provider,
systemSigningFn: SystemSigningFn
) {
const deployedBridge = SignatureBridge__factory.connect(contractAddress, provider);
const bridgeSide = new SignatureBridgeSide(deployedBridge, systemSigningFn);
return bridgeSide;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/interfaces/src/bridge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { IAnchor } from '..';
import { IBridgeSide } from '../IBridgeSide';

// Deployer config matches the chainId to the signer for that chain
export type DeployerConfig = Record<number, ethers.Signer>;
export type DeployerConfig = Record<number, ethers.Wallet>;

// Initial Governor config the chainId to the initial governor for that chain
export type GovernorConfig = Record<number, ethers.Wallet>;
export type GovernorConfig = Record<number, string>;

export type AnchorIdentifier = {
anchorSize?: ethers.BigNumberish;
Expand Down
17 changes: 12 additions & 5 deletions packages/vbridge/src/VBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,15 @@ export class VBridge {
return linkedVAnchorMap;
}

// Deployments of all contracts for the bridge will be done with the DeployerConfig.
// After deployments, the wallet in the DeployerConfig will transfer ownership
// to the initialGovernor
public static async deployVariableAnchorBridge(
vBridgeInput: VBridgeInput,
deployers: DeployerConfig,
initialGovernors: GovernorConfig,
smallCircuitZkComponents: ZkComponents,
largeCircuitZkComponents: ZkComponents
largeCircuitZkComponents: ZkComponents,
): Promise<VBridge> {
let webbTokenAddresses: Map<number, string> = new Map();
let vBridgeSides: Map<number, SignatureBridgeSide> = new Map();
Expand All @@ -125,7 +128,7 @@ export class VBridge {
for (let chainID of vBridgeInput.chainIDs) {
const initialGovernor = initialGovernors[chainID];
// Create the bridgeSide
let vBridgeInstance = await SignatureBridgeSide.createBridgeSide(initialGovernor, deployers[chainID]);
let vBridgeInstance = await SignatureBridgeSide.createBridgeSide(deployers[chainID]);

const handler = await AnchorHandler.createAnchorHandler(
vBridgeInstance.contract.address,
Expand All @@ -135,8 +138,6 @@ export class VBridge {
);
vBridgeInstance.setAnchorHandler(handler);

vBridgeSides.set(chainID, vBridgeInstance);

// Create Treasury and TreasuryHandler
const treasuryHandler = await TreasuryHandler.createTreasuryHandler(
vBridgeInstance.contract.address,
Expand Down Expand Up @@ -226,6 +227,11 @@ export class VBridge {

await VBridge.setPermissions(vBridgeInstance, chainGroupedVAnchors);
createdVAnchors.push(chainGroupedVAnchors);

// Transfer ownership of the bridge to the initialGovernor
const tx = await vBridgeInstance.transferOwnership(initialGovernor, 0);
await tx.wait();
vBridgeSides.set(chainID, vBridgeInstance);
}

// All anchors created, massage data to group anchors which should be linked together
Expand All @@ -240,8 +246,9 @@ export class VBridge {
groupLinkedVAnchors.push(linkedAnchors);
}

// finally, link the anchors
// link the anchors
const linkedVAnchorMap = await VBridge.createLinkedVAnchorMap(groupLinkedVAnchors);

return new VBridge(vBridgeSides, webbTokenAddresses, linkedVAnchorMap, vAnchors);
}

Expand Down
Loading