Skip to content

Commit

Permalink
feat(assets): add asset smart contract integration
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Wojno authored and dwojno committed Mar 30, 2021
1 parent dfdb481 commit 68b68db
Show file tree
Hide file tree
Showing 12 changed files with 1,391 additions and 1,293 deletions.
2,189 changes: 952 additions & 1,237 deletions package-lock.json

Large diffs are not rendered by default.

19 changes: 11 additions & 8 deletions package.json
Expand Up @@ -14,9 +14,11 @@
"build": "npm run build:contracts && npm run build:ts && copyfiles \"ethers/**/*.d.ts\" dist",
"build:ts": "bili",
"build:api_docs": "rm -rf docs/api && typedoc --plugin typedoc-plugin-markdown --hideBreadcrumbs true",
"build:contracts": "npm run build:typechain:registry && npm run build:typechain:resolver",
"build:contracts": "npm run build:typechain:registry && npm run build:typechain:resolver && npm run build:typechain:offerableIdentity && npm run build:typechain:identityManager",
"build:typechain:registry": "typechain --target ethers-v4 --outDir ethers './node_modules/@ensdomains/ens/build/contracts/ENSRegistry.json'",
"build:typechain:resolver": "typechain --target ethers-v4 --outDir ethers './node_modules/@ensdomains/resolver/build/contracts/PublicResolver.json'",
"build:typechain:offerableIdentity": "typechain --target ethers-v4 --outDir ethers './node_modules/@ew-did-registry/proxyidentity/build/contracts/OfferableIdentity.json'",
"build:typechain:identityManager": "typechain --target ethers-v4 --outDir ethers './node_modules/@ew-did-registry/proxyidentity/build/contracts/IdentityManager.json'",
"prepare": "npm run build",
"start-rpc": "run-with-testrpc -m \"candy maple cake sugar pudding cream honey rich smooth crumble sweet treat\" --port 8544 --accounts 20 --networkId=9 --gasLimit=10000000",
"test:watch": "npm run start-rpc -- \"jest --coverage --env=./test/env.js --watchAll\"",
Expand Down Expand Up @@ -48,13 +50,14 @@
"@babel/runtime": "^7.12.5",
"@ensdomains/ens": "^0.4.5",
"@ensdomains/resolver": "^0.2.4",
"@ew-did-registry/claims": "0.1.0-alpha.0",
"@ew-did-registry/did": "0.1.0-alpha.0",
"@ew-did-registry/did-document": "0.1.0-alpha.0",
"@ew-did-registry/did-ethr-resolver": "0.1.0-alpha.0",
"@ew-did-registry/did-resolver-interface": "0.1.0-alpha.0",
"@ew-did-registry/jwt": "0.1.0-alpha.0",
"@ew-did-registry/keys": "0.1.0-alpha.0",
"@ew-did-registry/claims": "0.4.0",
"@ew-did-registry/did": "0.4.0",
"@ew-did-registry/did-document": "0.4.0",
"@ew-did-registry/did-ethr-resolver": "0.4.0",
"@ew-did-registry/did-resolver-interface": "0.4.0",
"@ew-did-registry/jwt": "0.4.0",
"@ew-did-registry/keys": "0.4.0",
"@ew-did-registry/proxyidentity": "^0.4.3-alpha.995.0",
"@gnosis.pm/safe-apps-sdk": "1.0.3",
"@metamask/detect-provider": "^1.2.0",
"@walletconnect/web3-provider": "1.0.0-rc.4",
Expand Down
23 changes: 22 additions & 1 deletion src/cacheServerClient/ICacheServerClient.ts
@@ -1,13 +1,17 @@
import { IDIDDocument } from "@ew-did-registry/did-resolver-interface";
import { IClaimIssuance, IClaimRejection, IClaimRequest } from "../iam";
import {
Asset,
AssetHistory,
AssetHistoryEventType,
Claim,
IApp,
IAppDefinition,
IOrganization,
IOrganizationDefinition,
IRole,
IRoleDefinition
IRoleDefinition,
Order
} from "./cacheServerClient.types";

export interface ICacheServerClient {
Expand Down Expand Up @@ -71,4 +75,21 @@ export interface ICacheServerClient {
includeClaims?: boolean;
}) => Promise<IDIDDocument>;
addDIDToWatchList: ({ did }: { did: string }) => Promise<void>;
getOwnedAssets: ({ did }: { did: string }) => Promise<Asset[]>;
getOfferedAssets: ({ did }: { did: string }) => Promise<Asset[]>;
getAssetById: ({ id }: { id: string }) => Promise<Asset>;
getPreviouslyOwnedAssets: ({ owner }: { owner: string }) => Promise<Asset[]>;
getAssetHistory: ({
id,
order,
take,
skip,
type
}: {
id: string;
order?: Order;
take?: number;
skip?: number;
type?: AssetHistoryEventType;
}) => Promise<AssetHistory[]>;
}
49 changes: 48 additions & 1 deletion src/cacheServerClient/cacheServerClient.ts
@@ -1,6 +1,15 @@
import axios, { AxiosError, AxiosInstance, AxiosResponse } from "axios";
import { stringify } from "qs";
import { IApp, IOrganization, IRole, Claim } from "./cacheServerClient.types";
import {
IApp,
IOrganization,
IRole,
Claim,
Asset,
Order,
AssetHistoryEventType,
AssetHistory
} from "./cacheServerClient.types";

