-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
makes checksum,upload,verify argument aware
adds samples for lit, terms acceptance http sample call for signoff Signed-off-by: stadolf <stadolf@gmail.com>
- Loading branch information
1 parent
99683e8
commit ea9c25a
Showing
12 changed files
with
1,697 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
W3S_TOKEN= | ||
W3S_TOKEN= | ||
PRIVATE_KEY= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,46 @@ | ||
# Demo code for IP-NFT implementers | ||
|
||
Some of these examples rely on an API key for [web3.storage](https://web3.storage). Get one and put it in a local .env file. | ||
Some of these examples rely on an API key for [web3.storage](https://web3.storage). Get one and put it in a local ` .env` file. | ||
For the crypto-related scripts to run you need add a _private key_ of an Ethereum account as `PRIVATE_KEY`to the local`.env` file. You can copy this from your Metamask wallet. | ||
|
||
**!!!!NEVER USE ACCOUNTS THAT YOU ALSO WOULD USE ON A MAIN NET HERE!!!!** | ||
|
||
## Checksums | ||
|
||
Compute and verify a file's checksum using [multiformats](https://www.npmjs.com/package/multiformats) | ||
|
||
``` | ||
yarn ts-node ./checksum.mts | ||
yarn ts-node ./checksum.mts <file> | ||
``` | ||
|
||
## Uploads | ||
|
||
uploads sample files to IPFS using web3.storage | ||
uploads files to IPFS using web3.storage | ||
|
||
``` | ||
yarn ts-node ./upload.mts <file> | ||
``` | ||
|
||
## Lit encryption | ||
|
||
Reads and encrypts the provided file. Requires PRIVATE_KEY to sign in with Lit | ||
|
||
``` | ||
yarn ts-node ./lit.mts <agreement.pdf> | ||
``` | ||
|
||
## terms signature | ||
|
||
Reads the agreements from a preliminary ipnft.json file and assembles and signs the required terms acceptance message | ||
|
||
``` | ||
yarn ts-node ./upload.mts | ||
yarn ts-node ./terms.mts <current-ipnft-json> | ||
``` | ||
|
||
## Schema verification | ||
|
||
retrieves JSON schema and IP-NFT metadata from a public location and verifies its validity | ||
|
||
``` | ||
yarn ts-node ./verifyMetadata.mts | ||
yarn ts-node ./verifyMetadata.mts ipfs://bafy... | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import dotenv from "dotenv"; | ||
import * as ethers from "ethers"; | ||
import siwe from "siwe"; | ||
import LitJsSdk, { | ||
LitNodeClientNodeJs, | ||
} from "@lit-protocol/lit-node-client-nodejs"; | ||
import { hexlify, Wallet } from "ethers"; | ||
import { promises as fs } from "node:fs"; | ||
|
||
dotenv.config(); | ||
|
||
const createWallet = (privateKey: string) => { | ||
return new ethers.Wallet(privateKey); | ||
}; | ||
|
||
const obtainAuthSig = async (wallet: Wallet) => { | ||
const address = ethers.getAddress(await wallet.getAddress()); | ||
|
||
// Craft the SIWE message | ||
const domain = "localhost"; | ||
const origin = "https://localhost/login"; | ||
const statement = "This proves that we're controlling our address"; | ||
const siweMessage = new siwe.SiweMessage({ | ||
domain, | ||
address: address, | ||
statement, | ||
uri: origin, | ||
version: "1", | ||
chainId: 5, | ||
}); | ||
const messageToSign = siweMessage.prepareMessage(); | ||
|
||
// Sign the message and format the authSig | ||
const signature = await wallet.signMessage(messageToSign); | ||
|
||
return { | ||
sig: signature, | ||
derivedVia: "web3.eth.personal.sign", | ||
signedMessage: messageToSign, | ||
address: address, | ||
}; | ||
}; | ||
|
||
//see https://developer.litprotocol.com/v2/accessControl/EVM/customContractCalls#must-posess-at-least-one-erc1155-token-with-a-given-token-id | ||
const makeAccessControlConditions = (ipnftId: string) => { | ||
return [ | ||
{ | ||
contractAddress: "0xaf7358576C9F7cD84696D28702fC5ADe33cce0e9", | ||
chain: "goerli", | ||
functionName: "canRead", | ||
functionParams: [":userAddress", ipnftId], | ||
functionAbi: { | ||
inputs: [ | ||
{ | ||
internalType: "address", | ||
name: "reader", | ||
type: "address", | ||
}, | ||
{ | ||
internalType: "uint256", | ||
name: "tokenId", | ||
type: "uint256", | ||
}, | ||
], | ||
name: "canRead", | ||
outputs: [ | ||
{ | ||
internalType: "bool", | ||
name: "", | ||
type: "bool", | ||
}, | ||
], | ||
stateMutability: "view", | ||
type: "function", | ||
}, | ||
returnValueTest: { | ||
key: "", | ||
comparator: "=", | ||
value: "true", | ||
}, | ||
}, | ||
]; | ||
}; | ||
|
||
const encryptWithLit = async ( | ||
client: LitNodeClientNodeJs, | ||
binaryContent: Blob, | ||
wallet: Wallet | ||
) => { | ||
//note that the symmetric key is visible here! | ||
const { encryptedFile, symmetricKey } = await LitJsSdk.encryptFile({ | ||
file: binaryContent, | ||
}); | ||
|
||
const authSig = await obtainAuthSig(wallet); | ||
const accessControlConditions = makeAccessControlConditions("32"); | ||
|
||
const encryptedSymmetricKey = await client.saveEncryptionKey({ | ||
accessControlConditions, | ||
symmetricKey, | ||
authSig, | ||
chain: "goerli", | ||
}); | ||
|
||
return { accessControlConditions, encryptedFile, encryptedSymmetricKey }; | ||
}; | ||
|
||
const main = async () => { | ||
const filePath = process.argv[2]; | ||
//const binaryContent = new TextEncoder().encode("This is the content"); | ||
const fileContent = await fs.readFile(filePath); | ||
|
||
const client = new LitJsSdk.LitNodeClientNodeJs({}); | ||
await client.connect(); | ||
|
||
const wallet = createWallet(process.env.PRIVATE_KEY as string); | ||
|
||
const binaryContent = new Blob([fileContent], { | ||
type: "application/octet-stream", | ||
}); | ||
|
||
const { accessControlConditions, encryptedFile, encryptedSymmetricKey } = | ||
await encryptWithLit(client, binaryContent, wallet); | ||
|
||
await fs.writeFile( | ||
"./uploads/file.enc", | ||
Buffer.from(await encryptedFile.arrayBuffer()) | ||
); | ||
|
||
console.log( | ||
JSON.stringify( | ||
{ | ||
accessControlConditions, | ||
encryptedSymmetricKey: hexlify(encryptedSymmetricKey), | ||
}, | ||
null, | ||
2 | ||
) | ||
); | ||
}; | ||
|
||
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
POST https://testnet.mint.molecule.to/api/signoffMetadata | ||
Content-Type: application/json | ||
|
||
{ | ||
"network": "goerli", | ||
"minter": "0xd1f5B9Dc9F5d55523aB25839f8785aaC74EDE98F", | ||
"to": "0xd1f5B9Dc9F5d55523aB25839f8785aaC74EDE98F", | ||
"reservationId": 2, | ||
"tokenURI": "ipfs://bafkreihsjl25u5irbp33t3ntwwrvsaulajzxbieqpugkcan5bo3bm4romq" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import dotenv from "dotenv"; | ||
import * as ethers from "ethers"; | ||
|
||
import { promises as fs } from "node:fs"; | ||
|
||
dotenv.config(); | ||
|
||
type TermsMessageV1Parameters = { | ||
version: string; | ||
chainId: string; | ||
agreements: Array<{ type: string; content_hash: string }>; | ||
}; | ||
|
||
const TermsMessageV1 = | ||
"I accept the IP-NFT minting terms\n" + | ||
"\nI have read and agreed to the terms of the IP-NFT Assignment Agreement" + | ||
"\nI understand that the IP-NFT represents legal rights to IP and data of the project in my Research Agreement" + | ||
"\nI understand that this in an irreversible and publicly traceable transaction on the Ethereum Blockchain" + | ||
"\nI understand this is beta software and agree to the Terms of Service and assume all risks of minting this IP-NFT" + | ||
"\n" + | ||
"\n{agreements}" + | ||
"\n" + | ||
"\nVersion: {version}" + | ||
"\nChain ID: {chain-id}"; | ||
|
||
export const TermsMessage = (parameters: TermsMessageV1Parameters) => | ||
TermsMessageV1.replace( | ||
"{agreements}", | ||
parameters.agreements | ||
.map((a) => `${a.type} Hash: ${a.content_hash}`) | ||
.join("\n") | ||
) | ||
.replace("{version}", parameters.version) | ||
.replace("{chain-id}", parameters.chainId); | ||
|
||
const createWallet = (privateKey: string) => { | ||
return new ethers.Wallet(privateKey); | ||
}; | ||
|
||
const main = async () => { | ||
const filePath = process.argv[2]; | ||
const utfContent = await fs.readFile(filePath, "utf-8"); | ||
const metadata = JSON.parse(utfContent); | ||
const agreements = metadata.properties.agreements; | ||
|
||
const message = TermsMessage({ | ||
agreements, | ||
chainId: "5", | ||
version: "1", | ||
}); | ||
console.log("Terms Message\n", message); | ||
|
||
const wallet = createWallet(process.env.PRIVATE_KEY as string); | ||
//create an EIP-191 signed message | ||
const termsSig = await wallet.signMessage(message); | ||
|
||
console.log(`Terms Signature (by ${wallet.address}):`, termsSig); | ||
}; | ||
|
||
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.