Skip to content

Commit 4f1d70c

Browse files
committed
feat: wip - lazy asset registration
1 parent fb3f5a2 commit 4f1d70c

11 files changed

+267
-57
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import { assert } from 'chai'
2+
import { Account, ContractHandler, Nevermined, didZeroX, generateId, zeroX } from '../../src'
3+
import { config } from '../config'
4+
import { Signer, Transaction, ethers } from 'ethers'
5+
import { sleep } from '../utils/utils'
6+
7+
describe('Lazy registration of assets', () => {
8+
let publisher: Account
9+
let relayer: Account
10+
let publisherSigner: Signer
11+
let relayerSigner: Signer
12+
let nevermined: Nevermined
13+
let didRegistryAbi
14+
let registryContract: ethers.Contract
15+
let functionArgs
16+
17+
const functionName = 'registerDID'
18+
19+
const providers = []
20+
const metadataUrl = 'http://localhost:5000'
21+
const activityId = zeroX(generateId())
22+
const immutableUrl = ''
23+
24+
before(async () => {
25+
nevermined = await Nevermined.getInstance(config)
26+
;[publisher, relayer] = await nevermined.accounts.list()
27+
28+
publisherSigner = await nevermined.accounts.findSigner(publisher.getId())
29+
relayerSigner = await nevermined.accounts.findSigner(relayer.getId())
30+
31+
const networkName = await nevermined.keeper.getNetworkName()
32+
didRegistryAbi = await ContractHandler.getABI(
33+
'DIDRegistry',
34+
config.artifactsFolder,
35+
networkName,
36+
)
37+
registryContract = new ethers.Contract(
38+
didRegistryAbi.address,
39+
didRegistryAbi.abi,
40+
nevermined.web3,
41+
)
42+
registryContract[functionName](didRegistryAbi.address)
43+
})
44+
45+
describe('Ethers :: Lazy registration of assets', () => {
46+
const didSeed = zeroX(generateId())
47+
const checksum = zeroX(generateId())
48+
let fragment
49+
let unsignedTx
50+
let signedTx
51+
52+
it('should be able to generate a tx hash and the signature', async () => {
53+
registryContract.connect(publisherSigner)
54+
55+
functionArgs = [
56+
didSeed,
57+
checksum,
58+
providers.map(zeroX),
59+
metadataUrl,
60+
activityId,
61+
immutableUrl,
62+
]
63+
64+
fragment = await registryContract[functionName].getFragment(...functionArgs)
65+
assert.isDefined(fragment)
66+
67+
unsignedTx = await registryContract[functionName].populateTransaction(...functionArgs)
68+
assert.isDefined(unsignedTx)
69+
70+
console.log(`unsignedTx: `, unsignedTx)
71+
72+
signedTx = await publisherSigner.signTransaction(unsignedTx)
73+
74+
assert.isDefined(signedTx)
75+
console.log(`signedTx: `, JSON.stringify(signedTx))
76+
})
77+
78+
it('should be able to rely the tx and register on-chain', async () => {
79+
const tx = Transaction.from(signedTx)
80+
81+
const gasLimit = await registryContract[functionName].estimateGas(...functionArgs, {
82+
from: relayer.getId(),
83+
})
84+
const feeData = await nevermined.utils.contractHandler.getFeeData()
85+
86+
// const feeData = await nevermined.web3.getFeeData()
87+
88+
tx.chainId = await nevermined.keeper.getNetworkId()
89+
tx.type = 2
90+
tx.nonce = await relayerSigner.getNonce()
91+
tx.gasLimit = gasLimit
92+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
93+
if (Object.keys(feeData).includes('gasPrice'))
94+
tx.gasPrice = Object.values(feeData)['gasPrice']!
95+
else {
96+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
97+
tx.maxFeePerGas = Object.values(feeData)['maxFeePerGas']!
98+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
99+
tx.maxPriorityFeePerGas = Object.values(feeData)['maxPriorityFeePerGas']!
100+
}
101+
102+
console.log(`Deserialized tx: `, JSON.stringify(tx))
103+
104+
const txResponse = await nevermined.web3.broadcastTransaction(tx.serialized)
105+
106+
// const txResponse = await provider.sendTransaction(Transaction.from(signedTx))
107+
108+
assert.isDefined(txResponse)
109+
110+
console.log(`TX Response: `, txResponse)
111+
await sleep(3000)
112+
113+
// const txResult = await nevermined.web3.getTransactionReceipt(txResponse.hash)
114+
// console.log(`TX Result: `, JSON.stringify(txResult))
115+
})
116+
117+
it('the asset should be there created correctly', async () => {
118+
const did = await nevermined.keeper.didRegistry.hashDID(zeroX(didSeed), publisher.getId())
119+
120+
console.log(`DID: `, did)
121+
console.log(`DID Seed: `, didSeed)
122+
123+
const assetRegistry = await nevermined.keeper.didRegistry.getAttributesByDid(did)
124+
125+
assert.equal(assetRegistry.did, didZeroX(did))
126+
assert.equal(assetRegistry.owner, publisher.getId())
127+
})
128+
})
129+
130+
describe.skip('Contracts :: Lazy registration of assets', () => {
131+
const didSeed = `did:nv:${generateId()}`
132+
const checksum = generateId()
133+
134+
it('should be able to generate a tx hash and the signature', async () => {
135+
const _did = await nevermined.keeper.didRegistry.hashDID(didSeed, publisher.getId())
136+
137+
await nevermined.keeper.didRegistry.registerDID(
138+
didSeed,
139+
checksum,
140+
providers,
141+
publisher.getId(),
142+
metadataUrl,
143+
)
144+
})
145+
146+
// it('should be able to rely the tx and register on-chain', async () => {
147+
148+
// })
149+
150+
// it('the asset should be there created correctly', async () => {
151+
152+
// })
153+
})
154+
})

