Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Api for create/update/delete metadata #18

Merged
merged 2 commits into from
Apr 1, 2022
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ build
dist
yarn-error.log
package-lock.json
artifacts
cache
4 changes: 4 additions & 0 deletions packages/composer/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
artifacts
cache
coverage
1 change: 1 addition & 0 deletions packages/composer/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ dist
build
node_modules
yarn.lock
artifacts

# Log files
npm-debug.log*
Expand Down
7 changes: 7 additions & 0 deletions packages/composer/.solhint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "solhint:recommended",
"rules": {
"compiler-version": ["error", "^0.8.0"],
"func-visibility": ["warn", { "ignoreConstructors": true }]
}
}
1 change: 1 addition & 0 deletions packages/composer/.solhintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
2 changes: 2 additions & 0 deletions packages/composer/contracts/Poster.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pragma solidity 0.8.0;
import "Poster/contracts/Poster.sol";
8 changes: 8 additions & 0 deletions packages/composer/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { HardhatUserConfig } from 'hardhat/config'
import '@nomiclabs/hardhat-ethers'

const config: HardhatUserConfig = {
solidity: '0.8.0',
}

export default config
6 changes: 5 additions & 1 deletion packages/composer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc -p tsconfig.build.json",
"test": "jest",
"test": "hardhat compile && jest",
"lint:js": "eslint 'src/*.ts'",
"lint": "yarn lint:js"
},
Expand All @@ -29,17 +29,21 @@
"url": "https://github.com/clrfund/metadata-registry/issues"
},
"devDependencies": {
"@nomiclabs/hardhat-ethers": "^2.0.5",
"@types/jest": "^27.4.0",
"@typescript-eslint/eslint-plugin": "^5.11.0",
"@typescript-eslint/parser": "^5.11.0",
"Poster": "https://github.com/onPoster/contract.git#v7.0.1",
"eslint": "^8.8.0",
"eslint-config-prettier": "^8.3.0",
"hardhat": "^2.8.4",
"jest": "^27.4.7",
"ts-jest": "^27.1.3",
"typescript": "^4.5.5"
},
"dependencies": {
"@urql/core": "^2.4.1",
"ethers": "^5.5.4",
"graphql": "^15.5.1",
"isomorphic-unfetch": "^3.1.0"
}
Expand Down
90 changes: 81 additions & 9 deletions packages/composer/src/MetadataComposer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { createClient, Client, OperationResult } from '@urql/core'
import fetch from 'isomorphic-unfetch'
import { SearchOptions, MetadataResult } from './types'
import { buildSearchQuery } from './utils'
import { SEARCH_FIRST, GET_METADATA_QUERY } from './constants'
import { SEARCH_FIRST, GET_METADATA_QUERY, POSTER, Action } from './constants'
import { ContractTransaction, providers, Contract } from 'ethers'

