Using the Relation Content deployed by Relation Protocol, we can store and query a user's identity data. The Relation Content contract is an implementation of the Content contract defined by the Contract Standard.
Construct a Contract object
The address and abi file of the Content contract and the ContentWithSign contract can be accessed via Relation Protocol's list of resources. You can construct a Contract object using "ethers":
We can get the list of content published by a user through the list of tokens the user holds.
constaddr='0x000...';constcontract=getContractInstance()//Query the number of tokens held by an address.constbalance=awaitcontract.balanceOf(addr);var contentList = [];for(var i =0; i < balance;i++){//Query the tokenId a user holds via indexconsttokenId=awaitcontract.tokenOfOwnerByIndex(addr,i);//Query the published content via the tokenIdconstcontent=awaitcontract.contentOf(tokenId);contentList.push(content);}
Pay for someone else's gas fee
A user signs against the data and constructs it into a parameter to be posted on the blockchain. Any address can initiate a transaction with this parameter, with the gas paid by said address.
Publish content(Gas fee can be paid by someone else)
A user can upload the content to be published to Arweave with the following format:
{"content": {"body":"${The body of content}","title":"${The title of content}" }}
The subsequent transaction hash will be used to construct a parameter to be posted on the blockchain. The address paying for the gas fee should use this parameter to call the contract.
import { Bytes } from'@ethersproject/bytes'constcontract=getContractInstance()constcontractWithSign=getContentWithSignContractInstance()constpostContent='zX_Oa1...';constaccounts=awaitethereum.request({ method:'eth_requestAccounts' })let name =awaitcontractWithSign.name();let nonce =awaitcontractWithSign.nonces(accounts[0]);//The time when the signature expires(Unit: second). The following example means the signature will expire 100 seconds after the current time.let deadline =Date.parse(newDate()) /1000+100;let sign =awaitgetSign(awaitbuildPostParams( name,contractWithSign.address.toLowerCase(),contract.address.toLowerCase(), postContent,parseInt(nonce), deadline), accounts[0]);//Construct the parameterlet param = {"sig": {"v":sign.v,"r":sign.r,"s":sign.s,"deadline": deadline},"target":contract.address,"addr": accounts[0],"content": postContent}//In reality, this method will be called by the address paying the gas fee.awaitcontractWithSign.connect(accounts[1]).postWithSign(param);asyncfunctiongetSign(msgParams, signerAddress) {constparams= [signerAddress, msgParams];consttrace=awaithre.network.provider.send("eth_signTypedData_v4", params);returnBytes.splitSignature(trace);}asyncfunctiongetChainId() {returnawaitethereum.request({ method:'eth_chainId', });}functionbuildPostParams(name, contractAddress, contentContractAddress, content, nonce, deadline) {return { domain: { chainId:getChainId(), name: name, verifyingContract: contractAddress, version:'1', },// Defining the message signing data content. message: { target: contentContractAddress, content: content, nonce: nonce, deadline: deadline, },// Refers to the keys of the *types* object below. primaryType:'PostWithSign', types: { EIP712Domain: [ {name:'name', type:'string'}, {name:'version', type:'string'}, {name:'chainId', type:'uint256'}, {name:'verifyingContract', type:'address'}, ], PostWithSign: [ {name:'target', type:'address'}, {name:'content', type:'string'}, {name:'nonce', type:'uint256'}, {name:'deadline', type:'uint256'}, ], }, };}