import { IClaimIssuance, IClaimRejection, IClaimRequest } from "../iam";
import { IDIDDocument } from "@ew-did-registry/did-resolver-interface";
Expand Down Expand Up @@ -256,4 +265,42 @@ export class CacheServerClient implements ICacheServerClient {
async addDIDToWatchList({ did }: { did: string }) {
await this.httpClient.post(`/DID/${did}`);
}

async getOwnedAssets({ did }: { did: string }) {
const { data } = await this.httpClient.get<Asset[]>(`/assets/owner/${did}`);
return data;
}

async getOfferedAssets({ did }: { did: string }) {
const { data } = await this.httpClient.get<Asset[]>(`/assets/offered_to/${did}`);
return data;
}

async getAssetById({ id }: { id: string }) {
const { data } = await this.httpClient.get<Asset>(`/assets/${id}`);
return data;
}

async getPreviouslyOwnedAssets({ owner }: { owner: string }) {
const { data } = await this.httpClient.get<Asset[]>(`/assets/owner/history/${owner}`);
return data;
}

async getAssetHistory({
id,
order,
take,
skip,
type
}: {
id: string;
order?: Order;
take?: number;
skip?: number;
type?: AssetHistoryEventType;
}) {
const query = stringify({ order, take, skip, type }, { skipNulls: true });
const { data } = await this.httpClient.get<AssetHistory[]>(`/assets/history/${id}?${query}`);
return data;
}
}
30 changes: 30 additions & 0 deletions src/cacheServerClient/cacheServerClient.types.ts
@@ -1,3 +1,4 @@
import { IDIDDocument } from "@ew-did-registry/did-resolver-interface";
import { PreconditionTypes } from "../utils/constants";

export interface IRoleDefinition {
Expand Down Expand Up @@ -86,3 +87,32 @@ export interface Claim {
acceptedBy?: string;
isRejected?: boolean;
}

export interface Asset {
id: string;
owner: string;
offeredTo?: string;
document: IDIDDocument;
}

export interface AssetHistory {
id: number;
emittedBy: string;
relatedTo?: string;
at: number;
timestamp: string;
assetId?: string;
}

export enum Order {
"ASC" = "ASC",
"DESC" = "DESC"
}

export enum AssetHistoryEventType {
ASSET_CREATED = "ASSET_CREATED",
ASSET_OFFERED = "ASSET_OFFERED",
ASSET_OFFER_CANCELED = "ASSET_OFFER_CANCELED",
ASSET_TRANSFERRED = "ASSET_TRANSFERRED",
ASSET_OFFER_REJECTED = "ASSET_OFFER_REJECTED"
}
14 changes: 11 additions & 3 deletions src/iam-client-lib.ts
Expand Up @@ -30,7 +30,11 @@ import {
IOrganization,
IOrganizationDefinition,
IRole,
IRoleDefinition
IRoleDefinition,
Asset,
AssetHistory,
AssetHistoryEventType,
Order
} from "./cacheServerClient/cacheServerClient.types";

import {
Expand Down Expand Up @@ -65,7 +69,9 @@ export {
MessagingMethod,
ERROR_MESSAGES,
WalletProvider,
PreconditionTypes
PreconditionTypes,
Order,
AssetHistoryEventType
};

// TYPES
Expand All @@ -76,7 +82,9 @@ export {
IOrganization,
IOrganizationDefinition,
IRole,
IRoleDefinition
IRoleDefinition,
Asset,
AssetHistory
};

export { GnosisIam as SafeIam } from "./GnosisIam";
118 changes: 117 additions & 1 deletion src/iam.ts
Expand Up @@ -37,17 +37,20 @@ import {
ERROR_MESSAGES
} from "./errors";
import {
AssetHistoryEventType,
IAppDefinition,
IOrganization,
IOrganizationDefinition,
IRoleDefinition
IRoleDefinition,
Order
} from "./cacheServerClient/cacheServerClient.types";
import detectEthereumProvider from "@metamask/detect-provider";
import { WalletProvider } from "./types/WalletProvider";
import { getSubdomains } from "./utils/getSubDomains";
import { emptyAddress, NATS_EXCHANGE_TOPIC, PreconditionTypes } from "./utils/constants";
import { Subscription } from "nats.ws";
import { AxiosError } from "axios";
import { OfferableIdentityFactory } from "../ethers/OfferableIdentityFactory";

export type InitializeData = {
did: string | undefined;
Expand Down Expand Up @@ -1493,4 +1496,117 @@ export class IAM extends IAMBase {
})
);
}