/**
* Merge an array of subgraph query results from different networks
Expand Down Expand Up @@ -51,19 +52,16 @@ export function mapError(result: OperationResult<any, any>[] | unknown): any {
*/
export class MetadataComposer {
clients: Client[]
urls: string[]
posterAddress: string

/**
* @param urls subgraph urls
*
* @posterAddress address of the poster address, default POSTER.ADDRESS
* @constructor
*/
constructor(urls: string[]) {
this.urls = urls
this.clients = []
for (let i = 0; i < urls.length; i++) {
this.clients.push(createClient({ url: urls[i], fetch }))
}
constructor(urls: string[] = [], posterAddress?: string) {
this.clients = urls.map((url) => createClient({ url, fetch }))
this.posterAddress = posterAddress || POSTER.ADDRESS
}

/**
Expand Down Expand Up @@ -163,4 +161,78 @@ export class MetadataComposer {
return { error }
}
}

/**
* Create a metadata entry in the registry
* @param metadata metadata to add
* @param provider EIP1193 web3 provider
* @returns the added transaction
*/
async create(metadata: any, provider: any): Promise<ContractTransaction> {
const web3Provider = new providers.Web3Provider(provider)
const signer = web3Provider.getSigner()
const contract = new Contract(this.posterAddress, POSTER.ABI, signer)
const content = {
content: [
{
...metadata,
action: Action.create,
type: POSTER.METADATA_TYPE,
},
],
}

return contract.post(JSON.stringify(content), POSTER.METADATA_TAG)
}

/**
* Update a metadata in the registry
* @param metadata metadata to update
* @param provider EIP1193 web3 provider
* @returns the updated transaction
*/
async update(metadata: any, provider: any): Promise<ContractTransaction> {
const web3Provider = new providers.Web3Provider(provider)
const signer = web3Provider.getSigner()
const contract = new Contract(this.posterAddress, POSTER.ABI, signer)

const content = {
content: [
{
...metadata,
action: Action.update,
type: POSTER.METADATA_TYPE,
target: metadata.id,
},
],
}

return contract.post(JSON.stringify(content), POSTER.METADATA_TAG)
}

/**
* Mark a metadata as deleted in the registry
* @param metadataId metadata id to delete
* @param provider EIP1193 provider
* @returns the delete transaction
*/
async delete(
metadataId: string,
provider: any
): Promise<ContractTransaction> {
const web3Provider = new providers.Web3Provider(provider)
const signer = web3Provider.getSigner()
const contract = new Contract(this.posterAddress, POSTER.ABI, signer)
const content = {
content: [
{
target: metadataId,
action: Action.delete,
type: POSTER.METADATA_TYPE,
},
],
}

return contract.post(JSON.stringify(content), POSTER.METADATA_TAG)
}
}
20 changes: 20 additions & 0 deletions packages/composer/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,23 @@ export const GET_METADATA_QUERY = `query($id: String) {
${METADATA_FRAGMENT}
}
}`

// poster address is the same for all networks because it's deployed using the singleton method
export const POSTER = {
ADDRESS: '0x000000000000cd17345801aa8147b8D3950260FF',
ABI: [
'function post(string content, string tag) public',
'event NewPost(address indexed user, string content, string indexed tag)',
],
METADATA_TAG: 'METADATA',
METADATA_TYPE: 'metadata',
}

/**
* Metadata actions
*/
export enum Action {
create = 'create',
update = 'update',
delete = 'delete',
}
54 changes: 54 additions & 0 deletions packages/composer/test/poster.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import hre, { network } from 'hardhat'
import { MetadataComposer } from '../src/index'

describe('Poster', function () {
let registry: MetadataComposer
beforeAll(async () => {
const Poster = await hre.ethers.getContractFactory('Poster')
const poster = await Poster.deploy()
await poster.deployed()

// empty array fo urls because we are not testing subgraph part
const urls: string[] = []
registry = new MetadataComposer(urls, poster.address)
})
test('add metadata', async function () {
const metadata = { name: 'test', description: 'test' }
const tx = await registry.create(metadata, network.provider)
const receipt = await tx.wait()

expect(receipt.events).toEqual(
expect.arrayContaining([
expect.objectContaining({
event: 'NewPost',
}),
])
)
})
test('update metadata', async function () {
const metadata = { name: 'test', description: 'test' }
const tx = await registry.update(metadata, network.provider)
const receipt = await tx.wait()

expect(receipt.events).toEqual(
expect.arrayContaining([
expect.objectContaining({
event: 'NewPost',
}),
])
)
})
test('delete metadata', async function () {
const metadataId = 'someId'
const tx = await registry.delete(metadataId, network.provider)
const receipt = await tx.wait()

expect(receipt.events).toEqual(
expect.arrayContaining([
expect.objectContaining({
event: 'NewPost',
}),
])
)
})
})
6 changes: 4 additions & 2 deletions packages/composer/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
"extends": "./tsconfig.base.json",
"compilerOptions": {
"noEmit": true,
"types": ["node", "jest"]
"types": ["node", "jest"],
"module": "commonjs"
},
"include": ["./src", "./test"]
"include": ["./src", "./test"],
"files": ["./hardhat.config.ts"]
}
Loading