UNPKG

@rep3/rep3-sdk

Version:

`rep3-sdk` is the ts package for projects to integrate rep3-protocol and services in their projects. This documentation will provide various ways and code snippets for the same. To know more about the protocol head over to our [docs](https://docs.rep3.gg/

886 lines (845 loc) 25.7 kB
import ContractFactory from '../contracts'; import { IContract, IContractAbi, IContractAddress, IContractFactory, IMembershipVoucherV1, IMembershipVoucherV2, IConfig, } from '../types'; // import { eventListener, EventsEnum } from '../utils/eventListeners'; import ProxyV1 from '../contracts/abi/proxy/proxyV1.json'; import Web3 from 'web3' import {ethers} from 'ethers' import { createVoucher, generateData } from '../utils/voucherCreater'; import { getApproversForDao } from '../utils/internalFunctions'; class Rep3 { signer!: any; signerAddress!: string; config!: IConfig; ContractAbi!: IContractAbi; ContractAddress!: IContractAddress; chainId: number; Instance!: IContract; contractInfo!: IContractFactory; ProxyContractInstance!: any; biconomyInstance: any; networkWeb3: any; walletWeb3: any; packageInitialised: boolean; constructor( getSigner: any, walletProvider: typeof Web3.givenProvider, chainId: number, contractAddressConfig: IContractAddress | any, config: IConfig | undefined ) { this.signer = getSigner; this.walletWeb3 = new Web3(walletProvider); this.chainId = chainId; this.ContractAddress = contractAddressConfig; this.packageInitialised = false; if (config) { this.config = config; this.biconomyInstance = new this.config.biconomyInstance( new Web3.providers.HttpProvider(this.config.relayURL), { walletProvider, apiKey: this.config.apiKey, debug: true, contractAddresses: [this.ContractAddress.router], } ); this.networkWeb3 = new Web3(this.biconomyInstance); } } /* * Checks the chain id from the signer * @returns contract instances for forwarder and pocp * @throws error if not deployed in specified class initiated chain Id */ createInstance = async () => { this.contractInfo = new ContractFactory(this.chainId); this.ContractAbi = this.contractInfo.getAbi(); this.signerAddress = await this.signer.getAddress(); if (this.config) { console.log( 'manager', this.ContractAbi?.manager, this.ContractAddress?.manager ); this.biconomyInstance .onEvent(this.biconomyInstance.READY, async () => { this.Instance = { manager: new this.networkWeb3.eth.Contract( this.ContractAbi?.manager, this.ContractAddress?.manager ), beacon: undefined, }; this.packageInitialised = true; console.log( 'Biconomy Initialized successfully!!!!', this.packageInitialised ); }) .onEvent(this.biconomyInstance.ERROR, (error: any, message: any) => { throw { error, message, }; }); return Rep3; } else { this.Instance = { manager: new ethers.Contract( this.ContractAddress?.manager, this.ContractAbi?.manager, this.signer ), // manager:undefined, beacon: undefined, }; return Rep3; } }; /* * @param dao name in string * @param dao symbol in string * @param approver address in array * @returns The transaction receipt is contract call success * @throws "Contract call fails" * @throws "Metamask errors" * @throws "Relayer Api Call errors" */ deploy = async ( daoName: string, daoSymbol: string, approverAddresses: [string], transactionHashCallback: Function, callbackFunction?: Function ) => { //performs relay function if config file is set console.log('here.......', daoName, daoSymbol, approverAddresses); if (this.config) { const domainType = [ { name: 'name', type: 'string' }, { name: 'version', type: 'string' }, { name: 'verifyingContract', type: 'address' }, { name: 'salt', type: 'bytes32' }, ]; const metaTransactionType = [ { name: 'nonce', type: 'uint256' }, { name: 'from', type: 'address' }, { name: 'functionSignature', type: 'bytes' }, ]; let domainData = { name: 'Manager', version: '1', verifyingContract: this.ContractAddress.manager, salt: '0x' + this.chainId.toString(16).padStart(64, '0'), }; const nonce: any = await this.Instance?.manager?.methods .getNonce(this.signerAddress) .call(); console.log('function signature ====>', this.Instance.manager); let functionSignature = this.Instance?.manager?.methods .deployREP3TokenProxy( daoName, daoSymbol, approverAddresses, this.ContractAddress.beacon, this.ContractAddress.router ) .encodeABI(); let message: any = {}; message.nonce = parseInt(nonce); message.from = this.signerAddress; message.functionSignature = functionSignature; const dataToSign = JSON.stringify({ types: { EIP712Domain: domainType, MetaTransaction: metaTransactionType, }, domain: domainData, primaryType: 'MetaTransaction', message: message, }); console.log('data to sign', dataToSign); await this.walletWeb3.currentProvider.sendAsync( { jsonrpc: '2.0', id: 999999999999, method: 'eth_signTypedData_v3', params: [this.signerAddress, dataToSign], }, async (err: any, result: any) => { if (err) { console.log('error caught then catch', err); throw err; } if (result && !result.result) { const signature = result.substring(2); const r = '0x' + signature.substring(0, 64); const s = '0x' + signature.substring(64, 128); const v = parseInt(signature.substring(128, 130), 16); console.log( 'sig', result, 'r', r, 's', s, 'v', v, 'funcSig', functionSignature ); const promiEvent: any = this.Instance?.manager?.methods .executeMetaTransaction( this.signerAddress, functionSignature, r, s, v ) .send({ from: this.signerAddress, }); promiEvent .on('transactionHash', async (hash: any) => { try { await transactionHashCallback(hash); } catch (error) { throw error; } }) .once( 'confirmation', async (_confirmationNumber: any, receipt: any) => { try { if (receipt.status) { console.log('Transaction processed successfully'); if (callbackFunction) { try { await callbackFunction(receipt); } catch (error) { throw error; } } } else { throw { error: 'Transaction failed' }; } } catch (error) { throw error; } } ); } else if (result && result.result) { const signature = result.result.substring(2); const r = '0x' + signature.substring(0, 64); const s = '0x' + signature.substring(64, 128); const v = parseInt(signature.substring(128, 130), 16); const promiEvent: any = this.Instance?.manager?.methods .executeMetaTransaction( this.signerAddress, functionSignature, r, s, v ) .send({ from: this.signerAddress, }); promiEvent .on('transactionHash', async (hash: any) => { try { await transactionHashCallback(hash); } catch (error) { throw error; } }) .once( 'confirmation', async (_confirmationNumber: any, receipt: any) => { try { if (receipt.status) { console.log('Transaction processed successfully'); if (callbackFunction) { try { await callbackFunction(receipt); } catch (error) { throw error; } } } else { throw { error: 'Transaction failed' }; } } catch (error) { throw error; } } ); } else { throw { error: 'Could not get user signature. Check console for error', }; } } ); } else { //performs direct contract call if no config file is set } }; _generateEnd = (to: [string]): number[] => { let endArray: number[] = []; console.log(to) // to.forEach((_, i) => { // if (i + 1 < to.length) { // endArray.push(i + 1); // } // }); return endArray; }; /* * @param dao's contract address in string * @param dao's membershipNFT object of type * @param approver address in array * @returns The transaction receipt is contract call success * @throws "Contract call fails" * @throws "Metamask errors" * @throws "Relayer Api Call errors" */ createMembershipVoucher = async ( proxyAddress: string, levels: [number], categories: [number], // end:[], to: [string], tokenUris: string, signType: string = 'signTypedDatav2.0' ) => { console.log('Address', to); const domain = { name: 'REP3Signer', version: '0.0.1', verifyingContract: proxyAddress, //contract address salt: '0x' + this.chainId.toString(16).padStart(64, '0'), //For mainnet replace 80001 with 137 }; // types is the types const typesV2 = { NFTVoucher: [ { name: 'data', type: 'uint256[]' }, { name: 'end', type: 'uint8[]' }, { name: 'to', type: 'address[]' }, { name: 'tokenUris', type: 'string' }, ], }; // const typesV1 = { // NFTVoucher: [ // { name: 'levelCategory', type: 'uint16[]' }, // { name: 'end', type: 'uint8[]' }, // { name: 'to', type: 'address[]' }, // { name: 'tokenUris', type: 'string' }, // ], // }; let end:number[] if(levels.length>1){ end = this._generateEnd(to); }else{ end = [] } const voucher = createVoucher( levels, categories, end, to, tokenUris, signType ); try { console.log('voucher',domain,voucher) const signature = await this.signer._signTypedData( domain, typesV2, voucher ); const obj = { ...voucher, signature, }; console.log('voucher',obj) return obj; } catch (error) { console.log('voucher',domain,voucher) console.log('error', error); throw error; } }; /* * @param dao's contract address in string * @param claimer's membershipNFT voucher * @param approver address index in number * @returns The transaction receipt is contract call success * @throws "Contract call fails" * @throws "Metamask errors" * @throws "Relayer Api Call errors" */ claimMembership = async ( contractAddress: string, voucher: IMembershipVoucherV1 | IMembershipVoucherV2, approvedAddressIndex: number, signType: string = 'signTypedDatav2.0', gas: number, gasLimit: number, transactionHashCallback: Function, callbackFunction?: Function ) => { if (this.config) { let contract = new this.networkWeb3.eth.Contract( this.ContractAbi.router, this.ContractAddress.router ); let userAddress = this.signerAddress; const proxyContract = new this.walletWeb3.eth.Contract( signType === 'signTypedDatav2.0' ? this.ContractAbi.proxy : ProxyV1, contractAddress ); try { let tx = contract.methods .routeRequest({ to: contractAddress, gas, value: 0, data: proxyContract.methods .claimMembership(voucher, approvedAddressIndex) .encodeABI(), }) .send({ from: userAddress, signatureType: this.biconomyInstance.EIP712_SIGN, gasLimit, }); tx.on('transactionHash', async function(hash: any) { try { await transactionHashCallback(hash); } catch (error) { throw error; } }).once( 'confirmation', async (confirmationNumber: any, receipt: any) => { console.log(receipt); console.log(receipt.transactionHash, confirmationNumber); if (callbackFunction) { try { await callbackFunction(receipt); } catch (error) { throw error; } } } ); } catch (error) { console.log('Catched Error', error); } } else { //performs direct contract call if no config file is set } }; /* * @param dao's contract address in string * @param membershipNFT tokenId in number * @param level in number * @param category in number * @param metadataHash in string * @returns The transaction receipt is contract call success * @throws "Contract call fails" * @throws "Metamask errors" * @throws "Relayer Api Call errors" */ upgradeMembership = async ( contractAddress: string, tokenId: number, level: number, category: number, metaDataHash: string, gas: number, gasLimit: number, transactionHashCallback: Function, callbackFunction?: Function ) => { if (this.config) { let contract = new this.networkWeb3.eth.Contract( this.ContractAbi.router, this.ContractAddress.router ); let userAddress = this.signerAddress; const proxyContract = new this.walletWeb3.eth.Contract( this.ContractAbi.proxy, contractAddress ); const data = generateData([level], [category])[0]; try { let tx = contract.methods .routeRequest({ to: contractAddress, gas, value: 0, data: proxyContract.methods .updateMembership(tokenId, data, metaDataHash) .encodeABI(), }) .send({ from: userAddress, signatureType: this.biconomyInstance.EIP712_SIGN, gasLimit, }); tx.on('transactionHash', async function(hash: any) { try { console.log(`Transaction hash is ${hash}`); await transactionHashCallback(hash); } catch (error) { throw error; } }).once( 'confirmation', async (confirmationNumber: any, receipt: any) => { console.log(receipt); console.log(receipt.transactionHash, confirmationNumber); if (callbackFunction) { console.log('hash tx....', receipt); try { await callbackFunction(receipt); } catch (error) { throw error; } } } ); } catch (error) { console.log('Catched Error', error); } } }; createAssociationBadgeVoucher = async ( proxyAddress: string, memberTokenIds: [string], badgeTypes: [number], tokenUri: [string], nonces: [string], data: [number] ) => { try { const domain = { name: 'REP3Signer', version: '0.0.1', verifyingContract: proxyAddress, //contract address salt: '0x' + this.chainId.toString(16).padStart(64, '0'), //For mainnet replace 80001 with 137 }; const types = { BadgeVoucher: [ { name: 'index', type: 'uint32' }, { name: 'memberTokenIds', type: 'uint256[]' }, { name: 'type_', type: 'uint8[]' }, { name: 'tokenUri', type: 'string' }, { name: 'data', type: 'uint256[]' }, { name: 'nonces', type: 'uint32[]' }, ], }; const badgeVoucher = { index: 0, memberTokenIds: memberTokenIds, type_: badgeTypes, tokenUri: `${tokenUri.toString()},`, data: data, nonces: nonces, }; const signature = await this.signer._signTypedData( domain, types, badgeVoucher ); return { ...badgeVoucher, signature, }; } catch (error) { console.log('error', error); throw error; } }; claimAssociationBadges = async ( contractAddress: string, voucher: any, memberTokenId: number, approveIndex: [number], gas: number, gasLimit: number, transactionHashCallback: Function, callbackFunction?: Function ) => { if (this.config) { let contract = new this.networkWeb3.eth.Contract( this.ContractAbi.router, this.ContractAddress.router ); let userAddress = this.signerAddress; const proxyContract = new this.walletWeb3.eth.Contract( this.ContractAbi.proxy, contractAddress ); try { let tx = contract.methods .routeRequest({ to: contractAddress, gas, value: 0, data: proxyContract.methods .claimBadge(voucher, memberTokenId, approveIndex) .encodeABI(), }) .send({ from: userAddress, signatureType: this.biconomyInstance.EIP712_SIGN, gasLimit, }); tx.on('transactionHash', async function(hash: any) { try { console.log(`Transaction hash is ${hash}`); await transactionHashCallback(hash); } catch (error) { throw error; } }).once( 'confirmation', async (confirmationNumber: any, receipt: any) => { console.log(receipt.transactionHash, confirmationNumber); if (callbackFunction) { console.log('hash tx....', receipt); try { await callbackFunction(receipt); } catch (error) { throw error; } } } ); } catch (error) { console.log('Catched Error', error); } } else { //performs direct contract call if no config file is set // try { // this.ProxyContractInstance = new this.walletWeb3.eth.Contract( // this.ContractAbi?.pocpProxy, // contractAddress // ); // const res = await ( // await this.ProxyContractInstance?.claimMembership( // voucher, // approvedAddressIndex // ) // ).wait(); // if (callbackFunction) { // try { // await eventListener( // this.PocpInstance.pocpManager, // EventsEnum.MembershipClaimed, // callbackFunction, // res.transactionHash // ); // } catch (error) { // throw error; // } // } // return res; // } catch (error) { // throw error; // } } }; updateApprovers = async ( approverAddresses: [string], contractAddress: string, subgraphUrl: string, gas: number, gasLimit: number, transactionHashCallback: Function, callbackFunction?: Function ) => { if (this.config) { let contract = new this.networkWeb3.eth.Contract( this.ContractAbi.router, this.ContractAddress.router ); let userAddress = this.signerAddress; const proxyContract = new this.walletWeb3.eth.Contract( this.ContractAbi.proxy, contractAddress ); try { let currentApprovers: [string] = await getApproversForDao( contractAddress, subgraphUrl ); const approverAddressesInLowercase = approverAddresses.map(ele => ele.toLowerCase() ); const removedApprovers = currentApprovers.filter( ele => !approverAddressesInLowercase.includes(ele.toLowerCase()) ); const newlyAddedApprovers = approverAddressesInLowercase.filter( ele => !currentApprovers.includes(ele.toLowerCase()) ); console.log( 'removed approvers and added approvers', removedApprovers, newlyAddedApprovers ); let tx = contract.methods .routeRequest({ to: contractAddress, gas, value: 0, data: proxyContract.methods .changeApprover(newlyAddedApprovers, removedApprovers) .encodeABI(), }) .send({ from: userAddress, signatureType: this.biconomyInstance.EIP712_SIGN, gasLimit, }); tx.on('transactionHash', async function(hash: any) { try { console.log(`Transaction hash is ${hash}`); await transactionHashCallback(hash); } catch (error) { throw error; } }).once( 'confirmation', async (confirmationNumber: any, receipt: any) => { console.log(receipt.transactionHash, confirmationNumber); if (callbackFunction) { console.log('receipt tx....', receipt); try { await callbackFunction(receipt); } catch (error) { throw error; } } } ); } catch (error) { console.log('Catched Error', error); } } }; /* * @param dao's contract address in string * @param claimer's membershipNFT voucher * @param approver address index in number * @returns The transaction receipt is contract call success * @throws "Contract call fails" * @throws "Metamask errors" * @throws "Relayer Api Call errors" */ directIssueBadgeBatch = async ( contractAddress: string, memberTokenIds: [number], type_: [number], data: [number], arrayOfTokenUri: [string], signType: string, gas: number, gasLimit: number, transactionHashCallback: Function, callbackFunction?: Function ) => { if (this.config) { let contract = new this.networkWeb3.eth.Contract( this.ContractAbi.router, this.ContractAddress.router ); let userAddress = this.signerAddress; const proxyContract = new this.walletWeb3.eth.Contract( signType === 'signTypedDatav2.0' ? this.ContractAbi.proxy : ProxyV1, contractAddress ); try { let tx = contract.methods .routeRequest({ to: contractAddress, gas, value: 0, data: proxyContract.methods .batchIssueBadge( memberTokenIds, type_, data, `${arrayOfTokenUri.toString()},` ) .encodeABI(), }) .send({ from: userAddress, signatureType: this.biconomyInstance.EIP712_SIGN, gasLimit, }); tx.on('transactionHash', async function(hash: any) { try { await transactionHashCallback(hash); } catch (error) { throw error; } }).once( 'confirmation', async (confirmationNumber: any, receipt: any) => { console.log(receipt); console.log(receipt.transactionHash, confirmationNumber); if (callbackFunction) { try { await callbackFunction(receipt); } catch (error) { throw error; } } } ); } catch (error) { console.log('Catched Error', error); } } else { //performs direct contract call if no config file is set const proxyContract = new this.walletWeb3.eth.Contract( signType === 'signTypedDatav2.0' ? this.ContractAbi.proxy : ProxyV1, contractAddress ); proxyContract.methods .batchIssueBadge( memberTokenIds, type_, data, `${arrayOfTokenUri.toString()},` ) .send({ from: this.signerAddress, }) .on('receipt', async (receipt: any) => { try { await transactionHashCallback(receipt); } catch (error) { throw error; } }) .on('error', function(err: any) { console.error('-------err-------', new Error(err).message); throw err; }); } }; } export default Rep3;