Update optics-provider with governance capabilities (#21)

* Update optics-provider with governance capabilities

* Update mainnet domains

* Update staging community domains

* Update staging community domains

* update mainnet domains

* Update staging domain

* Add domain update scripts

* Re-add pagination

* address comments
pull/29/head
Asa Oines 3 years ago committed by GitHub
parent 632cc53ee1
commit d63e38123d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      typescript/optics-deploy/scripts/mainnet-community/update-optics-provider.ts
  2. 14
      typescript/optics-deploy/scripts/mainnet/update-optics-provider.ts
  3. 16
      typescript/optics-deploy/scripts/staging-community/update-optics-provider.ts
  4. 14
      typescript/optics-deploy/scripts/staging/update-optics-provider.ts
  5. 2
      typescript/optics-deploy/src/provider.ts
  6. 1468
      typescript/optics-provider/package-lock.json
  7. 3
      typescript/optics-provider/package.json
  8. 32
      typescript/optics-provider/src/optics/OpticsContext.ts
  9. 121
      typescript/optics-provider/src/optics/contracts/CoreContracts.ts
  10. 10
      typescript/optics-provider/src/optics/domains/devCommunity.ts
  11. 2
      typescript/optics-provider/src/optics/domains/domain.ts
  12. 30
      typescript/optics-provider/src/optics/domains/mainnet.ts
  13. 102
      typescript/optics-provider/src/optics/domains/mainnetCommunity.ts
  14. 33
      typescript/optics-provider/src/optics/domains/staging.ts
  15. 70
      typescript/optics-provider/src/optics/domains/stagingCommunity.ts
  16. 105
      typescript/optics-provider/src/optics/govern/index.ts
  17. 49
      typescript/optics-provider/src/optics/govern/utils.ts
  18. 10
      typescript/optics-provider/src/provider.ts
  19. 1
      typescript/optics-provider/src/utils.ts
  20. 1
      typescript/optics-provider/tsconfig.json

@ -0,0 +1,16 @@
import * as celo from '../../config/mainnets/celo';
import * as ethereum from '../../config/mainnets/ethereum';
import * as avalanche from '../../config/mainnets/avalanche';
import * as polygon from '../../config/mainnets/polygon';
import { updateProviderDomain } from '../../src/provider';
import { makeAllConfigs } from '../../src/config';
const configPath = '../../rust/config/production-community';
updateProviderDomain('mainnetCommunity', configPath, [
makeAllConfigs(celo, (_) => _.config),
makeAllConfigs(ethereum, (_) => _.config),
makeAllConfigs(avalanche, (_) => _.config),
makeAllConfigs(polygon, (_) => _.config),
]);

@ -0,0 +1,14 @@
import * as celo from '../../config/mainnets/celo';
import * as ethereum from '../../config/mainnets/ethereum';
import * as polygon from '../../config/mainnets/polygon';
import { updateProviderDomain } from '../../src/provider';
import { makeAllConfigs } from '../../src/config';
const configPath = '../../rust/config/mainnet';
updateProviderDomain('mainnet', configPath, [
makeAllConfigs(ethereum, (_) => _.config),
makeAllConfigs(polygon, (_) => _.config),
makeAllConfigs(celo, (_) => _.config),
]);

@ -0,0 +1,16 @@
import * as alfajores from '../../config/testnets/alfajores';
import * as kovan from '../../config/testnets/kovan';
import * as gorli from '../../config/testnets/gorli';
import * as ropsten from '../../config/testnets/ropsten';
import { updateProviderDomain } from '../../src/provider';
import { makeAllConfigs } from '../../src/config';
const configPath = '../../rust/config/staging-community';
updateProviderDomain('stagingCommunity', configPath, [
makeAllConfigs(alfajores, (_) => _.devConfig),
makeAllConfigs(ropsten, (_) => _.devConfig),
makeAllConfigs(kovan, (_) => _.devConfig),
makeAllConfigs(gorli, (_) => _.devConfig),
]);

@ -0,0 +1,14 @@
import * as alfajores from '../../config/testnets/alfajores';
import * as kovan from '../../config/testnets/kovan';
import * as rinkeby from '../../config/testnets/rinkeby';
import { updateProviderDomain } from '../../src/provider';
import { makeAllConfigs } from '../../src/config';
const configPath = '../../rust/config/staging';
updateProviderDomain('staging', configPath, [
makeAllConfigs(alfajores, (_) => _.devConfig),
makeAllConfigs(kovan, (_) => _.devConfig),
makeAllConfigs(rinkeby, (_) => _.devConfig),
]);

@ -27,6 +27,8 @@ export const ${config.chain.name}: OpticsDomain = {
id: ${config.chain.domain}, id: ${config.chain.domain},
bridgeRouter: '${bridgeDeploy.contracts.bridgeRouter!.proxy.address}',${!!bridgeDeploy.contracts.ethHelper ? `\n ethHelper: '${bridgeDeploy.contracts.ethHelper?.address}',` : ''} bridgeRouter: '${bridgeDeploy.contracts.bridgeRouter!.proxy.address}',${!!bridgeDeploy.contracts.ethHelper ? `\n ethHelper: '${bridgeDeploy.contracts.ethHelper?.address}',` : ''}
home: '${coreDeploy.contracts.home!.proxy.address}', home: '${coreDeploy.contracts.home!.proxy.address}',
governanceRouter: '${coreDeploy.contracts.governance!.proxy.address}',
xAppConnectionManager: '${coreDeploy.contracts.xAppConnectionManager!.address}',
replicas: [ replicas: [
${Object.keys(coreDeploy.contracts.replicas) ${Object.keys(coreDeploy.contracts.replicas)
.map(Number) .map(Number)

File diff suppressed because it is too large Load Diff

@ -27,6 +27,7 @@
}, },
"dependencies": { "dependencies": {
"@optics-xyz/ts-interface": "^1.1.0", "@optics-xyz/ts-interface": "^1.1.0",
"ethers": "^5.4.6" "celo-ethers-provider": "0.0.0",
"ethers": "^5.4.7"
} }
} }

@ -33,6 +33,7 @@ type Address = string;
export class OpticsContext extends MultiProvider { export class OpticsContext extends MultiProvider {
private cores: Map<number, CoreContracts>; private cores: Map<number, CoreContracts>;
private bridges: Map<number, BridgeContracts>; private bridges: Map<number, BridgeContracts>;
private _governorDomain?: number;
constructor( constructor(
domains: OpticsDomain[], domains: OpticsDomain[],
@ -199,8 +200,7 @@ export class OpticsContext extends MultiProvider {
home: string | number, home: string | number,
remote: string | number, remote: string | number,
): core.Replica | undefined { ): core.Replica | undefined {
return this.getCore(remote)?.replicas.get(this.resolveDomain(home)) return this.getCore(remote)?.getReplica(this.resolveDomain(home));
?.contract;
} }
/** /**
@ -225,6 +225,34 @@ export class OpticsContext extends MultiProvider {
return replica; return replica;
} }
/**
* Discovers the governor domain of this optics deployment and caches it.
*
* @returns The identifier of the governing domain
*/
async governorDomain(): Promise<number> {
if (this._governorDomain) {
return this._governorDomain;
}
const core: CoreContracts = this.cores.values().next().value;
if (!core) throw new Error('empty core map');
const governorDomain = await core.governanceRouter.governorDomain();
this._governorDomain = governorDomain !== 0 ? governorDomain : core.domain;
return this._governorDomain;
}
/**
* Discovers the governor domain of this optics deployment and returns the
* associated Core.
*
* @returns The identifier of the governing domain
*/
async governorCore(): Promise<CoreContracts> {
return this.mustGetCore(await this.governorDomain());
}
/** /**
* Resolve the local representation of a token on some domain. E.g. find the * Resolve the local representation of a token on some domain. E.g. find the
* deployed Celo address of Ethereum's Sushi Token. * deployed Celo address of Ethereum's Sushi Token.

@ -2,74 +2,133 @@ import { ethers } from 'ethers';
import { core } from '@optics-xyz/ts-interface'; import { core } from '@optics-xyz/ts-interface';
import { Contracts } from '../../contracts'; import { Contracts } from '../../contracts';
import { ReplicaInfo } from '../domains/domain'; import { ReplicaInfo } from '../domains/domain';
import { CallBatch } from '../govern';
type Address = string; type Address = string;
type InternalReplica = {
domain: number;
contract: core.Replica;
};
interface Core { interface Core {
id: number; id: number;
home: Address; home: Address;
replicas: ReplicaInfo[]; replicas: ReplicaInfo[];
governanceRouter: Address;
xAppConnectionManager: Address;
} }
export type Governor = {
local: boolean;
domain: number;
identifier: string;
};
export class CoreContracts extends Contracts { export class CoreContracts extends Contracts {
readonly domain; readonly domain: number;
home: core.Home; readonly _home: Address;
replicas: Map<number, InternalReplica>; readonly _replicas: Map<number, ReplicaInfo>;
readonly _governanceRouter: Address;
readonly _xAppConnectionManager: Address;
private providerOrSigner?: ethers.providers.Provider | ethers.Signer;
private _governor?: Governor;
constructor( constructor(
domain: number, domain: number,
home: Address, home: Address,
replicas: ReplicaInfo[], replicas: ReplicaInfo[],
signer?: ethers.Signer, governanceRouter: Address,
xAppConnectionManager: Address,
providerOrSigner?: ethers.providers.Provider | ethers.Signer,
) { ) {
super(domain, home, replicas, signer); super(domain, home, replicas, providerOrSigner);
this.providerOrSigner = providerOrSigner;
this.domain = domain; this.domain = domain;
this.home = new core.Home__factory(signer).attach(home); this._home = home;
this._governanceRouter = governanceRouter;
this._xAppConnectionManager = xAppConnectionManager;
this.replicas = new Map(); this._replicas = new Map();
replicas.forEach((replica) => { replicas.forEach((replica) => {
this.replicas.set(replica.domain, { this._replicas.set(replica.domain, {
contract: new core.Replica__factory(signer).attach(replica.address), address: replica.address,
domain: replica.domain, domain: replica.domain,
}); });
}); });
} }
connect(providerOrSigner: ethers.providers.Provider | ethers.Signer): void { getReplica(domain: number): core.Replica | undefined {
this.home = this.home.connect(providerOrSigner); if (!this.providerOrSigner) {
throw new Error('No provider or signer. Call `connect` first.');
}
const replica = this._replicas.get(domain);
if (!replica) return;
return core.Replica__factory.connect(
replica.address,
this.providerOrSigner,
);
}
Array.from(this.replicas.values()).forEach((replica: InternalReplica) => { get home(): core.Home {
replica.contract = replica.contract.connect(providerOrSigner); if (!this.providerOrSigner) {
}); throw new Error('No provider or signer. Call `connect` first.');
}
return core.Home__factory.connect(this._home, this.providerOrSigner);
} }
toObject(): Core { get governanceRouter(): core.GovernanceRouter {
const replicas: ReplicaInfo[] = Array.from(this.replicas.values()).map( if (!this.providerOrSigner) {
(replica) => { throw new Error('No provider or signer. Call `connect` first.');
return { }
domain: replica.domain, return core.GovernanceRouter__factory.connect(
address: replica.contract.address, this._governanceRouter,
}; this.providerOrSigner,
}, );
}
get xAppConnectionManager(): core.XAppConnectionManager {
if (!this.providerOrSigner) {
throw new Error('No provider or signer. Call `connect` first.');
}
return core.XAppConnectionManager__factory.connect(
this._xAppConnectionManager,
this.providerOrSigner,
); );
}
async governor(): Promise<Governor> {
if (this._governor) {
return this._governor;
}
const [domain, identifier] = await Promise.all([
this.governanceRouter.governorDomain(),
this.governanceRouter.governor(),
]);
const local = identifier !== ethers.constants.AddressZero;
this._governor = { local, domain, identifier };
return this._governor;
}
async newGovernanceBatch(): Promise<CallBatch> {
return CallBatch.fromCore(this);
}
connect(providerOrSigner: ethers.providers.Provider | ethers.Signer): void {
this.providerOrSigner = providerOrSigner;
}
toObject(): Core {
const replicas: ReplicaInfo[] = Array.from(this._replicas.values());
return { return {
id: this.domain, id: this.domain,
home: this.home.address, home: this._home,
replicas: replicas, replicas: replicas,
governanceRouter: this._governanceRouter,
xAppConnectionManager: this._xAppConnectionManager,
}; };
} }
static fromObject(data: Core, signer?: ethers.Signer): CoreContracts { static fromObject(data: Core, signer?: ethers.Signer): CoreContracts {
const { id, home, replicas } = data; const { id, home, replicas, governanceRouter, xAppConnectionManager } = data;
if (!id || !home || !replicas) { if (!id || !home || !replicas || !governanceRouter || !xAppConnectionManager) {
throw new Error('Missing key'); throw new Error('Missing key');
} }
return new CoreContracts(id, home, replicas, signer); return new CoreContracts(id, home, replicas, governanceRouter, xAppConnectionManager, signer);
} }
} }

@ -11,6 +11,8 @@ export const alfajores: OpticsDomain = {
{ domain: 43113, address: '0x570EDeF0c271E3f1ba6B5C66D040195750a79762' }, { domain: 43113, address: '0x570EDeF0c271E3f1ba6B5C66D040195750a79762' },
{ domain: 80001, address: '0xbA00eF80A55d4EefcF3d7971270D2c233F9d315e' }, { domain: 80001, address: '0xbA00eF80A55d4EefcF3d7971270D2c233F9d315e' },
], ],
governanceRouter: '0xBF79333049D140fCa12355f1F896c8ebedAf8707',
xAppConnectionManager: '0x2d230eB17F3AFe032809EC13A0E516E297b17AA3',
}; };
export const kovan: OpticsDomain = { export const kovan: OpticsDomain = {
@ -25,6 +27,8 @@ export const kovan: OpticsDomain = {
{ domain: 43113, address: '0xf3855B99b7cEfa56C66f0C2d0550b545df11d54A' }, { domain: 43113, address: '0xf3855B99b7cEfa56C66f0C2d0550b545df11d54A' },
{ domain: 80001, address: '0xeAc82476aF67dca63B04a66EA8D7230EfB4028DB' }, { domain: 80001, address: '0xeAc82476aF67dca63B04a66EA8D7230EfB4028DB' },
], ],
governanceRouter: '0x11E94700D9E5Ab1F8Bd0b3bd13e331CEFe3acEB7',
xAppConnectionManager: '0xf9db87020527A5A5aeFd95099051Fb14058916C9',
}; };
export const gorli: OpticsDomain = { export const gorli: OpticsDomain = {
@ -39,6 +43,8 @@ export const gorli: OpticsDomain = {
{ domain: 43113, address: '0xf3855B99b7cEfa56C66f0C2d0550b545df11d54A' }, { domain: 43113, address: '0xf3855B99b7cEfa56C66f0C2d0550b545df11d54A' },
{ domain: 80001, address: '0xeAc82476aF67dca63B04a66EA8D7230EfB4028DB' }, { domain: 80001, address: '0xeAc82476aF67dca63B04a66EA8D7230EfB4028DB' },
], ],
governanceRouter: '0x11E94700D9E5Ab1F8Bd0b3bd13e331CEFe3acEB7',
xAppConnectionManager: '0xf9db87020527A5A5aeFd95099051Fb14058916C9',
}; };
export const fuji: OpticsDomain = { export const fuji: OpticsDomain = {
@ -53,6 +59,8 @@ export const fuji: OpticsDomain = {
{ domain: 3000, address: '0xc501ad2163Ebd9921B4a6E46B344Ef7bA76A2cBa' }, { domain: 3000, address: '0xc501ad2163Ebd9921B4a6E46B344Ef7bA76A2cBa' },
{ domain: 80001, address: '0xeAc82476aF67dca63B04a66EA8D7230EfB4028DB' }, { domain: 80001, address: '0xeAc82476aF67dca63B04a66EA8D7230EfB4028DB' },
], ],
governanceRouter: '0x11E94700D9E5Ab1F8Bd0b3bd13e331CEFe3acEB7',
xAppConnectionManager: '0xf9db87020527A5A5aeFd95099051Fb14058916C9',
}; };
export const mumbai: OpticsDomain = { export const mumbai: OpticsDomain = {
@ -67,6 +75,8 @@ export const mumbai: OpticsDomain = {
{ domain: 3000, address: '0xc501ad2163Ebd9921B4a6E46B344Ef7bA76A2cBa' }, { domain: 3000, address: '0xc501ad2163Ebd9921B4a6E46B344Ef7bA76A2cBa' },
{ domain: 43113, address: '0xeAc82476aF67dca63B04a66EA8D7230EfB4028DB' }, { domain: 43113, address: '0xeAc82476aF67dca63B04a66EA8D7230EfB4028DB' },
], ],
governanceRouter: '0x11E94700D9E5Ab1F8Bd0b3bd13e331CEFe3acEB7',
xAppConnectionManager: '0xf9db87020527A5A5aeFd95099051Fb14058916C9',
}; };
export const devCommunityDomains = [alfajores, kovan, gorli, fuji, mumbai]; export const devCommunityDomains = [alfajores, kovan, gorli, fuji, mumbai];

@ -6,6 +6,8 @@ export interface OpticsDomain extends Domain {
ethHelper?: Address; ethHelper?: Address;
home: Address; home: Address;
replicas: ReplicaInfo[]; replicas: ReplicaInfo[];
governanceRouter: Address;
xAppConnectionManager: Address;
} }
export interface ReplicaInfo { export interface ReplicaInfo {

@ -6,15 +6,11 @@ export const ethereum: OpticsDomain = {
bridgeRouter: '0x6a39909e805A3eaDd2b61fFf61147796ca6aBB47', bridgeRouter: '0x6a39909e805A3eaDd2b61fFf61147796ca6aBB47',
ethHelper: '0xf1c1413096ff2278C3Df198a28F8D54e0369cF3A', ethHelper: '0xf1c1413096ff2278C3Df198a28F8D54e0369cF3A',
home: '0xf25C5932bb6EFc7afA4895D9916F2abD7151BF97', home: '0xf25C5932bb6EFc7afA4895D9916F2abD7151BF97',
governanceRouter: '0x42303634F37956687fB7ff2c6146AC842481A052',
xAppConnectionManager: '0xcEc158A719d11005Bd9339865965bed938BEafA3',
replicas: [ replicas: [
{ { domain: 1667591279, address: '0x07b5B57b08202294E657D51Eb453A189290f6385' },
domain: 1667591279, { domain: 1886350457, address: '0x7725EadaC5Ee986CAc8317a1d2fB16e59e079E8b' },
address: '0x07b5B57b08202294E657D51Eb453A189290f6385',
},
{
domain: 1886350457,
address: '0x7725EadaC5Ee986CAc8317a1d2fB16e59e079E8b',
},
], ],
}; };
@ -29,12 +25,11 @@ export const polygon: OpticsDomain = {
bridgeRouter: '0xf244eA81F715F343040569398A4E7978De656bf6', bridgeRouter: '0xf244eA81F715F343040569398A4E7978De656bf6',
ethHelper: '0xc494bFEE14b5E1E118F93CfedF831f40dFA720fA', ethHelper: '0xc494bFEE14b5E1E118F93CfedF831f40dFA720fA',
home: '0x97bbda9A1D45D86631b243521380Bc070D6A4cBD', home: '0x97bbda9A1D45D86631b243521380Bc070D6A4cBD',
governanceRouter: '0xcEc158A719d11005Bd9339865965bed938BEafA3',
xAppConnectionManager: '0x3BAD272559949B455f14ee394798E4D744342661',
replicas: [ replicas: [
{ domain: 6648936, address: '0xf25C5932bb6EFc7afA4895D9916F2abD7151BF97' }, { domain: 6648936, address: '0xf25C5932bb6EFc7afA4895D9916F2abD7151BF97' },
{ { domain: 1667591279, address: '0x681Edb6d52138cEa8210060C309230244BcEa61b' },
domain: 1667591279,
address: '0x681Edb6d52138cEa8210060C309230244BcEa61b',
},
], ],
}; };
@ -43,13 +38,12 @@ export const celo: OpticsDomain = {
id: 1667591279, id: 1667591279,
bridgeRouter: '0xf244eA81F715F343040569398A4E7978De656bf6', bridgeRouter: '0xf244eA81F715F343040569398A4E7978De656bf6',
home: '0x97bbda9A1D45D86631b243521380Bc070D6A4cBD', home: '0x97bbda9A1D45D86631b243521380Bc070D6A4cBD',
governanceRouter: '0xcEc158A719d11005Bd9339865965bed938BEafA3',
xAppConnectionManager: '0x3BAD272559949B455f14ee394798E4D744342661',
replicas: [ replicas: [
{ domain: 6648936, address: '0xf25c5932bb6efc7afa4895d9916f2abd7151bf97' }, { domain: 6648936, address: '0xf25C5932bb6EFc7afA4895D9916F2abD7151BF97' },
{ { domain: 1886350457, address: '0x681Edb6d52138cEa8210060C309230244BcEa61b' },
domain: 1886350457,
address: '0x681Edb6d52138cEa8210060C309230244BcEa61b',
},
], ],
}; };
export const mainnetDomains = [ethereum, celo, polygon]; export const mainnetDomains = [ethereum, polygon, celo];

@ -2,50 +2,55 @@ import { OpticsDomain } from './domain';
export const celo: OpticsDomain = { export const celo: OpticsDomain = {
name: 'celo', name: 'celo',
id: 1667591279, // b'celo' as an int id: 1667591279,
bridgeRouter: '0x1548cf5cf7dBd93f4dA11f45fCce315573d21B60', bridgeRouter: '0x1548cf5cf7dBd93f4dA11f45fCce315573d21B60',
home: '0x913EE05036f3cbc94Ee4afDea87ceb430524648a', home: '0x913EE05036f3cbc94Ee4afDea87ceb430524648a',
governanceRouter: '0xd13aC1024d266B73180cA7445Ca0E78b3Acfe8CE',
xAppConnectionManager: '0xaa099aF87ACE9E437b9B410a687F263eeaeC4321',
replicas: [ replicas: [
{ { domain: 6648936, address: '0xcDE146d1C673fE13f4fF1569d3F0d9f4d0b9c837' },
domain: 6648936, // ethereum { domain: 1635148152, address: '0x2784a755690453035f32Ac5e28c52524d127AfE2' },
address: '0xcDE146d1C673fE13f4fF1569d3F0d9f4d0b9c837' { domain: 1886350457, address: '0xfde0a96468ae91B4E13794E1B8e5B222E7Db6a23' },
},
{
domain: 1886350457, // polygon
address: '0xfde0a96468ae91B4E13794E1B8e5B222E7Db6a23',
},
{
domain: 1635148152, // avalanche
address: '0x2784a755690453035f32Ac5e28c52524d127AfE2',
},
], ],
}; };
export const ethereum: OpticsDomain = { export const ethereum: OpticsDomain = {
name: 'ethereum', name: 'ethereum',
id: 6648936, // b'eth' as an int id: 6648936,
bridgeRouter: '0x4fc16De11deAc71E8b2Db539d82d93BE4b486892', bridgeRouter: '0x4fc16De11deAc71E8b2Db539d82d93BE4b486892',
ethHelper: '0x2784a755690453035f32Ac5e28c52524d127AfE2', ethHelper: '0x2784a755690453035f32Ac5e28c52524d127AfE2',
home: '0xa73a3a74C7044B5411bD61E1990618A1400DA379', home: '0xa73a3a74C7044B5411bD61E1990618A1400DA379',
governanceRouter: '0xcbcF180dbd02460dCFCdD282A0985DdC049a4c94',
xAppConnectionManager: '0x8A926cE79f83A5A4C234BeE93feAFCC85b1E40cD',
replicas: [ replicas: [
{ { domain: 1635148152, address: '0xaa099aF87ACE9E437b9B410a687F263eeaeC4321' },
domain: 1667591279, // celo { domain: 1667591279, address: '0x27658c5556A9a57f96E69Bbf6d3B8016f001a785' },
address: '0x27658c5556A9a57f96E69Bbf6d3B8016f001a785' { domain: 1886350457, address: '0x4eA75c12eD058F0e6651475688a941555FA62395' },
}, ],
{ };
domain: 1886350457, // polygon
address: '0x4eA75c12eD058F0e6651475688a941555FA62395', export const avalanche: OpticsDomain = {
}, name: 'avalanche',
{ id: 1635148152,
domain: 1635148152, // avalanche paginate: {
address: '0xaa099aF87ACE9E437b9B410a687F263eeaeC4321', blocks: 1000000,
from: 6765067,
}, },
bridgeRouter: '0xB6bB41B1fb8c381b002C405B8abB5D1De0C0abFE',
ethHelper: '0x4fc16De11deAc71E8b2Db539d82d93BE4b486892',
home: '0x101a39eA1143cb252fc8093847399046fc35Db89',
governanceRouter: '0x4d89F34dB307015F8002F97c1d100d84e3AFb76c',
xAppConnectionManager: '0x81B97dfBB743c343983e9bE7B863dB636DbD7373',
replicas: [
{ domain: 6648936, address: '0xCf9066ee2fF063dD09862B745414c8dEa4Cc0497' },
{ domain: 1667591279, address: '0xA734EDE8229970776e1B68085D579b6b6E97dAd4' },
{ domain: 1886350457, address: '0x706DC810c79dAAFb82D304D7C9ff9518D8B43Fae' },
], ],
}; };
export const polygon: OpticsDomain = { export const polygon: OpticsDomain = {
name: 'polygon', name: 'polygon',
id: 1886350457, // b'poly' as an int id: 1886350457,
paginate: { paginate: {
// This needs to be stupidly low to avoid RPC timeouts // This needs to be stupidly low to avoid RPC timeouts
blocks: 10000, blocks: 10000,
@ -54,46 +59,13 @@ export const polygon: OpticsDomain = {
bridgeRouter: '0x3a5846882C0d5F8B0FA4bB04dc90C013104d125d', bridgeRouter: '0x3a5846882C0d5F8B0FA4bB04dc90C013104d125d',
ethHelper: '0xa489b8981ae5652C9Dd6515848cB8Dbecae5E1B0', ethHelper: '0xa489b8981ae5652C9Dd6515848cB8Dbecae5E1B0',
home: '0xCf9066ee2fF063dD09862B745414c8dEa4Cc0497', home: '0xCf9066ee2fF063dD09862B745414c8dEa4Cc0497',
governanceRouter: '0xf1dd0edC8f8C9a881F350e8010e06bE9eaf7DafA',
xAppConnectionManager: '0x4eA75c12eD058F0e6651475688a941555FA62395',
replicas: [ replicas: [
{ { domain: 6648936, address: '0x2784a755690453035f32Ac5e28c52524d127AfE2' },
domain: 1667591279, // celo { domain: 1635148152, address: '0xfde0a96468ae91B4E13794E1B8e5B222E7Db6a23' },
address: '0x45D35F60Ccf8F7031FB5A09954Cd923A9E84F89d' { domain: 1667591279, address: '0x45D35F60Ccf8F7031FB5A09954Cd923A9E84F89d' },
},
{
domain: 6648936, // ethereum
address: '0x2784a755690453035f32Ac5e28c52524d127AfE2',
},
{
domain: 1635148152, // avalanche
address: '0xfde0a96468ae91B4E13794E1B8e5B222E7Db6a23',
},
],
};
export const avalanche: OpticsDomain = {
name: 'avalanche',
id: 1635148152, // b'avax' as an int
paginate: {
blocks: 1000000,
from: 6765067,
},
bridgeRouter: '0xB6bB41B1fb8c381b002C405B8abB5D1De0C0abFE',
ethHelper: '0x4fc16De11deAc71E8b2Db539d82d93BE4b486892',
home: '0x101a39eA1143cb252fc8093847399046fc35Db89',
replicas: [
{
domain: 1667591279, // celo
address: '0xA734EDE8229970776e1B68085D579b6b6E97dAd4'
},
{
domain: 6648936, // ethereum
address: '0xCf9066ee2fF063dD09862B745414c8dEa4Cc0497',
},
{
domain: 1886350457, // polygon
address: '0x706DC810c79dAAFb82D304D7C9ff9518D8B43Fae',
},
], ],
}; };
export const mainnetCommunityDomains = [celo, ethereum, polygon, avalanche]; export const mainnetCommunityDomains = [celo, ethereum, avalanche, polygon];

@ -4,13 +4,12 @@ export const alfajores: OpticsDomain = {
name: 'alfajores', name: 'alfajores',
id: 1000, id: 1000,
bridgeRouter: '0xd6930Ee55C141E5Bb4079d5963cF64320956bb3E', bridgeRouter: '0xd6930Ee55C141E5Bb4079d5963cF64320956bb3E',
home: '0x47AaF05B1C36015eC186892C43ba4BaF91246aaA', home: '0xc8abA9c65A292C84EA00441B81124d9507fB22A8',
governanceRouter: '0x760AbbE9496BD9cEe159402E2B4d96E3d76dbE6a',
xAppConnectionManager: '0x02c144AeBA550634c8EE185F78657fd3C4a3F9B5',
replicas: [ replicas: [
{ domain: 2000, address: '0x7804079cF55110dE7Db5aA67eB1Be00cBE9CA526' }, { domain: 2000, address: '0x7149bF9f804F27e7259d0Ce328Dd5f6D5639ef19' },
{ { domain: 3000, address: '0xE469D8587D45BF85297BD924b159E726E7CA5408' },
domain: 3000,
address: '0x6B8D6947B9b70f3ff1b547a15B969F625d28104a',
},
], ],
}; };
@ -19,13 +18,12 @@ export const kovan: OpticsDomain = {
id: 3000, id: 3000,
bridgeRouter: '0x359089D34687bDbFD019fCC5093fFC21bE9905f5', bridgeRouter: '0x359089D34687bDbFD019fCC5093fFC21bE9905f5',
ethHelper: '0x411ABcFD947212a0D64b97C9882556367b61704a', ethHelper: '0x411ABcFD947212a0D64b97C9882556367b61704a',
home: '0x5B55C29A10aEe6D5750F128C6a8f490de763ccc7', home: '0xB6Ee3e8fE5b577Bd6aB9a06FA169F97303586E7C',
governanceRouter: '0xa95868Ffaed7489e9059d4a08A0C1B0F78041b33',
xAppConnectionManager: '0x1d9Af80594930574201d919Af0fBfe6bb89800E2',
replicas: [ replicas: [
{ domain: 2000, address: '0xC1AB4d72548Cc1C248EAdcD340035C3b213a47C3' }, { domain: 1000, address: '0xF76995174f3C02e2900d0F6261e8cbeC04078E1f' },
{ { domain: 2000, address: '0xFF47138c42119Fe0B1f267e2fa254321DE287Fc6' },
domain: 1000,
address: '0xE63E73339501EE3A8d2928d6C88cf30aC8556Ee0',
},
], ],
}; };
@ -34,13 +32,12 @@ export const rinkeby: OpticsDomain = {
id: 2000, id: 2000,
bridgeRouter: '0x8FbEA25D0bFDbff68F2B920df180e9498E9c856A', bridgeRouter: '0x8FbEA25D0bFDbff68F2B920df180e9498E9c856A',
ethHelper: '0x1BEBC8F1260d16EE5d1CFEE9366bB474bD13DC5f', ethHelper: '0x1BEBC8F1260d16EE5d1CFEE9366bB474bD13DC5f',
home: '0x6E6010E6bd43a9d2F7AE3b7eA9f61760e58758f3', home: '0x8459EDe1ed4dADD6D5B142d845240088A6530Cf8',
governanceRouter: '0x8f8424DC94b4c302984Ab5a03fc4c2d1Ec95DC92',
xAppConnectionManager: '0x53B94f2D4a3159b66fcCC4f406Ea388426A3f3cB',
replicas: [ replicas: [
{ domain: 1000, address: '0x6A5F9531D1877ebE96Bc0631DbF64BBCf1f7421c' }, { domain: 1000, address: '0xb473F5e0AAf47Ba54dac048633e7b578c1eBde01' },
{ { domain: 3000, address: '0x7EB8450a5397b795F2d89BC48EA20c24fa147F11' },
domain: 3000,
address: '0x6554bc7a5C35bA64Bf48FA8a9e662d8808aaa890',
},
], ],
}; };

@ -5,19 +5,12 @@ export const alfajores: OpticsDomain = {
id: 1000, id: 1000,
bridgeRouter: '0xe29Abbc3669064d8aF9F6BE378179a133664a92C', bridgeRouter: '0xe29Abbc3669064d8aF9F6BE378179a133664a92C',
home: '0xDf89d5d4039ada018BCDb992Bb6C2e05fEf86328', home: '0xDf89d5d4039ada018BCDb992Bb6C2e05fEf86328',
governanceRouter: '0x1E2DE9CD3f64c4e9AadE11a60C7b3620dD026888',
xAppConnectionManager: '0x56Bf96be9ab395aa2861E7Ae4aCEFc11D8C2Ec49',
replicas: [ replicas: [
{ { domain: 3, address: '0xC9e581Cd4fF6533f5ccBA4Dc5d5f642B8b658B93' },
domain: 3, // ropsten { domain: 5, address: '0x4eAD31e37b950B32b9EBbE747f0ef4BffAc336a5' },
address: '0xC9e581Cd4fF6533f5ccBA4Dc5d5f642B8b658B93' { domain: 3000, address: '0x15fA9169F7495162ac52b4A7957c9054097Ab0FF' },
},
{
domain: 3000, // kovan
address: '0x15fA9169F7495162ac52b4A7957c9054097Ab0FF',
},
{
domain: 5, // gorli
address: '0x4eAD31e37b950B32b9EBbE747f0ef4BffAc336a5',
},
], ],
}; };
@ -27,19 +20,12 @@ export const ropsten: OpticsDomain = {
bridgeRouter: '0xe29Abbc3669064d8aF9F6BE378179a133664a92C', bridgeRouter: '0xe29Abbc3669064d8aF9F6BE378179a133664a92C',
ethHelper: '0x9A0e88a3D8CF09F3dc5Ba65640299DE3D87f926C', ethHelper: '0x9A0e88a3D8CF09F3dc5Ba65640299DE3D87f926C',
home: '0x7E26E170dB94E81979927d2D39CB703048Ad599D', home: '0x7E26E170dB94E81979927d2D39CB703048Ad599D',
governanceRouter: '0xa8C889D257d9eE02cb957941cd785CfffDe5a453',
xAppConnectionManager: '0xe5C92bC2a443016c00b3908dFA63f55bEe1a7a16',
replicas: [ replicas: [
{ { domain: 5, address: '0x15C1edbf6E6161d50d58682dF7587F0d61db5C38' },
domain: 1000, // alfajores { domain: 1000, address: '0x30dAE25E9eBd644841d1A1fF25e303331B1CdEb3' },
address: '0x30dAE25E9eBd644841d1A1fF25e303331B1CdEb3' { domain: 3000, address: '0xF782C67AA111a9D75f6ccEf3d7aDB54620D5A8e9' },
},
{
domain: 3000, // kovan
address: '0xF782C67AA111a9D75f6ccEf3d7aDB54620D5A8e9',
},
{
domain: 5, // gorli
address: '0x15C1edbf6E6161d50d58682dF7587F0d61db5C38',
},
], ],
}; };
@ -49,19 +35,12 @@ export const kovan: OpticsDomain = {
bridgeRouter: '0x9A0e88a3D8CF09F3dc5Ba65640299DE3D87f926C', bridgeRouter: '0x9A0e88a3D8CF09F3dc5Ba65640299DE3D87f926C',
ethHelper: '0x8c7510966c0312dEb2305A5E1C923CE48bbf55Ce', ethHelper: '0x8c7510966c0312dEb2305A5E1C923CE48bbf55Ce',
home: '0x7E26E170dB94E81979927d2D39CB703048Ad599D', home: '0x7E26E170dB94E81979927d2D39CB703048Ad599D',
governanceRouter: '0xa8C889D257d9eE02cb957941cd785CfffDe5a453',
xAppConnectionManager: '0xe5C92bC2a443016c00b3908dFA63f55bEe1a7a16',
replicas: [ replicas: [
{ { domain: 3, address: '0x15C1edbf6E6161d50d58682dF7587F0d61db5C38' },
domain: 1000, // alfajores { domain: 5, address: '0xF782C67AA111a9D75f6ccEf3d7aDB54620D5A8e9' },
address: '0x30dAE25E9eBd644841d1A1fF25e303331B1CdEb3' { domain: 1000, address: '0x30dAE25E9eBd644841d1A1fF25e303331B1CdEb3' },
},
{
domain: 3, // ropsten
address: '0x15C1edbf6E6161d50d58682dF7587F0d61db5C38',
},
{
domain: 5, // gorli
address: '0xF782C67AA111a9D75f6ccEf3d7aDB54620D5A8e9',
},
], ],
}; };
@ -71,20 +50,13 @@ export const gorli: OpticsDomain = {
bridgeRouter: '0xe29Abbc3669064d8aF9F6BE378179a133664a92C', bridgeRouter: '0xe29Abbc3669064d8aF9F6BE378179a133664a92C',
ethHelper: '0x9A0e88a3D8CF09F3dc5Ba65640299DE3D87f926C', ethHelper: '0x9A0e88a3D8CF09F3dc5Ba65640299DE3D87f926C',
home: '0xDf89d5d4039ada018BCDb992Bb6C2e05fEf86328', home: '0xDf89d5d4039ada018BCDb992Bb6C2e05fEf86328',
governanceRouter: '0x1E2DE9CD3f64c4e9AadE11a60C7b3620dD026888',
xAppConnectionManager: '0x56Bf96be9ab395aa2861E7Ae4aCEFc11D8C2Ec49',
replicas: [ replicas: [
{ { domain: 3, address: '0xC9e581Cd4fF6533f5ccBA4Dc5d5f642B8b658B93' },
domain: 1000, // alfajores { domain: 1000, address: '0x15fA9169F7495162ac52b4A7957c9054097Ab0FF' },
address: '0x15fA9169F7495162ac52b4A7957c9054097Ab0FF' { domain: 3000, address: '0x4eAD31e37b950B32b9EBbE747f0ef4BffAc336a5' },
},
{
domain: 3, // ropsten
address: '0xC9e581Cd4fF6533f5ccBA4Dc5d5f642B8b658B93',
},
{
domain: 3000, // kovan
address: '0x4eAD31e37b950B32b9EBbE747f0ef4BffAc336a5',
},
], ],
}; };
export const stagingCommunityDomains = [alfajores, kovan, ropsten, gorli]; export const stagingCommunityDomains = [alfajores, ropsten, kovan, gorli];

@ -0,0 +1,105 @@
import { ethers } from 'ethers';
import { CoreContracts } from '../contracts';
import * as utils from './utils';
export type Address = string;
export interface Call {
to: Address;
data: ethers.utils.BytesLike;
}
export class CallBatch {
readonly local: Readonly<Call>[];
readonly remote: Map<number, Readonly<Call>[]>;
private core: CoreContracts;
private built?: ethers.PopulatedTransaction[];
constructor(core: CoreContracts) {
this.core = core;
this.remote = new Map();
this.local = [];
}
static async fromCore(core: CoreContracts): Promise<CallBatch> {
const governor = await core.governor();
if (!governor.local)
throw new Error(
'Cannot create call batch on a chain without governance rights. Use the governing chain.',
);
return new CallBatch(core);
}
pushLocal(call: Call): void {
if (this.built)
throw new Error('Batch has been built. Cannot push more calls');
this.local.push(utils.normalizeCall(call));
}
pushRemote(domain: number, call: Call): void {
if (this.built)
throw new Error('Batch has been built. Cannot push more calls');
const calls = this.remote.get(domain);
const normalized = utils.normalizeCall(call);
if (!calls) {
this.remote.set(domain, [normalized]);
} else {
calls.push(normalized);
}
}
// Build governance transactions from this callbatch
async build(
overrides?: ethers.Overrides,
): Promise<ethers.PopulatedTransaction[]> {
if (this.built && overrides)
throw new Error('Cannot rebuild batch with new overrides')
if (this.built) return this.built;
const [domains, remoteCalls] = utils.associateRemotes(this.remote);
const local = await this.core.governanceRouter.populateTransaction.callLocal(this.local)
const remotes = await Promise.all(
domains.map((domain: number, i: number) => this.core.governanceRouter.populateTransaction.callRemote(domain, remoteCalls[i], overrides))
)
this.built = remotes.concat(local)
return this.built;
}
// Sign each governance transaction and dispatch them to the chain
async execute(
overrides?: ethers.Overrides,
): Promise<ethers.providers.TransactionReceipt[]> {
const transactions = await this.build(overrides);
const signer = await this.governorSigner()
const receipts = []
for (const tx of transactions) {
const response = await signer.sendTransaction(tx)
receipts.push(await response.wait())
}
return receipts
}
async estimateGas(
overrides?: ethers.Overrides,
): Promise<any[]> {
const transactions = await this.build(overrides);
const signer = await this.governorSigner()
const responses = []
for (const tx of transactions) {
responses.push(await signer.estimateGas(tx))
}
return responses
}
async governorSigner(): Promise<ethers.Signer> {
const signer = this.core.governanceRouter.signer;
const governor = await this.core.governor()
const signerAddress = await signer.getAddress()
if (!governor.local)
throw new Error('Governor is not local');
if (signerAddress !== governor.identifier)
throw new Error('Signer is not Governor');
return signer
}
}

@ -0,0 +1,49 @@
import { ethers } from 'ethers';
import { Call } from '.';
import { canonizeId } from '../../utils';
// Returns the length (in bytes) of a BytesLike.
export function byteLength(bytesLike: ethers.utils.BytesLike): number {
return ethers.utils.arrayify(bytesLike).length;
}
/**
* Serialize a call to its packed Optics governance representation
* @param call The function call to serialize
* @returns The serialized function call, as a '0x'-prepended hex string
*/
export function serializeCall(call: Call): string {
const { to, data } = call;
const dataLen = byteLength(data);
if (!to || !data) {
throw new Error(`Missing data in Call: \n ${call}`);
}
return ethers.utils.solidityPack(
['bytes32', 'uint32', 'bytes'],
[to, dataLen, data],
);
}
export function associateRemotes(
remoteCalls: Map<number, Call[]>,
): [number[], Call[][]] {
const domains = [];
const calls = [];
for (const [key, value] of remoteCalls) {
domains.push(key);
calls.push(value);
}
return [domains, calls];
}
export function normalizeCall(partial: Partial<Call>): Readonly<Call> {
const to = ethers.utils.hexlify(canonizeId(partial.to!));
const data = partial.data ?? '0x';
return Object.freeze({
to,
data,
});
}

@ -1,5 +1,6 @@
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import { Domain } from './domains'; import { Domain } from './domains';
import { StaticCeloJsonRpcProvider } from 'celo-ethers-provider';
type Provider = ethers.providers.Provider; type Provider = ethers.providers.Provider;
@ -151,7 +152,14 @@ export class MultiProvider {
*/ */
registerRpcProvider(nameOrDomain: string | number, rpc: string): void { registerRpcProvider(nameOrDomain: string | number, rpc: string): void {
const domain = this.resolveDomain(nameOrDomain); const domain = this.resolveDomain(nameOrDomain);
const celoNames = ['alfajores', 'celo']
for (const name of celoNames) {
if (nameOrDomain === name) {
const provider = new StaticCeloJsonRpcProvider(rpc);
this.registerProvider(domain, provider);
return
}
}
const provider = new ethers.providers.StaticJsonRpcProvider(rpc); const provider = new ethers.providers.StaticJsonRpcProvider(rpc);
this.registerProvider(domain, provider); this.registerProvider(domain, provider);
} }

@ -11,6 +11,7 @@ export type Address = string;
* @returns A Uint8Array of length 32 * @returns A Uint8Array of length 32
*/ */
export function canonizeId(data: BytesLike): Uint8Array { export function canonizeId(data: BytesLike): Uint8Array {
if (!data) throw new Error('Bad input. Undefined');
const buf = ethers.utils.arrayify(data); const buf = ethers.utils.arrayify(data);
if (buf.length > 32) { if (buf.length > 32) {
throw new Error('Too long'); throw new Error('Too long');

@ -11,6 +11,7 @@
"./src/optics/contracts/*.ts", "./src/optics/contracts/*.ts",
"./src/optics/domains/*.ts", "./src/optics/domains/*.ts",
"./src/optics/events/*.ts", "./src/optics/events/*.ts",
"./src/optics/govern/*.ts",
"./src/optics/messages/*.ts", "./src/optics/messages/*.ts",
"./src/optics/tokens/*.ts" "./src/optics/tokens/*.ts"
] ]

Loading…
Cancel
Save