// ### ASSETS ###
public async registerAsset() {
if (!this._address) {
throw new Error(ERROR_MESSAGES.USER_NOT_LOGGED_IN);
}
const asset = new OfferableIdentityFactory(this._signer);
const { address } = await asset.deploy(this._address, this._assetManagerAddress);
if (this._cacheClient) {
/*
* we need to wait until cache server will resolve assets did document
* which is taking some time
*/
let asset = await this.getAssetById({ id: `did:ethr:${address}` });
let loops = 0;
while (!asset && loops < 20) {
asset = await this.getAssetById({ id: `did:ethr:${address}` });
await new Promise(resolve => setTimeout(resolve, 1000));
loops++;
}
}
return address;
}

public async offerAsset({ assetDID, offerTo }: { assetDID: string; offerTo: string }) {
if (!this._address) {
throw new Error(ERROR_MESSAGES.USER_NOT_LOGGED_IN);
}
const [, , offerToAddress] = offerTo.split(":");
const [, , assetContractAddress] = assetDID.split(":");
const tx = this.offerAssetTx({ assetContractAddress, offerTo: offerToAddress });
await this.send({
calls: [tx],
from: this._address
});
}

public async acceptAssetOffer({ assetDID }: { assetDID: string }) {
if (!this._address) {
throw new Error(ERROR_MESSAGES.USER_NOT_LOGGED_IN);
}
const [, , assetContractAddress] = assetDID.split(":");
const tx = this.acceptOfferTx({ assetContractAddress });
await this.send({
calls: [tx],
from: this._address
});
}

public async rejectAssetOffer({ assetDID }: { assetDID: string }) {
if (!this._address) {
throw new Error(ERROR_MESSAGES.USER_NOT_LOGGED_IN);
}
const [, , assetContractAddress] = assetDID.split(":");
const tx = this.rejectOfferTx({ assetContractAddress });
await this.send({
calls: [tx],
from: this._address
});
}

public async cancelAssetOffer({ assetDID }: { assetDID: string }) {
if (!this._address) {
throw new Error(ERROR_MESSAGES.USER_NOT_LOGGED_IN);
}
const [, , assetContractAddress] = assetDID.split(":");
const tx = this.cancelOfferTx({ assetContractAddress });
await this.send({ calls: [tx], from: this._address });
}

public async getOwnedAssets({ did = this._did }: { did?: string } = {}) {
if (!did) {
throw new Error(ERROR_MESSAGES.USER_NOT_LOGGED_IN);
}
return this._cacheClient.getOwnedAssets({ did });
}

public async getOfferedAssets({ did = this._did }: { did?: string } = {}) {
if (!did) {
throw new Error(ERROR_MESSAGES.USER_NOT_LOGGED_IN);
}
return this._cacheClient.getOfferedAssets({ did });
}

public async getAssetById({ id }: { id: string }) {
if (this._cacheClient) {
return this._cacheClient.getAssetById({ id });
}
throw new Error(ERROR_MESSAGES.CACHE_CLIENT_NOT_PROVIDED);
}

public async getPreviouslyOwnedAssets({ owner }: { owner: string }) {
if (this._cacheClient) {
return this._cacheClient.getPreviouslyOwnedAssets({ owner });
}
throw new Error(ERROR_MESSAGES.CACHE_CLIENT_NOT_PROVIDED);
}

public async getAssetHistory({
id,
...query
}: {
id: string;
order?: Order;
take?: number;
skip?: number;
type?: AssetHistoryEventType;
}) {
if (this._cacheClient) {
return this._cacheClient.getAssetHistory({ id, ...query });
}
throw new Error(ERROR_MESSAGES.CACHE_CLIENT_NOT_PROVIDED);
}
}
2 changes: 2 additions & 0 deletions src/iam/chainConfig.ts
Expand Up @@ -7,6 +7,7 @@ export interface ChainConfig {
rpcUrl: string;
ensRegistryAddress: string;
ensResolverAddress: string;
assetManagerAddress: string;
didContractAddress: string;
}

Expand All @@ -24,6 +25,7 @@ export const chainConfigs: Record<number, ChainConfig> = {
rpcUrl: "https://volta-rpc-vkn5r5zx4ke71f9hcu0c.energyweb.org/",
ensRegistryAddress: "0xd7CeF70Ba7efc2035256d828d5287e2D285CD1ac",
ensResolverAddress: "0x0a97e07c4Df22e2e31872F20C5BE191D5EFc4680",
assetManagerAddress: "0x66163955e2D94eFb5823163cc705C42484c90362",
didContractAddress: VoltaAddress1056
}
};
Expand Down

0 comments on commit 68b68db

Please sign in to comment.