diff --git a/middleware/thread.config b/middleware/thread.config index a3ac142..ea2792e 100644 --- a/middleware/thread.config +++ b/middleware/thread.config @@ -1 +1 @@ -{"threadId":[1,85,29,234,10,53,7,157,97,192,61,180,56,48,2,22,47,84,9,196,26,127,17,14,50,178,218,79,196,82,4,198,107,129]} \ No newline at end of file +{"threadId":[1,85,187,90,47,202,196,33,70,132,16,200,55,153,171,34,20,16,177,239,202,241,34,186,30,239,14,95,27,14,223,55,109,84]} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 55c2d01..ea222cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,18 @@ { "name": "@safient/core", - "version": "0.1.21-alpha.4", + "version": "0.1.21-alpha.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@safient/core", - "version": "0.1.21-alpha.4", + "version": "0.1.21-alpha.5", "dependencies": { "@ceramicnetwork/http-client": "^1.5.3", "@ceramicstudio/idx": "^0.12.0", "@ceramicstudio/idx-tools": "^0.10.0", "@ethersproject/providers": "^5.4.4", - "@safient/contracts": "^0.1.18-alpha", + "@safient/contracts": "^0.1.19-alpha", "@stablelib/random": "^1.0.1", "@textile/hub": "^6.3.1", "bcryptjs": "^2.4.3", @@ -1592,9 +1592,9 @@ } }, "node_modules/@safient/contracts": { - "version": "0.1.18-alpha", - "resolved": "https://registry.npmjs.org/@safient/contracts/-/contracts-0.1.18-alpha.tgz", - "integrity": "sha512-gfZN7qq/7Ci1yWRQMg8+srGESUWc5Q9q9Rd/sITtDs6xblIHhx/c0nm7F/D/TTafBOQk1RdZKIQw7iB4um43pg==", + "version": "0.1.19-alpha", + "resolved": "https://registry.npmjs.org/@safient/contracts/-/contracts-0.1.19-alpha.tgz", + "integrity": "sha512-3LiE3pfOMctFpKPOBorCHBAAVzA4jCc3ltK/PoU7X+Mw7nv5MaXvFDbX90YPrWExBorFxuNhIP8mhMDIHk6R7w==", "dependencies": { "@ethersproject/address": "^5.2.0", "@ethersproject/bignumber": "^5.2.0", @@ -18363,9 +18363,9 @@ } }, "@safient/contracts": { - "version": "0.1.18-alpha", - "resolved": "https://registry.npmjs.org/@safient/contracts/-/contracts-0.1.18-alpha.tgz", - "integrity": "sha512-gfZN7qq/7Ci1yWRQMg8+srGESUWc5Q9q9Rd/sITtDs6xblIHhx/c0nm7F/D/TTafBOQk1RdZKIQw7iB4um43pg==", + "version": "0.1.19-alpha", + "resolved": "https://registry.npmjs.org/@safient/contracts/-/contracts-0.1.19-alpha.tgz", + "integrity": "sha512-3LiE3pfOMctFpKPOBorCHBAAVzA4jCc3ltK/PoU7X+Mw7nv5MaXvFDbX90YPrWExBorFxuNhIP8mhMDIHk6R7w==", "requires": { "@ethersproject/address": "^5.2.0", "@ethersproject/bignumber": "^5.2.0", diff --git a/package.json b/package.json index 34de838..f0d2a5f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@safient/core", - "version": "0.1.21-alpha.4", + "version": "0.1.21-alpha.5", "description": "JavaScript SDK to manage safes and interact with Safient protocol.", "keywords": [ "Web3", @@ -37,7 +37,7 @@ "@ceramicstudio/idx": "^0.12.0", "@ceramicstudio/idx-tools": "^0.10.0", "@ethersproject/providers": "^5.4.4", - "@safient/contracts": "^0.1.18-alpha", + "@safient/contracts": "^0.1.19-alpha", "@stablelib/random": "^1.0.1", "@textile/hub": "^6.3.1", "bcryptjs": "^2.4.3", diff --git a/src/SafientCore.ts b/src/SafientCore.ts index e3bcb48..3ec5349 100644 --- a/src/SafientCore.ts +++ b/src/SafientCore.ts @@ -223,18 +223,20 @@ export class SafientCore { guardian, }; + this.userData = data; + const result: UserResponse = await createUser( data, this.connection.idx?.id! ); if (result.status === false) { - const ceramicResult = await idx?.set( - this.ceramicDefintions.definitions.profile, - { - name: details?.name, - email: details?.email, - } - ); + // const ceramicResult = await idx?.set( + // this.ceramicDefintions.definitions.profile, + // { + // name: details?.name, + // email: details?.email, + // } + // ); return new SafientResponse({ data: result.data! }); } else { throw new SafientResponse({ error: Errors.UserAlreadyExists }); @@ -342,8 +344,6 @@ export class SafientCore { const guardiansDid: string[] = []; //userQueryDid function // const creatorUser: User[] = await queryUserDid(creatorDID); - const signalPeriod = claimDetails? (claimDetails.type == 0 ? claimDetails.period : 0) : 0; - const dDay = claimDetails? (claimDetails.type == 2 ? claimDetails.period : 0) : 0; const isBeneficiary = typeof beneficiary == 'object' && beneficiary ? Object.keys(beneficiary).length : false if (isBeneficiary && beneficiary) { @@ -393,9 +393,7 @@ export class SafientCore { encSafeData: encryptedSafeData.encryptedData, encSafeKeyShards: encryptedSafeData.shardData, onChain: onChain, - claimType: claimDetails ? claimDetails?.type : null, - signalingPeriod: signalPeriod, - dDay: dDay, + claim: {type: claimDetails ? claimDetails?.type : null, period: claimDetails?.period ? claimDetails.period : 0}, timeStamp: Date.now(), }; @@ -409,16 +407,14 @@ export class SafientCore { guardians: guardiansDid, beneficiary: beneficiaryUser? beneficiaryUser?.did : null, encSafeKey: encryptedSafeData.creatorEncKey, - beneficiaryEncSafeKey: claimDetails ? null : encryptedSafeData.beneficiaryEncKey, + beneficiaryEncSafeKey: claimDetails ? (claimDetails.type !== Types.ClaimType.Expirion ? null : encryptedSafeData.beneficiaryEncKey) : encryptedSafeData.beneficiaryEncKey, encSafeData: encryptedSafeData.encryptedData, stage: SafeStages.ACTIVE, encSafeKeyShards: encryptedSafeData.shardData, decSafeKeyShards: [], claims: [], onChain: onChain, - claimType: claimDetails ? claimDetails?.type : null, - signalingPeriod: signalPeriod, - dDay: dDay, + claim: {type: claimDetails ? claimDetails?.type : null, period: claimDetails?.period ? claimDetails.period : 0}, timeStamp: Date.now(), proofSubmission: false, cid: safeLink, @@ -445,8 +441,7 @@ export class SafientCore { beneficiaryUser.userAddress, safe[0], claimDetails?.type, - signalPeriod, - dDay, + claimDetails ? claimDetails.period : 0, metaDataEvidenceUri, String(ethers.utils.parseEther(String(totalFee))) ); //NOTE: Change the time from 1 to required period here @@ -620,7 +615,7 @@ export class SafientCore { if (parseFloat(etherBalance) >= 0.1) { if (safe.onChain === true) { - if (safe.claimType === Types.ClaimType.ArbitrationBased) { + if (safe.claim.type === Types.ClaimType.ArbitrationBased) { if (safe.stage === SafeStages.ACTIVE) { // Fix the metadata and IPFS stores // evidenceUri = await createClaimEvidenceUri( @@ -632,19 +627,19 @@ export class SafientCore { tx = await this.contract.createClaim(safe._id, evidenceUri); txReceipt = await tx.wait(); } - } else if (safe.claimType === Types.ClaimType.SignalBased) { + } else if (safe.claim.type === Types.ClaimType.SignalBased) { if (safe.stage === SafeStages.ACTIVE) { tx = await this.contract.createClaim(safe._id, ""); txReceipt = await tx.wait(); } - } else if (safe.claimType === Types.ClaimType.DDayBased) { + } else if (safe.claim.type === Types.ClaimType.DDayBased) { tx = await this.contract.createClaim(safe._id, ""); txReceipt = await tx.wait(); } } if (safe.onChain === false) { - if (safe.claimType === Types.ClaimType.ArbitrationBased) { + if (safe.claim.type === Types.ClaimType.ArbitrationBased) { // Fix the metadata and IPFS stores // const metaDataEvidenceUri: string = await createMetaData( // "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", @@ -662,15 +657,14 @@ export class SafientCore { createSafetx = await this.contract.syncSafe( creatorUser[0].userAddress, safeId, - safe.claimType, - safe.signalingPeriod, - safe.dDay, + safe.claim.type, + safe.claim.period, metaDataEvidenceUri, totalFee ); createSafetxReceipt = await createSafetx.wait(); } - } else if (safe.claimType === Types.ClaimType.SignalBased) { + } else if (safe.claim.type === Types.ClaimType.SignalBased) { if (safe.stage === SafeStages.ACTIVE) { const totalFee: string = String( ethers.utils.parseEther(String(this.guardianFee)) @@ -678,24 +672,22 @@ export class SafientCore { createSafetx = await this.contract.syncSafe( creatorUser[0].userAddress, safeId, - safe.claimType, - safe.signalingPeriod, - safe.dDay, + safe.claim.type, + safe.claim.period, "", totalFee ); //Note update time here createSafetxReceipt = await createSafetx.wait(); } - } else if (safe.claimType === Types.ClaimType.DDayBased) { + } else if (safe.claim.type === Types.ClaimType.DDayBased) { const totalFee: string = String( ethers.utils.parseEther(String(this.guardianFee)) ); createSafetx = await this.contract.syncSafe( creatorUser[0].userAddress, safeId, - safe.claimType, - safe.signalingPeriod, - safe.dDay, + safe.claim.type, + safe.claim.period, "", totalFee ); //Note update time here @@ -703,7 +695,7 @@ export class SafientCore { } if (createSafetxReceipt.status === 1) { - if (safe.claimType === Types.ClaimType.ArbitrationBased) { + if (safe.claim.type === Types.ClaimType.ArbitrationBased) { // Fix the metadata and IPFS stores // evidenceUri = await createClaimEvidenceUri( // file, @@ -720,19 +712,19 @@ export class SafientCore { } if (txReceipt.status === 1) { - if (safe.claimType === Types.ClaimType.ArbitrationBased) { + if (safe.claim.type === Types.ClaimType.ArbitrationBased) { if (safe.stage === SafeStages.ACTIVE) { dispute = txReceipt.events[2].args[1]; timeStamp = parseInt(txReceipt.events[2].args[2]._hex); disputeId = parseInt(dispute._hex); } - } else if (safe.claimType === Types.ClaimType.SignalBased) { + } else if (safe.claim.type === Types.ClaimType.SignalBased) { if (safe.stage === SafeStages.ACTIVE) { dispute = txReceipt.events[0].args[1]; timeStamp = parseInt(txReceipt.events[0].args[2]._hex); disputeId = parseInt(dispute._hex); } - } else if (safe.claimType === Types.ClaimType.DDayBased) { + } else if (safe.claim.type === Types.ClaimType.DDayBased) { dispute = txReceipt.events[0].args[1]; timeStamp = parseInt(txReceipt.events[0].args[2]._hex); disputeId = parseInt(dispute._hex); @@ -893,16 +885,23 @@ export class SafientCore { const safeResponse: SafientResponse = await this.getSafe(safeId); const safe = safeResponse.data!; + // TODO: expiration check is temporary until the recovery happens through claim flow if ( safe.stage !== SafeStages.RECOVERED && safe.stage !== SafeStages.CLAIMED && - safe.claimType !== null + safe.claim.type !== null && + safe.claim.type !== Types.ClaimType.Expirion ) { throw new SafientResponse({ error: Errors.StageNotUpdated }); } - - if(safe.claimType !== null) { + + if(safe.claim.type == null || safe.claim.type === Types.ClaimType.Expirion) { + + beneficiaryEncKey = safe.beneficiaryEncSafeKey; + + } + else { const decShards: DecShard[] = safe.decSafeKeyShards; decShards.map((shard) => { shards.push(shard.share); @@ -910,19 +909,15 @@ export class SafientCore { reconstructedSafeData = await this.crypto.reconstructSafeData(shards); beneficiaryEncKey = reconstructedSafeData.beneficiaryEncKey - - } - else { - - beneficiaryEncKey = safe.beneficiaryEncSafeKey; } safeData = await this.crypto.decryptSafeData( beneficiaryEncKey, this.connection, Buffer.from(safe.encSafeData) ); + - if (!safe.claimType) { + if (!safe.claim.type || safe.claim.type == Types.ClaimType.Expirion) { result = JSON.parse(safeData.toString()); return new SafientResponse({ data: result.data }); } diff --git a/src/lib/enums.ts b/src/lib/enums.ts index 6f9e5cc..bc96fef 100644 --- a/src/lib/enums.ts +++ b/src/lib/enums.ts @@ -33,5 +33,6 @@ export const ClaimStages = { export enum ClaimType { SignalBased = 0, ArbitrationBased = 1, - DDayBased = 2 + DDayBased = 2, + ExpirationBased = 3 } \ No newline at end of file diff --git a/src/lib/types.ts b/src/lib/types.ts index 8b68fb2..b2d8660 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -57,9 +57,7 @@ export interface Safe { decSafeKeyShards: DecShard[]; claims: Claim[]; onChain: boolean; - claimType: Types.ClaimType | null; - signalingPeriod: number, - dDay: number, + claim: { type: Types.ClaimType | null, period: number }; timeStamp: number, proofSubmission: boolean, cid: string | null @@ -199,9 +197,7 @@ export type SafeLink = { encSafeData: Buffer; encSafeKeyShards: Shard[]; onChain: boolean; - claimType: Types.ClaimType | null; - signalingPeriod: number, - dDay: number, + claim: { type: Types.ClaimType | null, period: number }; timeStamp: number } export type DecShard = { diff --git a/src/utils/networks.ts b/src/utils/networks.ts index b81396c..e1ca3d1 100644 --- a/src/utils/networks.ts +++ b/src/utils/networks.ts @@ -80,7 +80,7 @@ export const Networks = [ "safientMain": "0x8C2FA3dE952f5A1c463af0Fb42a9A812D3Ffe9e3", "arbitrator": "0x823E2b7623aD287819674548f43F8965F38B2626" }, - "threadId": [1,85,9,109,19,103,1,168,185,231,88,22,247,217,104,122,75,238,32,212,163,63,22,250,183,121,17,21,244,123,136,157,194,213], + "threadId": [1,85,187,90,47,202,196,33,70,132,16,200,55,153,171,34,20,16,177,239,202,241,34,186,30,239,14,95,27,14,223,55,109,84], "ceramic": { "CERAMIC_URL": "https://ceramic-clay.safient.io", "config": { diff --git a/test/scenario4.js b/test/scenario4.js index ce6be45..f9c16b8 100644 --- a/test/scenario4.js +++ b/test/scenario4.js @@ -31,7 +31,7 @@ describe('Scenario 4 - Creating signal based Safe', async () => { const ClaimType = { SignalBased: 0, ArbitrationBased: 1, - DDayBased: 2, + DDayBased: 2 }; before(async () => { @@ -161,7 +161,8 @@ it('Should register a Guardian 3', async () => { {did:beneficiary.data.did}, {type: ClaimType.SignalBased, period: 6}, { name: "On Chain Wallet - signal based", - description: "Hardware wallet instructions"} + description: "Hardware wallet instructions"}, + true ); safeId = safeid.data.id; const safe = await safient.getSafe(safeId); @@ -222,6 +223,7 @@ it('Should register a Guardian 3', async () => { await safient.loginUser(beneficiarySigner); const data = await safient.recoverSafeByBeneficiary(safeId, beneficiary.data.did); + console.log(data) expect(data.data.data.data.hardwareWallet).to.equal('Instruction for hardware wallet'); }); diff --git a/test/scenario5.js b/test/scenario5.js index 484b441..023d8a6 100644 --- a/test/scenario5.js +++ b/test/scenario5.js @@ -158,7 +158,8 @@ describe('Scenario 5 - Creating signal based Safe', async () => { {did:beneficiary.data.did}, {type: ClaimType.SignalBased, period: 10}, { name: "Signal based", - description: "generic safe i.e Signal based"} + description: "generic safe i.e Signal based"}, + true, ); diff --git a/test/scenario8.js b/test/scenario8.js new file mode 100644 index 0000000..7d4d4be --- /dev/null +++ b/test/scenario8.js @@ -0,0 +1,180 @@ +const { Client, PrivateKey, ThreadID, Where } = require('@textile/hub'); +const { randomBytes } = require('crypto'); +const { getThreadId } = require('../dist/utils/threadDb'); +const chai = require('chai'); +const { writeFile } = require('fs').promises; + +const expect = chai.expect; +chai.use(require('chai-as-promised')); + +// Import package +const { SafientCore } = require('../dist/index'); +const { JsonRpcProvider } = require('@ethersproject/providers'); +const { Enums, Errors } = require('../dist/index'); + +describe('Scenario 8 - Creating expiration based safe', async () => { + let creator; + let beneficiary; + let guardianOne; + let guardianTwo; + let guardianThree; + let safeId; + let provider, chainId; + let creatorSigner, beneficiarySigner, guardianOneSigner, guardianTwoSigner, guardianThreeSigner; + let disputeId; + let admin; + let creatorSc, beneficiarySc, guardianOneSc, guardianTwoSc, guardianThreeSc; + + const apiKey = process.env.USER_API_KEY; + const secret = process.env.USER_API_SECRET; + + const ClaimType = { + SignalBased: 0, + ArbitrationBased: 1, + DDayBased: 2, + Expiration: 3, + }; + + before(async () => { + provider = new JsonRpcProvider('http://localhost:8545'); + const network = await provider.getNetwork(); + chainId = network.chainId; + + admin = await provider.getSigner(0); + creatorSigner = await provider.getSigner(1); + beneficiarySigner = await provider.getSigner(2); + guardianOneSigner = await provider.getSigner(3); + guardianTwoSigner = await provider.getSigner(4); + guardianThreeSigner = await provider.getSigner(5); + pseudoAccount = await provider.getSigner(6); + + guardianOneAddress = await guardianOneSigner.getAddress(); + + safient = new SafientCore(Enums.NetworkType.localhost); + }); + +//Step 1: Register all users +it('Should register a Creator', async () => { + + try{ + creator = await safient.createUser(creatorSigner, {name: 'Creator', email: 'creator@test.com'}); + }catch(err){ + if(err.error.code === Errors.UserAlreadyExists.code){ + creator = await safient.loginUser(creatorSigner); + } + } + + try{ + const result = await safient.createUser(creatorSigner, {name: 'Creator', email: 'creator@test.com'}); + }catch(err){ + expect(err.error.code).to.equal(Errors.UserAlreadyExists.code); + } + + const loginUser = await safient.getUser({ did: creator.data.did }); + expect(loginUser.data.name).to.equal('Creator'); + expect(loginUser.data.email).to.equal('creator@test.com'); +}); + +it('Should register a beneficiary', async () => { + + try{ + beneficiary = await safient.createUser(beneficiarySigner, { name: 'beneficiary', email: 'beneficiary@test.com'}); + }catch(err){ + + if(err.error.code === Errors.UserAlreadyExists.code){ + beneficiary = await safient.loginUser(beneficiarySigner); + + } + } + + const loginUser = await safient.getUser({ did: beneficiary.data.did }); + expect(loginUser.data.name).to.equal('beneficiary'); + expect(loginUser.data.email).to.equal('beneficiary@test.com'); +}); + +it('Should register a Guardian 1', async () => { + + try{ + guardianOne = await safient.createUser(guardianOneSigner, {name: 'Guardian 1', email: 'guardianOne@test.com'}, true); + + }catch(err){ + if(err.error.code === Errors.UserAlreadyExists.code){ + guardianOne = await safient.loginUser(guardianOneSigner); + } + } + + const loginUser = await safient.getUser({ email: `guardianOne@test.com` }); + expect(loginUser.data.name).to.equal('Guardian 1'); + expect(loginUser.data.email).to.equal('guardianOne@test.com'); +}); + +it('Should register a Guardian 2', async () => { + + try{ + guardianTwo = await safient.createUser(guardianTwoSigner, {name: 'Guardian 2', email: 'guardianTwo@test.com'}, true); + }catch(err){ + if(err.error.code === Errors.UserAlreadyExists.code){ + guardianTwo = await safient.loginUser(guardianTwoSigner); + + } + } + + const loginUser = await safient.getUser({ email: `guardianTwo@test.com` }); + expect(loginUser.data.name).to.equal('Guardian 2'); + expect(loginUser.data.email).to.equal('guardianTwo@test.com'); +}); + +it('Should register a Guardian 3', async () => { + + try{ + + guardianThree = await safient.createUser(guardianThreeSigner, {name: 'Guardian 3', email: 'guardianThree@test.com'}, true); + } + catch(err){ + if(err.error.code === Errors.UserAlreadyExists.code){ + guardianThree = await safient.loginUser(guardianThreeSigner); + + } +} + + const loginUser = await safient.getUser({ did: guardianThree.data.did }); + expect(loginUser.data.name).to.equal('Guardian 3'); + expect(loginUser.data.email).to.equal('guardianThree@test.com'); +}); + + //should create a safe onChain and offChain + it('Should create Crypto safe with private key as data offchain using expiration claim', async () => { + const secretSafe = { + seedPhrase: null, + privateKey: '0x81993E3b09f9ee1a5a8e5c59c9CF1411E5Bd28ea', + keyStore: null, + }; + const cryptoSafe = { + data: secretSafe, + }; + const safeData = { + data: cryptoSafe, + }; + + await safient.loginUser(creatorSigner); + + const safeid = await safient.createSafe( + safeData, + {did:beneficiary.data.did}, + {type: ClaimType.Expiration, period: 6}, + { name: "Offchain Safient voucher - expiration based", + description: "Safient voucher key"} + ); + safeId = safeid.data.id; + const safe = await safient.getSafe(safeId); + expect(safe.data.creator).to.equal(creator.data.did); + }); + + it('Should recover data for the beneficiary', async () => { + + await safient.loginUser(beneficiarySigner); + const data = await safient.recoverSafeByBeneficiary(safeId, beneficiary.data.did); + expect(data.data.data.data.privateKey).to.equal('0x81993E3b09f9ee1a5a8e5c59c9CF1411E5Bd28ea'); + }); + +});