Skip to content
Draft
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
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 36 additions & 39 deletions src/modules/domains/domains.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,10 @@ import {
MulticallTx,
SetRoleDefinitionOptions,
CreateOrganizationOptions,
ReturnStep,
CreateApplicationOptions,
CreateRoleOptions,
ChangeOrgOwnershipOptions,
ChangeAppOwnershipOptions,
ReturnStepWithRetryCheck,
ChangeRoleOwnershipOptions,
DeleteOrganizationOptions,
DeleteApplicationOptions,
Expand All @@ -58,6 +56,7 @@ import { validateAddress } from '../../utils/address';
import { UnregisteredResolverError } from '../../errors/unregistered-resolver.error';
import { castToV2 } from './domains.types';
import { getLogger } from '../../config/logger.config';
import { GnosisSigner, ProviderType } from '../signer';

/**
* Service responsible for handling the request to ENS, creating roles/organizations/applications namespaces.
Expand Down Expand Up @@ -190,6 +189,7 @@ export class DomainsService {
/**
* Create organization domain with given definition for given namespace.
* Also includes creating subdomains for roles and applications. (roles.yourOrg.ewc, apps.yourOrg.ewc).
* When iam-lib initialized with Gnosis wallet new organization will belong to Safe wallet.
*
* ```typescript
* domainsService.createOrganization({
Expand All @@ -210,19 +210,24 @@ export class DomainsService {
namespace,
data,
returnSteps,
}: CreateOrganizationOptions): Promise<ReturnStep[] | undefined> {
}: CreateOrganizationOptions): Promise<MulticallTx | undefined> {
const orgDomain = `${orgName}.${namespace}`;
const rolesDomain = `${NamespaceType.Role}.${orgDomain}`;
const appsDomain = `${NamespaceType.Application}.${orgDomain}`;
if (!(await this.isOwner({ domain: namespace, user: this._owner }))) {
throw new Error(ERROR_MESSAGES.NOT_AUTHORIZED_TO_CHANGE_DOMAIN);
}
const steps: ReturnStep[] = [
const owner =
this._signerService.providerType === ProviderType.Gnosis
? (this._signerService.signer as GnosisSigner).safeInfo.safeAddress
: this._owner;

const steps: MulticallTx = [
{
tx: this.createSubdomainTx({
domain: namespace,
nodeName: orgName,
owner: this._owner,
owner,
}),
info: 'Create organization subdomain',
},
Expand All @@ -237,7 +242,7 @@ export class DomainsService {
tx: this.createSubdomainTx({
domain: orgDomain,
nodeName: NamespaceType.Role,
owner: this._owner,
owner,
}),
info: 'Create roles subdomain for organization',
},
Expand All @@ -251,7 +256,7 @@ export class DomainsService {
tx: this.createSubdomainTx({
domain: orgDomain,
nodeName: NamespaceType.Application,
owner: this._owner,
owner,
}),
info: 'Create app subdomain for organization',
},
Expand All @@ -264,7 +269,7 @@ export class DomainsService {
].map((step) => ({
...step,
next: async () => {
await this._signerService.send({ ...step.tx });
return this._signerService.send({ ...step.tx });
},
}));
if (returnSteps) {
Expand Down Expand Up @@ -300,10 +305,10 @@ export class DomainsService {
namespace: domain,
data,
returnSteps,
}: CreateApplicationOptions): Promise<ReturnStep[] | undefined> {
}: CreateApplicationOptions): Promise<MulticallTx | undefined> {
const appDomain = `${appName}.${domain}`;
const from = await this.getOwner({ namespace: domain });
const steps: ReturnStep[] = [
const steps: MulticallTx = [
{
tx: this.createSubdomainTx({ domain, nodeName: appName, owner: from }),
info: 'Set subdomain for application',
Expand Down Expand Up @@ -332,7 +337,7 @@ export class DomainsService {
].map((step) => ({
...step,
next: async () => {
await this._signerService.send(step.tx);
return this._signerService.send(step.tx);
},
}));
if (returnSteps) {
Expand Down Expand Up @@ -375,11 +380,11 @@ export class DomainsService {
namespace,
data,
returnSteps,
}: CreateRoleOptions): Promise<ReturnStep[] | undefined> {
}: CreateRoleOptions): Promise<MulticallTx | undefined> {
const dataV2 = castToV2(data);
const newDomain = `${roleName}.${namespace}`;
const from = await this.getOwner({ namespace });
const steps: ReturnStep[] = [
const steps: MulticallTx = [
{
tx: this.createSubdomainTx({
domain: namespace,
Expand All @@ -398,7 +403,7 @@ export class DomainsService {
].map((step) => ({
...step,
next: async () => {
await this._signerService.send(step.tx);
return this._signerService.send(step.tx);
},
}));
if (returnSteps) {
Expand Down Expand Up @@ -519,9 +524,7 @@ export class DomainsService {
namespace,
newOwner,
returnSteps,
}: ChangeAppOwnershipOptions): Promise<
ReturnStepWithRetryCheck[] | undefined
> {
}: ChangeAppOwnershipOptions): Promise<MulticallTx | undefined> {
DomainsService.validateOwnerAddress(newOwner);
const roles = await this.getRolesByNamespace({
namespace,
Expand Down Expand Up @@ -552,22 +555,20 @@ export class DomainsService {
);
}

const steps: ReturnStepWithRetryCheck[] = changeOwnerNamespaces.map(
(name) => {
const tx = this.changeDomainOwnerTx({ newOwner, namespace: name });
return {
tx,
next: async ({ retryCheck }: { retryCheck?: boolean } = {}) => {
if (retryCheck) {
const owner = await this.getOwner({ namespace: name });
if (owner === newOwner) return;
}
return this._signerService.send(tx);
},
info: `Changing ownership of ${name}`,
};
}
);
const steps: MulticallTx = changeOwnerNamespaces.map((name) => {
const tx = this.changeDomainOwnerTx({ newOwner, namespace: name });
return {
tx,
next: async ({ retryCheck }: { retryCheck?: boolean } = {}) => {
if (retryCheck) {
const owner = await this.getOwner({ namespace: name });
if (owner === newOwner) return;
}
return this._signerService.send(tx);
},
info: `Changing ownership of ${name}`,
};
});

if (returnSteps) {
return steps;
Expand Down Expand Up @@ -626,9 +627,7 @@ export class DomainsService {
async deleteOrganization({
namespace,
returnSteps = false,
}: DeleteOrganizationOptions): Promise<
ReturnStepWithRetryCheck[] | undefined
> {
}: DeleteOrganizationOptions): Promise<MulticallTx | undefined> {
const apps = this._cacheClient
? await this.getAppsOfOrg(namespace)
: await this.getSubdomains({
Expand Down Expand Up @@ -710,9 +709,7 @@ export class DomainsService {
async deleteApplication({
namespace,
returnSteps = false,
}: DeleteApplicationOptions): Promise<
ReturnStepWithRetryCheck[] | undefined
> {
}: DeleteApplicationOptions): Promise<MulticallTx | undefined> {
const roles = this._cacheClient
? await this._cacheClient.getApplicationRoles(namespace)
: await this.getSubdomains({
Expand Down
15 changes: 0 additions & 15 deletions src/modules/domains/domains.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
IRoleDefinition,
IRoleDefinitionV2,
} from '@energyweb/credential-governance';
import { TransactionReceipt } from '@energyweb/ekc';
import { providers } from 'ethers';

export enum NamespaceType {
Expand Down Expand Up @@ -64,20 +63,6 @@ export function castToV2(
}
}

export interface ReturnStep {
next: () => Promise<void>;
tx: EncodedCall;
info: string;
}

export interface ReturnStepWithRetryCheck {
next: (opt?: {
retryCheck?: boolean;
}) => Promise<TransactionReceipt | undefined>;
tx: EncodedCall;
info: string;
}

export type MulticallTx = {
tx: EncodedCall;
next: (opts?: {
Expand Down
16 changes: 9 additions & 7 deletions src/modules/signer/gnosis.signer.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { providers } from 'ethers';
import SafeAppSdk from '@gnosis.pm/safe-apps-sdk';
import SafeAppSdk, { SafeInfo } from '@gnosis.pm/safe-apps-sdk';
import { SafeAppProvider } from '@gnosis.pm/safe-apps-provider';
import { ProviderType } from './signer.types';
import { ProviderType, SignerT } from './signer.types';
import { SignerService } from './signer.service';

/**
* @description Intended for use in Volta Gnosis web interface(https://volta.gnosis-safe.io/).
* Dapp should provide SafeAppSdk injected by Gnosis interface
*/
export const fromGnosis = async (safeAppSdk: SafeAppSdk) => {
const gnosisProvider = new SafeAppProvider(
await safeAppSdk.safe.getInfo(),
safeAppSdk
);
const safeInfo = await safeAppSdk.safe.getInfo();
const gnosisProvider = new SafeAppProvider(safeInfo, safeAppSdk);
const provider = new providers.Web3Provider(gnosisProvider);
const signerService = new SignerService(
provider.getSigner(),
Object.assign(provider.getSigner(), { safeInfo }),
ProviderType.Gnosis
);
return signerService;
};

export interface GnosisSigner extends SignerT {
safeInfo: SafeInfo;
}