integration/nevermined/Assets.test.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { config } from '../config'
55
import { getAssetPrice, getMetadata } from '../utils'
66
import { Nevermined, Account, MetaData, DDO, AssetPrice, AssetAttributes } from '../../src'
77
import { generateId } from '../../src/utils'
8-
import { PublishMetadata, DIDResolvePolicy } from '../../src/nevermined'
8+
import { PublishMetadataOptions, DIDResolvePolicy } from '../../src/nevermined'
99

1010
let nevermined: Nevermined
1111
let publisher: Account
@@ -60,7 +60,9 @@ describe('Assets', () => {
6060
},
6161
],
6262
})
63-
ddo = await nevermined.assets.create(assetAttributes, publisher, PublishMetadata.IPFS)
63+
ddo = await nevermined.assets.create(assetAttributes, publisher, {
64+
metadata: PublishMetadataOptions.IPFS,
65+
})
6466

6567
assert.isDefined(ddo)
6668
assert.equal(ddo._nvm.versions.length, 1)
@@ -119,7 +121,7 @@ describe('Assets', () => {
119121
ddo.shortId(),
120122
updatedMetadata,
121123
publisher,
122-
PublishMetadata.IPFS,
124+
PublishMetadataOptions.IPFS,
123125
)
124126

125127
const resolvedDDO = await nevermined.assets.resolve(ddo.id, DIDResolvePolicy.ImmutableFirst)

integration/nevermined/NFT1155Api.e2e.test.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ import {
1212
import { config } from '../config'
1313
import { getMetadata } from '../utils'
1414
import {
15+
DIDResolvePolicy,
1516
getRoyaltyAttributes,
16-
PublishMetadata,
17+
PublishMetadataOptions,
1718
RoyaltyKind,
1819
} from '../../src/nevermined/api/AssetsApi'
1920
import { ethers } from 'ethers'
2021
import '../globals'
2122
import { AssetAttributes } from '../../src/models/AssetAttributes'
2223
import { NFTAttributes } from '../../src/models/NFTAttributes'
23-
import { DIDResolvePolicy } from '../../src/nevermined/api/RegistryBaseApi'
2424

2525
chai.use(chaiAsPromised)
2626

@@ -169,7 +169,9 @@ function makeTest(isCustom) {
169169
royaltyAttributes,
170170
preMint: true,
171171
})
172-
ddo = await nevermined.nfts1155.create(nftAttributes, artist, PublishMetadata.IPFS)
172+
ddo = await nevermined.nfts1155.create(nftAttributes, artist, {
173+
metadata: PublishMetadataOptions.IPFS,
174+
})
173175

174176
assert.isDefined(ddo)
175177

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@nevermined-io/sdk",
3-
"version": "2.0.0-rc8",
3+
"version": "2.0.0-rc9",
44
"description": "Javascript SDK for connecting with Nevermined Data Platform ",
55
"main": "./dist/node/sdk.js",
66
"typings": "./dist/node/sdk.d.ts",
@@ -56,7 +56,7 @@
5656
"cross-fetch": "^4.0.0",
5757
"crypto-browserify": "^3.12.0",
5858
"deprecated-decorator": "^0.1.6",
59-
"ethers": "^6.6.5",
59+
"ethers": "^6.7.1",
6060
"graphql": "^16.7.1",
6161
"https-browserify": "^1.0.0",
6262
"jose": "^4.5.1",

src/ddo/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,8 @@ export interface NvmConfig {
502502
networks?: {
503503
[key: string]: boolean
504504
}
505+
506+
lazyRegistrationSignature?: string
505507
}
506508

507509
export enum ImmutableBackends {

src/nevermined/api/AssetsApi.ts

+36-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { TxParameters, RoyaltyScheme } from '../../keeper'
66
import { AssetError, DDOError } from '../../errors'
77
import { Nevermined, apiPath } from '../../sdk'
88
import { ContractTransactionReceipt } from 'ethers'
9-
import { DIDResolvePolicy, RegistryBaseApi } from './RegistryBaseApi'
9+
import { RegistryBaseApi } from './RegistryBaseApi'
1010
import { CreateProgressStep, OrderProgressStep, UpdateProgressStep } from '../ProgressSteps'
1111
import { Providers } from '../Provider'
1212
import { Babysig, AssetAttributes } from '../../models'
@@ -18,13 +18,40 @@ import { Babysig, AssetAttributes } from '../../models'
1818
* - Filecoin, The metadata will be stored in the Metadata/Marketplace API and Filecoin
1919
* - Arweave, The metadata will be stored in the Metadata/Marketplace API and Arweave
2020
*/
21-
export enum PublishMetadata {
21+
export enum PublishMetadataOptions {
2222
OnlyMetadataAPI,
2323
IPFS,
2424
Filecoin,
2525
Arweave,
2626
}
2727

28+
/**
29+
* It specifies if the DID will be published on-chain initially or not.
30+
*/
31+
export enum PublishOnChainOptions {
32+
DIDRegistry, // The DID and the reference to the DDO will be stored in the DIDRegistry contract
33+
OnlyOffchain, // THE DID won't be stored on-chain and will be lazy-registered when needed
34+
}
35+
36+
export class AssetPublicationOptions {
37+
metadata?: PublishMetadataOptions = PublishMetadataOptions.OnlyMetadataAPI
38+
did?: PublishOnChainOptions = PublishOnChainOptions.DIDRegistry
39+
}
40+
41+
/**
42+
* It described the policy to be used when resolving an asset. It has the following options:
43+
* * ImmutableFirst - It checks if there is a reference to an immutable data-store (IPFS, Filecoin, etc) on-chain. If that's the case uses the URL to resolve the Metadata. If not try to resolve the metadata using the URL of the Metadata/Marketplace API
44+
* * MetadataAPIFirst - Try to resolve the metadata from the Marketplace/Metadata API, if it can't tries to resolve using the immutable url
45+
* * OnlyImmutable - Try to resolve the metadata only from the immutable data store URL
46+
* * OnlyMetadataAPI - Try to resolve the metadata only from the Marketplace/Metadata API
47+
*/
48+
export enum DIDResolvePolicy {
49+
ImmutableFirst,
50+
MetadataAPIFirst,
51+
OnlyImmutable,
52+
OnlyMetadataAPI,
53+
}
54+
2855
/**
2956
* Attributes defining the royalties model attached to the asset
3057
*/
@@ -115,7 +142,7 @@ export class AssetsApi extends RegistryBaseApi {
115142
* {@link https://docs.nevermined.io/docs/architecture/nevermined-data}
116143
*
117144
* @param assetAttributes - Attributes describing the asset
118-
* @param publishMetadata - Allows to specify if the metadata should be stored in different backends
145+
* @param publicationOptions - Allows to specify the publication options of the off-chain and the on-chain data. @see {@link PublishOnChainOptions} and {@link PublishMetadataOptions}
119146
* @param publisherAccount - The account publishing the asset
120147
* @param txParams - Optional transaction parameters
121148
* @returns The metadata of the asset created (DDO)
@@ -125,13 +152,16 @@ export class AssetsApi extends RegistryBaseApi {
125152
public create(
126153
assetAttributes: AssetAttributes,
127154
publisherAccount: Account,
128-
publishMetadata: PublishMetadata = PublishMetadata.OnlyMetadataAPI,
155+
publicationOptions: AssetPublicationOptions = {
156+
metadata: PublishMetadataOptions.OnlyMetadataAPI,
157+
did: PublishOnChainOptions.DIDRegistry,
158+
},
129159
txParams?: TxParameters,
130160
): SubscribablePromise<CreateProgressStep, DDO> {
131161
return this.registerNeverminedAsset(
132162
assetAttributes,
133163
publisherAccount,
134-
publishMetadata,
164+
publicationOptions,
135165
undefined,
136166
txParams,
137167
)
@@ -161,7 +191,7 @@ export class AssetsApi extends RegistryBaseApi {
161191
did: string,
162192
metadata: MetaData,
163193
publisherAccount: Account,
164-
publishMetadata: PublishMetadata = PublishMetadata.OnlyMetadataAPI,
194+
publishMetadata: PublishMetadataOptions = PublishMetadataOptions.OnlyMetadataAPI,
165195
txParams?: TxParameters,
166196
): SubscribablePromise<UpdateProgressStep, DDO> {
167197
return this.updateAsset(did, metadata, publisherAccount, publishMetadata, txParams)

src/nevermined/api/ComputeApi.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { InstantiableConfig } from '../../Instantiable.abstract'
55
import { TxParameters } from '../../keeper'
66
import { SubscribablePromise } from '../../utils'
77
import { CreateProgressStep, OrderProgressStep, UpdateProgressStep } from '../ProgressSteps'
8-
import { PublishMetadata } from './AssetsApi'
8+
import { AssetPublicationOptions, PublishMetadataOptions, PublishOnChainOptions } from './AssetsApi'
99
import { RegistryBaseApi } from './RegistryBaseApi'
1010

1111
/**
@@ -33,7 +33,7 @@ export class ComputeApi extends RegistryBaseApi {
3333
* {@link https://docs.nevermined.io/docs/architecture/nevermined-data}
3434
*
3535
* @param assetAttributes - Attributes describing the asset
36-
* @param publishMetadata - Allows to specify if the metadata should be stored in different backends
36+
* @param publicationOptions - Allows to specify the publication options of the off-chain and the on-chain data. @see {@link PublishOnChainOptions} and {@link PublishMetadataOptions}
3737
* @param publisherAccount - The account publishing the asset
3838
* @param txParams - Optional transaction parameters
3939
* @returns The metadata of the asset created (DDO)
@@ -43,7 +43,10 @@ export class ComputeApi extends RegistryBaseApi {
4343
public create(
4444
assetAttributes: AssetAttributes,
4545
publisherAccount: Account,
46-
publishMetadata: PublishMetadata = PublishMetadata.OnlyMetadataAPI,
46+
publicationOptions: AssetPublicationOptions = {
47+
metadata: PublishMetadataOptions.OnlyMetadataAPI,
48+
did: PublishOnChainOptions.DIDRegistry,
49+
},
4750
txParams?: TxParameters,
4851
): SubscribablePromise<CreateProgressStep, DDO> {
4952
const computeService = assetAttributes.services.find((service) => {
@@ -55,7 +58,7 @@ export class ComputeApi extends RegistryBaseApi {
5558
return this.registerNeverminedAsset(
5659
assetAttributes,
5760
publisherAccount,
58-
publishMetadata,
61+
publicationOptions,
5962
undefined,
6063
txParams,
6164
)
@@ -85,7 +88,7 @@ export class ComputeApi extends RegistryBaseApi {
8588
did: string,
8689
metadata: MetaData,
8790
publisherAccount: Account,
88-
publishMetadata: PublishMetadata = PublishMetadata.OnlyMetadataAPI,
91+
publishMetadata: PublishMetadataOptions = PublishMetadataOptions.OnlyMetadataAPI,
8992
txParams?: TxParameters,
9093
): SubscribablePromise<UpdateProgressStep, DDO> {
9194
return this.updateAsset(did, metadata, publisherAccount, publishMetadata, txParams)

0 commit comments

Comments
 (0)