Skip to content
This repository was archived by the owner on Jan 24, 2022. It is now read-only.

Eliminates ProxyAdmin code duplication in ProxyAdminProject and AppProject using TypeScript Mixins #815

Merged
merged 1 commit into from
Apr 17, 2019
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
17 changes: 6 additions & 11 deletions packages/lib/src/project/AppProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import isEmpty from 'lodash.isempty';
import App from '../application/App';
import Package from '../application/Package';
import ProxyAdmin from '../proxy/ProxyAdmin';
import ProxyAdminProjectMixin from './mixin/ProxyAdminProjectMixin';
import ImplementationDirectory from '../application/ImplementationDirectory';
import BasePackageProject from './BasePackageProject';
import SimpleProject from './SimpleProject';
Expand Down Expand Up @@ -37,7 +38,7 @@ interface ExistingAddresses {
proxyFactoryAddress?: string;
}

export default class AppProject extends BasePackageProject {
class BaseAppProject extends BasePackageProject {
private name: string;
private app: App;
public proxyAdmin: ProxyAdmin;
Expand Down Expand Up @@ -68,7 +69,7 @@ export default class AppProject extends BasePackageProject {
if (!await app.hasPackage(name, version)) await app.setPackage(name, thepackage.address, version);
const proxyAdmin: ProxyAdmin | null = proxyAdminAddress ? await ProxyAdmin.fetch(proxyAdminAddress, txParams) : null;
const proxyFactory = ProxyFactory.tryFetch(proxyFactoryAddress, txParams);
const project: AppProject = new this(app, name, version, proxyAdmin, proxyFactory, txParams);
const project: AppProject = new AppProject(app, name, version, proxyAdmin, proxyFactory, txParams);
project.directory = directory;
project.package = thepackage;
return project;
Expand Down Expand Up @@ -130,11 +131,6 @@ export default class AppProject extends BasePackageProject {
public getAdminAddress(): Promise<string> {
return new Promise((resolve) => resolve(this.proxyAdmin ? this.proxyAdmin.address : null));
}

public async transferAdminOwnership(newAdminOwner: string): Promise<void> {
await this.proxyAdmin.transferOwnership(newAdminOwner);
}

public getApp(): App {
return this.app;
}
Expand Down Expand Up @@ -237,10 +233,6 @@ export default class AppProject extends BasePackageProject {
return this.proxyAdmin.upgradeProxy(proxyAddress, implementationAddress, contract, initMethod, initArgs);
}

public async changeProxyAdmin(proxyAddress: string, newAdmin: string): Promise<void> {
return this.proxyAdmin.changeProxyAdmin(proxyAddress, newAdmin);
}

public async getDependencyPackage(name: string): Promise<Package> {
const packageInfo = await this.app.getPackage(name);
return packageInfo.package;
Expand Down Expand Up @@ -275,3 +267,6 @@ export default class AppProject extends BasePackageProject {
}
}
}
// Mixings produce value but not type
// We have to export full class with type & callable
export default class AppProject extends ProxyAdminProjectMixin(BaseAppProject) {};
20 changes: 8 additions & 12 deletions packages/lib/src/project/ProxyAdminProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ import BaseSimpleProject from './BaseSimpleProject';
import { ContractInterface } from './AppProject';
import Contract from '../artifacts/Contract';
import ProxyFactory from '../proxy/ProxyFactory';
import ProxyAdminProjectMixin from './mixin/ProxyAdminProjectMixin';

const log: Logger = new Logger('ProxyAdminProject');

export default class ProxyAdminProject extends BaseSimpleProject {
class BaseProxyAdminProject extends BaseSimpleProject {
public proxyAdmin: ProxyAdmin;

public static async fetch(name: string = 'main', txParams: any = {}, proxyAdminAddress?: string, proxyFactoryAddress?: string) {
public static async fetch(name: string = 'main', txParams: any = {}, proxyAdminAddress?: string, proxyFactoryAddress?: string): Promise<ProxyAdminProject> {
const proxyAdmin = proxyAdminAddress ? await ProxyAdmin.fetch(proxyAdminAddress, txParams) : null;
const proxyFactory = proxyFactoryAddress ? await ProxyFactory.fetch(proxyFactoryAddress, txParams) : null;
return new this(name, proxyAdmin, proxyFactory, txParams);
return new ProxyAdminProject(name, proxyAdmin, proxyFactory, txParams);
}

constructor(name: string = 'main', proxyAdmin: ProxyAdmin, proxyFactory?: ProxyFactory, txParams: any = {}) {
Expand All @@ -40,23 +41,18 @@ export default class ProxyAdminProject extends BaseSimpleProject {
return contract.at(pAddress);
}

public async changeProxyAdmin(proxyAddress: string, newAdmin: string): Promise<void> {
await this.proxyAdmin.changeProxyAdmin(proxyAddress, newAdmin);
log.info(`Proxy ${proxyAddress} admin changed to ${newAdmin}`);
}

public getAdminAddress(): Promise<string> {
return new Promise((resolve) => resolve(this.proxyAdmin ? this.proxyAdmin.address : null));
}

public async transferAdminOwnership(newAdminOwner: string): Promise<void> {
await this.proxyAdmin.transferOwnership(newAdminOwner);
}

public async ensureProxyAdmin(): Promise<ProxyAdmin> {
if (!this.proxyAdmin) {
this.proxyAdmin = await ProxyAdmin.deploy(this.txParams);
}
return this.proxyAdmin;
}
}

// Mixings produce value but not type
// We have to export full class with type & callable
export default class ProxyAdminProject extends ProxyAdminProjectMixin(BaseProxyAdminProject) {};
21 changes: 21 additions & 0 deletions packages/lib/src/project/mixin/ProxyAdminProjectMixin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Constructable, { AbstractType, GetMixinType } from '../../utils/Mixin';
import ProxyAdmin from '../../proxy/ProxyAdmin';

// A mixin that adds ProxyAdmin field and related ProxyAdminProject methods
// Intented to as a building block for Project class
// Can't extend contructor at that moment due to TypeScript limitations https://github.com/Microsoft/TypeScript/issues/14126
function ProxyAdminProjectMixin<T extends Constructable>(Base: T) {
return class extends Base {
public proxyAdmin: ProxyAdmin;

public async transferAdminOwnership(newAdminOwner: string): Promise<void> {
await this.proxyAdmin.transferOwnership(newAdminOwner);
}

public async changeProxyAdmin(proxyAddress: string, newAdmin: string): Promise<void> {
return this.proxyAdmin.changeProxyAdmin(proxyAddress, newAdmin);
}
};
}

export default ProxyAdminProjectMixin;
7 changes: 7 additions & 0 deletions packages/lib/src/utils/Mixin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type Constructable<T = {}> = new (...args: any[]) => T;
export type Callable<T = any> = (...args: any[]) => T;
export type AbstractType<T = {}> = Function & { prototype: T };

export type GetMixinType<T extends Callable> = InstanceType<ReturnType<T>>;

export default Constructable;