From 6f8b207a8013b7e0cfaa2893726f8f5ca4bc1826 Mon Sep 17 00:00:00 2001 From: Pavan Soratur Date: Fri, 29 Oct 2021 14:56:45 +0530 Subject: [PATCH 1/5] modifies few API response types (#24) --- src/contracts/SafientMain.ts | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/contracts/SafientMain.ts b/src/contracts/SafientMain.ts index be007a1..03bd000 100644 --- a/src/contracts/SafientMain.ts +++ b/src/contracts/SafientMain.ts @@ -1,8 +1,17 @@ -import { ContractABI, ContractAddress, Claim, ClaimType, RecoveryProof, Safe, Signer } from '../types/Types'; +import { + ContractABI, + ContractAddress, + Claim, + ClaimStatus, + ClaimType, + RecoveryProof, + Safe, + Signer, +} from '../types/Types'; import { TransactionResponse } from '@ethersproject/providers'; import { Contract } from '@ethersproject/contracts'; import { BigNumber } from '@ethersproject/bignumber'; -import { formatEther } from '@ethersproject/units'; +import { formatEther, parseEther } from '@ethersproject/units'; import { Logger } from '@ethersproject/logger'; import { Bytes } from 'ethers'; import networks from '../utils/networks.json'; @@ -192,9 +201,9 @@ export class SafientMain { * @param claimId Id of the claim * @returns The status of the claim */ - getClaimStatus = async (safeId: string, claimId: number): Promise => { + getClaimStatus = async (safeId: string, claimId: number): Promise => { try { - const claimStatus: number = await this.contract.getClaimStatus(safeId, claimId); + const claimStatus: ClaimStatus = await this.contract.getClaimStatus(safeId, claimId); return claimStatus; } catch (e: any) { this.logger.throwError(e.message); @@ -294,12 +303,12 @@ export class SafientMain { /** * This function allows the guardians to claim their rewards - * @param funds Total funds need to be claimed in Gwei + * @param funds Total funds need to be claimed in ETH * @returns A transaction response */ claimRewards = async (funds: number): Promise => { try { - this.tx = await this.contract.claimRewards(funds); + this.tx = await this.contract.claimRewards(parseEther(String(funds))); return this.tx; } catch (e: any) { this.logger.throwError(e.message); @@ -309,12 +318,12 @@ export class SafientMain { /** * This function returns the total guardian reward balance of a guardian * @param address The address of the guardian - * @returns The total guardian reward balance + * @returns The total guardian reward balance in ETH */ - getGuardianRewards = async (address: string): Promise => { + getGuardianRewards = async (address: string): Promise => { try { const guardianReward: BigNumber = await this.contract.guardianRewards(address); - return Number(guardianReward); + return Number(formatEther(guardianReward)); } catch (e: any) { this.logger.throwError(e.message); } From 4a2ca660c51ab23c1fcad7163cfbab7962ac0d04 Mon Sep 17 00:00:00 2001 From: Koshik Raj Date: Fri, 29 Oct 2021 15:41:06 +0530 Subject: [PATCH 2/5] update package release flow (#25) --- .github/workflows/publish.yml | 5 +---- docs/static/CNAME | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) create mode 100644 docs/static/CNAME diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1624ba3..26d5e05 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,10 +1,7 @@ name: Safient Claims CD on: - # Trigger only for the master branch and on release - push: - branches: - - main + # Trigger only on a new release release: types: [created] diff --git a/docs/static/CNAME b/docs/static/CNAME new file mode 100644 index 0000000..24ef20c --- /dev/null +++ b/docs/static/CNAME @@ -0,0 +1 @@ +contracts.safient.io \ No newline at end of file From 3d8c0c631d517be63a22692aa23ca5c07f379852 Mon Sep 17 00:00:00 2001 From: Koshik Raj Date: Fri, 29 Oct 2021 15:44:56 +0530 Subject: [PATCH 3/5] updates package version (#26) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 59157b4..94cc262 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@safient/contracts", - "version": "0.1.9", + "version": "0.1.10-alpha", "description": "JavaScript SDK to manage and interact with the safe claims on Safient protocol.", "keywords": [ "Web3", From 6da3c882467c9885967aad48b0961999e8a0e200 Mon Sep 17 00:00:00 2001 From: Pavan Soratur Date: Mon, 8 Nov 2021 17:52:44 +0530 Subject: [PATCH 4/5] #23 - Adds D-day based claim method (#27) * modifies few API response types * adds D day based claiming method * incorporates review comment change requests * updates param docs --- contracts/SafientMain.sol | 45 ++++++++-- contracts/components/Claims.sol | 65 +++++++++++++- contracts/components/Guardians.sol | 1 + contracts/components/Safes.sol | 52 ++++++++++- contracts/libraries/Types.sol | 10 ++- package.json | 2 +- src/abis/SafientMain.json | 2 +- src/contracts/SafientMain.ts | 38 ++++++-- src/types/Types.ts | 7 +- test-sdk/claims.js | 121 ++++++++++++++++++++++++- test/claims.js | 140 +++++++++++++++++++++++++++-- 11 files changed, 454 insertions(+), 29 deletions(-) diff --git a/contracts/SafientMain.sol b/contracts/SafientMain.sol index 044de61..b17fc9c 100644 --- a/contracts/SafientMain.sol +++ b/contracts/SafientMain.sol @@ -40,7 +40,8 @@ contract SafientMain is Safes, Claims, Guardians, IArbitrable { * @param _beneficiary Address of the safe beneficiary * @param _safeId Id of the safe * @param _claimType Type of the claim - * @param _signalingPeriod Signaling time window + * @param _signalingPeriod The time window in seconds within which the creator wants to signal the safe in response to a claim on the safe + * @param _DDay The timestamp in unix epoch milliseconds after which the beneficiary can directly claim the safe * @param _metaEvidence URL of the metaevidence */ function createSafe( @@ -48,6 +49,7 @@ contract SafientMain is Safes, Claims, Guardians, IArbitrable { string memory _safeId, Types.ClaimType _claimType, uint256 _signalingPeriod, + uint256 _DDay, string calldata _metaEvidence ) external payable returns (bool) { return @@ -56,6 +58,7 @@ contract SafientMain is Safes, Claims, Guardians, IArbitrable { _safeId, _claimType, _signalingPeriod, + _DDay, _metaEvidence ); } @@ -65,7 +68,8 @@ contract SafientMain is Safes, Claims, Guardians, IArbitrable { * @param _creator Address of the safe creator * @param _safeId Id of the safe * @param _claimType Type of the claim - * @param _signalingPeriod Signaling time window + * @param _signalingPeriod TThe time window in seconds within which the creator wants to signal the safe in response to a claim on the safe + * @param _DDay The timestamp in unix epoch milliseconds after which the beneficiary can directly claim the safe * @param _metaEvidence URL of the metaevidence */ function syncSafe( @@ -73,6 +77,7 @@ contract SafientMain is Safes, Claims, Guardians, IArbitrable { string memory _safeId, Types.ClaimType _claimType, uint256 _signalingPeriod, + uint256 _DDay, string calldata _metaEvidence ) external payable returns (bool) { return @@ -81,6 +86,7 @@ contract SafientMain is Safes, Claims, Guardians, IArbitrable { _safeId, _claimType, _signalingPeriod, + _DDay, _metaEvidence ); } @@ -130,8 +136,18 @@ contract SafientMain is Safes, Claims, Guardians, IArbitrable { safe.claimsCount += 1; safes[_safeId] = safe; - } + } else if (safe.claimType == Types.ClaimType.DDayBased) { + Types.DDayBasedClaimData memory data = Types.DDayBasedClaimData( + safe.currentOwner, + safe.beneficiary, + safe.dDay + ); + + _createDDayBasedClaim(_safeId, data); + safe.claimsCount += 1; + safes[_safeId] = safe; + } return true; } @@ -190,17 +206,20 @@ contract SafientMain is Safes, Claims, Guardians, IArbitrable { /** * @notice Get the status of a claim * @param _safeId Id of the safe - * @param _disputeID Id of the claim + * @param _claimId Id of the claim */ - function getClaimStatus(string memory _safeId, uint256 _disputeID) + function getClaimStatus(string memory _safeId, uint256 _claimId) external view returns (Types.ClaimStatus status) { Types.Safe memory safe = safes[_safeId]; - if (safe.claimType == Types.ClaimType.ArbitrationBased) { - Types.Claim memory claim = claims[_disputeID]; + if ( + safe.claimType == Types.ClaimType.ArbitrationBased || + safe.claimType == Types.ClaimType.DDayBased + ) { + Types.Claim memory claim = claims[_claimId]; return claim.status; } else if (safe.claimType == Types.ClaimType.SignalBased) { @@ -267,4 +286,16 @@ contract SafientMain is Safes, Claims, Guardians, IArbitrable { function claimRewards(uint256 _funds) external returns (bool) { return _claimRewards(_funds); } + + /** + * @notice Update the D-Day + * @param _safeId Id of the safe + * @param _DDay The timestamp in unix epoch milliseconds after which the beneficiary can directly claim the safe + */ + function updateDDay(string memory _safeId, uint256 _DDay) + external + returns (bool) + { + return _updateDDay(_safeId, _DDay); + } } diff --git a/contracts/components/Claims.sol b/contracts/components/Claims.sol index fbfe455..cc83582 100644 --- a/contracts/components/Claims.sol +++ b/contracts/components/Claims.sol @@ -38,14 +38,17 @@ contract Claims { Types.ArbitrationBasedClaimData memory data ) { require(data.currentOwner != address(0), "Safe does not exist"); + require( bytes(_safeId).length > 1, "Should provide ID of the safe on threadDB" ); + require( msg.sender == data.beneficiary, "Only beneficiary of the safe can create the claim" ); + require( data.funds >= data.arbitrationCost, "Insufficient funds in the safe to pay the arbitration fee" @@ -58,22 +61,48 @@ contract Claims { Types.SignalBasedClaimData memory data ) { require(data.currentOwner != address(0), "Safe does not exist"); + require( bytes(_safeId).length > 1, "Should provide ID of the safe on threadDB" ); + require( msg.sender == data.beneficiary, "Only beneficiary of the safe can create the claim" ); + require(data.endSignalTime == 0, "Safe end signal time should be zero"); _; } + modifier dDayBasedClaim( + string memory _safeId, + Types.DDayBasedClaimData memory data + ) { + require(data.currentOwner != address(0), "Safe does not exist"); + + require( + bytes(_safeId).length > 1, + "Should provide ID of the safe on threadDB" + ); + + require( + msg.sender == data.beneficiary, + "Only beneficiary of the safe can create the claim" + ); + + require(data.dDay != 0, "D day is not set by the safe's current owner"); + _; + } + modifier evidenceSubmission(uint256 _disputeID, string calldata _evidence) { + Types.Claim memory claim = claims[_disputeID]; + require(_disputeID <= claimsCount, "Claim or Dispute does not exist"); + require(bytes(_evidence).length > 1, "Should provide evidence URI"); - Types.Claim memory claim = claims[_disputeID]; + require( msg.sender == claim.claimedBy, "Only creator of the claim can submit the evidence" @@ -199,6 +228,40 @@ contract Claims { emit CreateClaim(msg.sender, _safeId, claimsCount); } + /** + * @notice Create a new D-Day based claim + * @param _safeId Id of the safe + * @param data Includes safe data + */ + function _createDDayBasedClaim( + string memory _safeId, + Types.DDayBasedClaimData memory data + ) internal dDayBasedClaim(_safeId, data) { + claimsCount += 1; + + if (block.timestamp >= data.dDay) { + claims[claimsCount] = Types.Claim({ + id: claimsCount, + claimedBy: msg.sender, + claimType: Types.ClaimType.DDayBased, + metaEvidenceId: 0, + evidenceGroupId: 0, + status: Types.ClaimStatus.Passed + }); + } else if (block.timestamp < data.dDay) { + claims[claimsCount] = Types.Claim({ + id: claimsCount, + claimedBy: msg.sender, + claimType: Types.ClaimType.DDayBased, + metaEvidenceId: 0, + evidenceGroupId: 0, + status: Types.ClaimStatus.Failed + }); + } + + emit CreateClaim(msg.sender, _safeId, claimsCount); + } + /** * @notice Give a ruling on an arbitration based claim * @param _disputeID Dispute id of the claim diff --git a/contracts/components/Guardians.sol b/contracts/components/Guardians.sol index f978882..8da5053 100644 --- a/contracts/components/Guardians.sol +++ b/contracts/components/Guardians.sol @@ -15,6 +15,7 @@ contract Guardians { modifier withdrawRewards(uint256 _funds) { require(guardianRewards[msg.sender] != 0, "No rewards remaining"); + require( guardianRewards[msg.sender] >= _funds, "Funds requested exceeds the total remaining funds" diff --git a/contracts/components/Safes.sol b/contracts/components/Safes.sol index e1ff640..fbf55ba 100644 --- a/contracts/components/Safes.sol +++ b/contracts/components/Safes.sol @@ -33,10 +33,12 @@ contract Safes { bytes(_safeId).length > 1, "Should provide ID of the safe on threadDB" ); + require( _beneficiary != address(0), "Should provide an beneficiary for the safe" ); + require( msg.sender != _beneficiary, "Safe creator should not be the beneficiary of the safe" @@ -49,10 +51,12 @@ contract Safes { bytes(_safeId).length > 1, "Should provide ID of the safe on threadDB" ); + require( _creator != address(0), "Should provide an creator for the safe" ); + require( msg.sender != _creator, "Safe should be synced by the beneficiary of the safe" @@ -62,35 +66,43 @@ contract Safes { modifier depositSafeFunds(string memory _safeId) { Types.Safe memory safe = safes[_safeId]; + require(safe.currentOwner != address(0), "Safe does not exist"); _; } modifier withdrawSafeFunds(string memory _safeId) { Types.Safe memory safe = safes[_safeId]; + require(safe.currentOwner != address(0), "Safe does not exist"); + require( msg.sender == safe.currentOwner, "Only safe owner can withdraw the deposit balance" ); + require(safe.funds != 0, "No funds remaining in the safe"); _; } modifier signal(string memory _safeId) { Types.Safe memory safe = safes[_safeId]; + require( msg.sender == safe.currentOwner, "Only safe current owner can send the signal" ); + require( safe.endSignalTime != 0, "Safe is not claimed since safe's endSignalTime is zero" ); + require( block.timestamp < safe.endSignalTime, "Signaling period is over" ); + require( safe.latestSignalTime == 0, "Safe is not claimed since safe's latestSignalTime is not zero" @@ -98,6 +110,18 @@ contract Safes { _; } + modifier DDayUpdate(string memory _safeId) { + Types.Safe memory safe = safes[_safeId]; + + require( + msg.sender == safe.currentOwner, + "Only safe current owner can updade the D Day" + ); + + require(block.timestamp < safe.dDay, "DDay has already passed"); + _; + } + event MetaEvidence(uint256 indexed _metaEvidenceID, string _evidence); event CreateSafe( @@ -111,7 +135,8 @@ contract Safes { * @param _beneficiary Address of the safe beneficiary * @param _safeId Id of the safe * @param _claimType Type of the claim - * @param _signalingPeriod Signaling time window + * @param _signalingPeriod The time window in seconds within which the creator wants to signal the safe in response to a claim on the safe + * @param _DDay The timestamp in unix epoch milliseconds after which the beneficiary can directly claim the safe * @param _metaEvidence URL of the metaevidence */ function _createSafe( @@ -119,6 +144,7 @@ contract Safes { string memory _safeId, Types.ClaimType _claimType, uint256 _signalingPeriod, + uint256 _DDay, string calldata _metaEvidence ) internal createSafeByCreator(_safeId, _beneficiary) returns (bool) { if (_claimType == Types.ClaimType.ArbitrationBased) { @@ -135,6 +161,7 @@ contract Safes { signalingPeriod: _signalingPeriod, endSignalTime: 0, latestSignalTime: 0, + dDay: _DDay, claimType: _claimType, metaEvidenceId: metaEvidenceID, claimsCount: 0, @@ -156,7 +183,8 @@ contract Safes { * @param _creator Address of the safe creator * @param _safeId Id of the safe * @param _claimType Type of the claim - * @param _signalingPeriod Signaling time window + * @param _signalingPeriod The time window in seconds within which the creator wants to signal the safe in response to a claim on the safe + * @param _DDay The timestamp in unix epoch milliseconds after which the beneficiary can directly claim the safe * @param _metaEvidence URL of the metaevidence */ function _syncSafe( @@ -164,6 +192,7 @@ contract Safes { string memory _safeId, Types.ClaimType _claimType, uint256 _signalingPeriod, + uint256 _DDay, string calldata _metaEvidence ) internal syncSafeByBeneficiary(_safeId, _creator) returns (bool) { if (_claimType == Types.ClaimType.ArbitrationBased) { @@ -180,6 +209,7 @@ contract Safes { signalingPeriod: _signalingPeriod, endSignalTime: 0, latestSignalTime: 0, + dDay: _DDay, claimType: _claimType, metaEvidenceId: metaEvidenceID, claimsCount: 0, @@ -257,4 +287,22 @@ contract Safes { return true; } + + /** + * @notice Update the D-Day + * @param _safeId Id of the safe + * @param _DDay The timestamp in unix epoch milliseconds after which the beneficiary can directly claim the safe + */ + function _updateDDay(string memory _safeId, uint256 _DDay) + internal + DDayUpdate(_safeId) + returns (bool) + { + Types.Safe memory safe = safes[_safeId]; + + safe.dDay = _DDay; + safes[_safeId] = safe; + + return true; + } } diff --git a/contracts/libraries/Types.sol b/contracts/libraries/Types.sol index 93f69c3..b4a06ac 100644 --- a/contracts/libraries/Types.sol +++ b/contracts/libraries/Types.sol @@ -18,7 +18,8 @@ library Types { enum ClaimType { SignalBased, - ArbitrationBased + ArbitrationBased, + DDayBased } struct Safe { @@ -29,6 +30,7 @@ library Types { uint256 signalingPeriod; uint256 endSignalTime; uint256 latestSignalTime; + uint256 dDay; ClaimType claimType; uint256 metaEvidenceId; uint256 claimsCount; @@ -64,4 +66,10 @@ library Types { uint256 metaEvidenceId; uint256 funds; } + + struct DDayBasedClaimData { + address currentOwner; + address beneficiary; + uint256 dDay; + } } diff --git a/package.json b/package.json index 94cc262..6d633a1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@safient/contracts", - "version": "0.1.10-alpha", + "version": "0.1.11-alpha", "description": "JavaScript SDK to manage and interact with the safe claims on Safient protocol.", "keywords": [ "Web3", diff --git a/src/abis/SafientMain.json b/src/abis/SafientMain.json index eb5fa75..9fc0838 100644 --- a/src/abis/SafientMain.json +++ b/src/abis/SafientMain.json @@ -1 +1 @@ -{"abi":[{"inputs":[{"internalType":"contract IArbitrator","name":"_arbitrator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"createdBy","type":"address"},{"indexed":true,"internalType":"string","name":"safeId","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"CreateClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"createdBy","type":"address"},{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":true,"internalType":"uint256","name":"metaEvidenceId","type":"uint256"}],"name":"CreateSafe","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IArbitrator","name":"_arbitrator","type":"address"},{"indexed":true,"internalType":"uint256","name":"_disputeID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_metaEvidenceID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_evidenceGroupID","type":"uint256"}],"name":"Dispute","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IArbitrator","name":"_arbitrator","type":"address"},{"indexed":true,"internalType":"uint256","name":"_evidenceGroupID","type":"uint256"},{"indexed":true,"internalType":"address","name":"_party","type":"address"},{"indexed":false,"internalType":"string","name":"_evidence","type":"string"}],"name":"Evidence","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_metaEvidenceID","type":"uint256"},{"indexed":false,"internalType":"string","name":"_evidence","type":"string"}],"name":"MetaEvidence","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IArbitrator","name":"_arbitrator","type":"address"},{"indexed":true,"internalType":"uint256","name":"_disputeID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_ruling","type":"uint256"}],"name":"Ruling","type":"event"},{"inputs":[],"name":"arbitrator","outputs":[{"internalType":"contract IArbitrator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_funds","type":"uint256"}],"name":"claimRewards","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"claims","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"claimedBy","type":"address"},{"internalType":"enum Types.ClaimType","name":"claimType","type":"uint8"},{"internalType":"uint256","name":"metaEvidenceId","type":"uint256"},{"internalType":"uint256","name":"evidenceGroupId","type":"uint256"},{"internalType":"enum Types.ClaimStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_safeId","type":"string"},{"internalType":"string","name":"_evidence","type":"string"}],"name":"createClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"},{"internalType":"string","name":"_safeId","type":"string"},{"internalType":"enum Types.ClaimType","name":"_claimType","type":"uint8"},{"internalType":"uint256","name":"_signalingPeriod","type":"uint256"},{"internalType":"string","name":"_metaEvidence","type":"string"}],"name":"createSafe","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"_safeId","type":"string"}],"name":"depositFunds","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"evidenceGroupID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_safeId","type":"string"},{"internalType":"uint256","name":"_disputeID","type":"uint256"}],"name":"getClaimStatus","outputs":[{"internalType":"enum Types.ClaimStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_message","type":"string"},{"internalType":"bytes","name":"_signature","type":"bytes"},{"components":[{"internalType":"bytes32","name":"secretHash","type":"bytes32"},{"internalType":"address","name":"guardianAddress","type":"address"}],"internalType":"struct Types.RecoveryProof[]","name":"_guardianproof","type":"tuple[]"},{"internalType":"string[]","name":"_secrets","type":"string[]"},{"internalType":"string","name":"_safeId","type":"string"}],"name":"guardianProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"guardianRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metaEvidenceID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_disputeID","type":"uint256"},{"internalType":"uint256","name":"_ruling","type":"uint256"}],"name":"rule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rulingOptions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"safes","outputs":[{"internalType":"string","name":"id","type":"string"},{"internalType":"address","name":"createdBy","type":"address"},{"internalType":"address","name":"currentOwner","type":"address"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"signalingPeriod","type":"uint256"},{"internalType":"uint256","name":"endSignalTime","type":"uint256"},{"internalType":"uint256","name":"latestSignalTime","type":"uint256"},{"internalType":"enum Types.ClaimType","name":"claimType","type":"uint8"},{"internalType":"uint256","name":"metaEvidenceId","type":"uint256"},{"internalType":"uint256","name":"claimsCount","type":"uint256"},{"internalType":"uint256","name":"funds","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"safesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_safeId","type":"string"}],"name":"sendSignal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_disputeID","type":"uint256"},{"internalType":"string","name":"_evidence","type":"string"}],"name":"submitEvidence","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"string","name":"_safeId","type":"string"},{"internalType":"enum Types.ClaimType","name":"_claimType","type":"uint8"},{"internalType":"uint256","name":"_signalingPeriod","type":"uint256"},{"internalType":"string","name":"_metaEvidence","type":"string"}],"name":"syncSafe","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"_safeId","type":"string"}],"name":"withdrawFunds","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]} \ No newline at end of file +{"abi":[{"inputs":[{"internalType":"contract IArbitrator","name":"_arbitrator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"createdBy","type":"address"},{"indexed":true,"internalType":"string","name":"safeId","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"CreateClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"createdBy","type":"address"},{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":true,"internalType":"uint256","name":"metaEvidenceId","type":"uint256"}],"name":"CreateSafe","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IArbitrator","name":"_arbitrator","type":"address"},{"indexed":true,"internalType":"uint256","name":"_disputeID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_metaEvidenceID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_evidenceGroupID","type":"uint256"}],"name":"Dispute","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IArbitrator","name":"_arbitrator","type":"address"},{"indexed":true,"internalType":"uint256","name":"_evidenceGroupID","type":"uint256"},{"indexed":true,"internalType":"address","name":"_party","type":"address"},{"indexed":false,"internalType":"string","name":"_evidence","type":"string"}],"name":"Evidence","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_metaEvidenceID","type":"uint256"},{"indexed":false,"internalType":"string","name":"_evidence","type":"string"}],"name":"MetaEvidence","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IArbitrator","name":"_arbitrator","type":"address"},{"indexed":true,"internalType":"uint256","name":"_disputeID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_ruling","type":"uint256"}],"name":"Ruling","type":"event"},{"inputs":[],"name":"arbitrator","outputs":[{"internalType":"contract IArbitrator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_funds","type":"uint256"}],"name":"claimRewards","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"claims","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"claimedBy","type":"address"},{"internalType":"enum Types.ClaimType","name":"claimType","type":"uint8"},{"internalType":"uint256","name":"metaEvidenceId","type":"uint256"},{"internalType":"uint256","name":"evidenceGroupId","type":"uint256"},{"internalType":"enum Types.ClaimStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_safeId","type":"string"},{"internalType":"string","name":"_evidence","type":"string"}],"name":"createClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"},{"internalType":"string","name":"_safeId","type":"string"},{"internalType":"enum Types.ClaimType","name":"_claimType","type":"uint8"},{"internalType":"uint256","name":"_signalingPeriod","type":"uint256"},{"internalType":"uint256","name":"_DDay","type":"uint256"},{"internalType":"string","name":"_metaEvidence","type":"string"}],"name":"createSafe","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"_safeId","type":"string"}],"name":"depositFunds","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"evidenceGroupID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_safeId","type":"string"},{"internalType":"uint256","name":"_claimId","type":"uint256"}],"name":"getClaimStatus","outputs":[{"internalType":"enum Types.ClaimStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_message","type":"string"},{"internalType":"bytes","name":"_signature","type":"bytes"},{"components":[{"internalType":"bytes32","name":"secretHash","type":"bytes32"},{"internalType":"address","name":"guardianAddress","type":"address"}],"internalType":"struct Types.RecoveryProof[]","name":"_guardianproof","type":"tuple[]"},{"internalType":"string[]","name":"_secrets","type":"string[]"},{"internalType":"string","name":"_safeId","type":"string"}],"name":"guardianProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"guardianRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metaEvidenceID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_disputeID","type":"uint256"},{"internalType":"uint256","name":"_ruling","type":"uint256"}],"name":"rule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rulingOptions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"safes","outputs":[{"internalType":"string","name":"id","type":"string"},{"internalType":"address","name":"createdBy","type":"address"},{"internalType":"address","name":"currentOwner","type":"address"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"signalingPeriod","type":"uint256"},{"internalType":"uint256","name":"endSignalTime","type":"uint256"},{"internalType":"uint256","name":"latestSignalTime","type":"uint256"},{"internalType":"uint256","name":"dDay","type":"uint256"},{"internalType":"enum Types.ClaimType","name":"claimType","type":"uint8"},{"internalType":"uint256","name":"metaEvidenceId","type":"uint256"},{"internalType":"uint256","name":"claimsCount","type":"uint256"},{"internalType":"uint256","name":"funds","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"safesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_safeId","type":"string"}],"name":"sendSignal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_disputeID","type":"uint256"},{"internalType":"string","name":"_evidence","type":"string"}],"name":"submitEvidence","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"string","name":"_safeId","type":"string"},{"internalType":"enum Types.ClaimType","name":"_claimType","type":"uint8"},{"internalType":"uint256","name":"_signalingPeriod","type":"uint256"},{"internalType":"uint256","name":"_DDay","type":"uint256"},{"internalType":"string","name":"_metaEvidence","type":"string"}],"name":"syncSafe","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"_safeId","type":"string"},{"internalType":"uint256","name":"_DDay","type":"uint256"}],"name":"updateDDay","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_safeId","type":"string"}],"name":"withdrawFunds","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]} \ No newline at end of file diff --git a/src/contracts/SafientMain.ts b/src/contracts/SafientMain.ts index 03bd000..f1e7998 100644 --- a/src/contracts/SafientMain.ts +++ b/src/contracts/SafientMain.ts @@ -64,7 +64,8 @@ export class SafientMain { * @param beneficiaryAddress Address of the beneficiary who can claim to inherit this safe * @param safeId Id of the safe * @param claimType Type of claim the inheritor has go through - * @param signalingPeriod Number of days within which the safe creator is willing to send a signal + * @param signalingPeriod The time window in seconds within which the creator wants to signal the safe in response to a claim on the safe + * @param dDay The timestamp in unix epoch milliseconds after which the beneficiary can directly claim the safe * @param metaevidenceURI IPFS URI pointing to the metaevidence related to general agreement, arbitration details, actors involved etc * @param value Safe maintanence fee in Gwei, minimum arbitration fee required * @returns A transaction response @@ -74,6 +75,7 @@ export class SafientMain { safeId: string, claimType: ClaimType, signalingPeriod: number, + dDay: number, metaevidenceURI: string, value: string ): Promise => { @@ -83,6 +85,7 @@ export class SafientMain { safeId, claimType, signalingPeriod, + dDay, metaevidenceURI, { value, @@ -99,7 +102,8 @@ export class SafientMain { * @param creatorAddress Address of the creator who created the safe offchain * @param safeId Id of the safe * @param claimType Type of claim the inheritor has go through - * @param signalingPeriod Number of days within which the safe creator is willing to send a signal + * @param signalingPeriod The time window in seconds within which the creator wants to signal the safe in response to a claim on the safe + * @param dDay The timestamp in unix epoch milliseconds after which the beneficiary can directly claim the safe * @param metaevidenceURI IPFS URI pointing to the metaevidence related to general agreement, arbitration details, actors involved etc * @param value Safe maintanence fee in Gwei, minimum arbitration fee required * @returns A transaction response @@ -109,13 +113,22 @@ export class SafientMain { safeId: string, claimType: ClaimType, signalingPeriod: number, + dDay: number, metaevidenceURI: string, value: string ): Promise => { try { - this.tx = await this.contract.syncSafe(creatorAddress, safeId, claimType, signalingPeriod, metaevidenceURI, { - value, - }); + this.tx = await this.contract.syncSafe( + creatorAddress, + safeId, + claimType, + signalingPeriod, + dDay, + metaevidenceURI, + { + value, + } + ); return this.tx; } catch (e: any) { this.logger.throwError(e.message); @@ -328,4 +341,19 @@ export class SafientMain { this.logger.throwError(e.message); } }; + + /** + * This function updates the D-Day of a safe + * @param safeId Id of the safe + * @param dDay The timestamp in unix epoch milliseconds after which the beneficiary can directly claim the safe + * @returns A transaction response + */ + updateDDay = async (safeId: string, dDay: number): Promise => { + try { + this.tx = await this.contract.updateDDay(safeId, dDay); + return this.tx; + } catch (e: any) { + this.logger.throwError(e.message); + } + }; } diff --git a/src/types/Types.ts b/src/types/Types.ts index 6682229..4cae249 100644 --- a/src/types/Types.ts +++ b/src/types/Types.ts @@ -26,13 +26,13 @@ export type Claim = { status: ClaimStatus; }; - /** @ignore */ +/** @ignore */ export type ContractAddress = string; - /** @ignore */ +/** @ignore */ export type ContractABI = ContractInterface | object[]; - /** @ignore */ +/** @ignore */ export type Signer = Wallet | JsonRpcSigner; export type RecoveryProof = { @@ -50,4 +50,5 @@ export enum ClaimStatus { export enum ClaimType { SignalBased, ArbitrationBased, + DDayBased, } diff --git a/test-sdk/claims.js b/test-sdk/claims.js index 6a3b05e..4289774 100644 --- a/test-sdk/claims.js +++ b/test-sdk/claims.js @@ -26,7 +26,7 @@ describe('safientMain', async () => { describe('Safient Claims Test Flow', async () => { before(async () => { // Random safe id's - for (let i = 0; i < 3; i++) { + for (let i = 0; i < 5; i++) { safeId.push(Math.random().toString(36).substr(2, 5)); } @@ -61,6 +61,7 @@ describe('safientMain', async () => { safeId[0], Types.ClaimType.ArbitrationBased, 0, // 0 seconds because opting ArbitrationBased + 0, // D day - 0 seconds metaevidenceOrEvidenceURI, String(ethers.utils.parseEther(String(arbitrationFee + guardianFee))) ); @@ -85,6 +86,7 @@ describe('safientMain', async () => { '', Types.ClaimType.ArbitrationBased, 0, + 0, metaevidenceOrEvidenceURI, String(ethers.utils.parseEther(String(arbitrationFee + guardianFee))) ) @@ -97,6 +99,7 @@ describe('safientMain', async () => { safeId[0], Types.ClaimType.ArbitrationBased, 0, + 0, metaevidenceOrEvidenceURI, String(ethers.utils.parseEther(String(arbitrationFee + guardianFee))) ) @@ -108,7 +111,8 @@ describe('safientMain', async () => { safeCreatorAddress, safeId[0], Types.ClaimType.ArbitrationBased, - 0, // 0 seconds (6 * 0) because opting ArbitrationBased + 0, // 0 seconds + 0, metaevidenceOrEvidenceURI, String(ethers.utils.parseEther(String(arbitrationFee + guardianFee))) ) @@ -126,6 +130,7 @@ describe('safientMain', async () => { safeId[1], Types.ClaimType.SignalBased, 6, // 6 seconds because opting SignalBased + 0, '', // no metaevidence because SignalBased '' // no safe maintenence fee because SignalBased ); @@ -140,13 +145,14 @@ describe('safientMain', async () => { expect(Number(safe.latestSignalTime)).to.equal(0); expect(Number(safe.claimType)).to.equal(0); // SignalBased - // SUCCESS : create another safe with safeId3(for claimType - SignalBased & signal - will signal) + // SUCCESS : create another safe with safeId3 (for claimType - SignalBased & signal - will signal) const safientMain2 = new SafientMain(safeCreatorSigner, chainId); await safientMain2.createSafe( beneficiaryAddress, // 2nd account safeId[2], Types.ClaimType.SignalBased, 6, + 0, '', '' ); @@ -316,5 +322,114 @@ describe('safientMain', async () => { const safientMain = new SafientMain(accountXSigner, chainId); expect(await safientMain.getContractBalance()).to.equal(0); }); + + it('Should allow beneficiaries to create a claim (D-Day based)', async () => { + const safientMainCreator = new SafientMain(safeCreatorSigner, chainId); + const safientMainBeneficiary = new SafientMain(beneficiarySigner, chainId); + const safientMainAccountX = new SafientMain(accountXSigner, chainId); + + const latestBlockNumber = await provider.getBlockNumber(); + const latestBlock = await provider.getBlock(latestBlockNumber); + const now = latestBlock.timestamp; + + // SUCCESS : create another safe with safeId4 (for claimType - DDayBased) with DDay set to 6 seconds + await safientMainCreator.createSafe(beneficiaryAddress, safeId[3], Types.ClaimType.DDayBased, 0, now + 6, '', ''); + + // create a claim - before D-Day (claim should fail) + const tx1 = await safientMainBeneficiary.createClaim(safeId[3], ''); + const txReceipt1 = await tx1.wait(); + const claimId1 = txReceipt1.events[0].args[2]; + const claimID1 = parseInt(claimId1._hex); + + // check claim status (DDayBased) + const safeId4ClaimResult1 = await safientMainAccountX.getClaimStatus(safeId[3], claimID1); + expect(safeId4ClaimResult1).to.equal(2); // claim got Failed (before D-Day) + + // mine a new block after 6 seconds + const mineNewBlock = new Promise((resolve, reject) => { + setTimeout(() => { + resolve(provider.send('evm_mine')); + }, 7000); + }); + const result = await mineNewBlock; + + // create a claim - before D-Day (claim should pass) + const tx2 = await safientMainBeneficiary.createClaim(safeId[3], ''); + const txReceipt2 = await tx2.wait(); + const claimId2 = txReceipt2.events[0].args[2]; + const claimID2 = parseInt(claimId2._hex); + + // check claim status (DDayBased) + const safeId4ClaimResult2 = await safientMainAccountX.getClaimStatus(safeId[3], claimID2); + expect(safeId4ClaimResult2).to.equal(1); // claim got Passed (after D-Day) + }); + + it('Should allow safe current owner to update the D-Day', async () => { + let latestBlockNumber, latestBlock, now; + + const safientMainCreator = new SafientMain(safeCreatorSigner, chainId); + const safientMainBeneficiary = new SafientMain(beneficiarySigner, chainId); + const safientMainAccountX = new SafientMain(accountXSigner, chainId); + + latestBlockNumber = await ethers.provider.getBlockNumber(); + latestBlock = await ethers.provider.getBlock(latestBlockNumber); + now = latestBlock.timestamp; + + // SUCCESS : create another safe with safeId4 (for claimType - DDayBased) with DDay set to 6 seconds + await safientMainCreator.createSafe(beneficiaryAddress, safeId[4], Types.ClaimType.DDayBased, 0, now + 6, '', ''); + + // create a claim - before D-Day (6 seconds) (claim should fail) + const tx1 = await safientMainBeneficiary.createClaim(safeId[4], ''); + const txReceipt1 = await tx1.wait(); + const claimId1 = txReceipt1.events[0].args[2]; + const claimID1 = parseInt(claimId1._hex); + + // check claim status (DDayBased) + const safeId4ClaimResult1 = await safientMainAccountX.getClaimStatus(safeId[4], claimID1); + expect(safeId4ClaimResult1).to.equal(2); // claim got Failed (before D-Day) + + latestBlockNumber = await ethers.provider.getBlockNumber(); + latestBlock = await ethers.provider.getBlock(latestBlockNumber); + now = latestBlock.timestamp; + + // Update the D-Day - 12 seconds + await safientMainCreator.updateDDay(safeId[4], now + 12); // update the D-Day to 12 seconds from the time of updating + + // mine a new block after 10 seconds + const mineNewBlock1 = new Promise((resolve, reject) => { + setTimeout(() => { + resolve(ethers.provider.send('evm_mine')); + }, 8000); + }); + const result1 = await mineNewBlock1; + + // create a claim - before D-Day (12 seconds) (claim should fail) + const tx2 = await safientMainBeneficiary.createClaim(safeId[4], ''); + const txReceipt2 = await tx2.wait(); + const claimId2 = txReceipt2.events[0].args[2]; + const claimID2 = parseInt(claimId2._hex); + + // check claim status (DDayBased) + const safeId4ClaimResult2 = await safientMainAccountX.getClaimStatus(safeId[4], claimID2); + expect(safeId4ClaimResult2).to.equal(2); // claim got Failed (before D-Day) + + // mine a new block after 2 seconds + const mineNewBlock2 = new Promise((resolve, reject) => { + setTimeout(() => { + resolve(ethers.provider.send('evm_mine')); + }, 4000); + }); + const result2 = await mineNewBlock2; + + // create a claim - after D-Day (10 + 2 = 12 seconds) (claim should pass) + const tx3 = await safientMainBeneficiary.createClaim(safeId[4], ''); + const txReceipt3 = await tx3.wait(); + const claimId3 = txReceipt3.events[0].args[2]; + const claimID3 = parseInt(claimId3._hex); + + // check claim status (DDayBased) + const safeId4ClaimResult3 = await safientMainAccountX.getClaimStatus(safeId[4], claimID3); + expect(safeId4ClaimResult3).to.equal(1); // claim got Passed (after D-Day) + }); }); }); diff --git a/test/claims.js b/test/claims.js index da51d1b..281fdf6 100644 --- a/test/claims.js +++ b/test/claims.js @@ -9,10 +9,13 @@ describe('SafientMain', async () => { const safeId1 = '01234567890'; // ArbitrationBased claim const safeId2 = '01234567891'; // SignalBased claim (owner won't signal) const safeId3 = '01234567892'; // SignalBased claim (owner will signal) + const safeId4 = '01234567893'; // DDayBased claim + const safeId5 = '01234567894'; // DDayBased claim const ClaimType = { SignalBased: 0, ArbitrationBased: 1, + DDayBased: 2, }; describe('SafientMain Test Flow', async () => { @@ -39,7 +42,8 @@ describe('SafientMain', async () => { beneficiary.address, safeId1, ClaimType.ArbitrationBased, - 0, // 0 seconds (6 * 0) because opting ArbitrationBased + 0, // signaling period - 0 seconds + 0, // D day - 0 seconds 'https://bafybeif52vrffdp7m2ip5f44ox552r7p477druj2w4g3r47wpuzdn7235y.ipfs.infura-ipfs.io/', { value: arbitrationFee.toNumber() + ethers.utils.parseEther('0.001').toNumber(), @@ -67,6 +71,7 @@ describe('SafientMain', async () => { safeId1, ClaimType.ArbitrationBased, 0, + 0, 'https://bafybeif52vrffdp7m2ip5f44ox552r7p477druj2w4g3r47wpuzdn7235y.ipfs.infura-ipfs.io/', { value: arbitrationFee.toNumber(), @@ -83,6 +88,7 @@ describe('SafientMain', async () => { safeId1, ClaimType.ArbitrationBased, 0, + 0, 'https://bafybeif52vrffdp7m2ip5f44ox552r7p477druj2w4g3r47wpuzdn7235y.ipfs.infura-ipfs.io/', { value: arbitrationFee.toNumber(), @@ -98,6 +104,7 @@ describe('SafientMain', async () => { safeId2, ClaimType.SignalBased, 6, // 6 seconds because opting SignalBased + 0, '' // no metaevidence because SignalBased ); @@ -115,16 +122,16 @@ describe('SafientMain', async () => { await expect( safientMain .connect(beneficiary) - .syncSafe('0x0000000000000000000000000000000000000000', safeId2, ClaimType.SignalBased, 1, '') + .syncSafe('0x0000000000000000000000000000000000000000', safeId2, ClaimType.SignalBased, 1, 0, '') ).to.be.revertedWith('Should provide an creator for the safe'); // FAILURE : safe creator and beneficiary are same await expect( - safientMain.connect(beneficiary).syncSafe(beneficiary.address, safeId2, ClaimType.SignalBased, 1, '') + safientMain.connect(beneficiary).syncSafe(beneficiary.address, safeId2, ClaimType.SignalBased, 1, 0, '') ).to.be.revertedWith('Safe should be synced by the beneficiary of the safe'); // SUCCESS : create another safe with safeId3(for claimType - SignalBased & signal - will signal) - await safientMain.connect(safeCreator).createSafe(beneficiary.address, safeId3, ClaimType.SignalBased, 6, ''); + await safientMain.connect(safeCreator).createSafe(beneficiary.address, safeId3, ClaimType.SignalBased, 6, 0, ''); }); it('Should allow beneficiaries to create a claim (ArbitrationBased)', async () => { @@ -292,7 +299,7 @@ describe('SafientMain', async () => { expect(await safientMain.getBalance()).to.equal(ethers.utils.parseEther('2')); // 2.002 eth }); - it('Should allow current owner of the to withdraw funds in the safe', async () => { + it('Should allow current owner to withdraw funds in the safe', async () => { // FAILURE : safe does not exist await expect(safientMain.connect(safeCreator).withdrawFunds('123')).to.be.revertedWith('Safe does not exist'); @@ -311,5 +318,128 @@ describe('SafientMain', async () => { 'No funds remaining in the safe' ); }); + + it('Should allow beneficiaries to create a claim (D-Day based)', async () => { + const latestBlockNumber = await ethers.provider.getBlockNumber(); + const latestBlock = await ethers.provider.getBlock(latestBlockNumber); + const now = latestBlock.timestamp; + + // create a safe(for claimType - DDayBased) + await safientMain.connect(safeCreator).createSafe( + beneficiary.address, + safeId4, + ClaimType.DDayBased, + 0, // signaling period - 0 seconds + now + 6, // D day - 6 seconds + '' + ); + + // create a claim - before D-Day (claim should fail) + const tx1 = await safientMain.connect(beneficiary).createClaim(safeId4, ''); + const txReceipt1 = await tx1.wait(); + const claimId1 = txReceipt1.events[0].args[2]; + const claimID1 = parseInt(claimId1._hex); + + // check claim status (DDayBased) + const safeId4ClaimResult1 = await safientMain.connect(accountX).getClaimStatus(safeId4, claimID1); + expect(safeId4ClaimResult1).to.equal(2); // claim got Failed (before D-Day) + + // mine a new block after 6 seconds + const mineNewBlock = new Promise((resolve, reject) => { + setTimeout(() => { + resolve(ethers.provider.send('evm_mine')); + }, 7000); + }); + const result = await mineNewBlock; + + // create a claim - before D-Day (claim should pass) + const tx2 = await safientMain.connect(beneficiary).createClaim(safeId4, ''); + const txReceipt2 = await tx2.wait(); + const claimId2 = txReceipt2.events[0].args[2]; + const claimID2 = parseInt(claimId2._hex); + + // check claim status (DDayBased) + const safeId4ClaimResult2 = await safientMain.connect(accountX).getClaimStatus(safeId4, claimID2); + expect(safeId4ClaimResult2).to.equal(1); // claim got Passed (after D-Day) + + // FAILURE : safe does not exist + await expect(safientMain.connect(beneficiary).createClaim('1234', '')).to.be.revertedWith('Safe does not exist'); + + // FAILURE : only beneficiary of the safe can create the claim + await expect(safientMain.connect(accountX).createClaim(safeId4, '')).to.be.revertedWith( + 'Only beneficiary of the safe can create the claim' + ); + }); + + it('Should allow safe current owner to update the D-Day', async () => { + let latestBlockNumber, latestBlock, now; + + latestBlockNumber = await ethers.provider.getBlockNumber(); + latestBlock = await ethers.provider.getBlock(latestBlockNumber); + now = latestBlock.timestamp; + + // create a safe(for claimType - DDayBased) + await safientMain.connect(safeCreator).createSafe( + beneficiary.address, + safeId5, + ClaimType.DDayBased, + 0, // signaling period - 0 seconds + now + 6, // D day - 6 seconds + '' + ); + + // create a claim - before D-Day (6 seconds) (claim should fail) + const tx1 = await safientMain.connect(beneficiary).createClaim(safeId5, ''); + const txReceipt1 = await tx1.wait(); + const claimId1 = txReceipt1.events[0].args[2]; + const claimID1 = parseInt(claimId1._hex); + + // check claim status (DDayBased) + const safeId5ClaimResult1 = await safientMain.connect(accountX).getClaimStatus(safeId5, claimID1); + expect(safeId5ClaimResult1).to.equal(2); // claim got Failed (before D-Day) + + latestBlockNumber = await ethers.provider.getBlockNumber(); + latestBlock = await ethers.provider.getBlock(latestBlockNumber); + now = latestBlock.timestamp; + + // Update the D-Day - 12 seconds + await safientMain.connect(safeCreator).updateDDay(safeId5, now + 12); // update the D-Day to 12 seconds from the time of updating + + // mine a new block after 8 seconds + const mineNewBlock1 = new Promise((resolve, reject) => { + setTimeout(() => { + resolve(ethers.provider.send('evm_mine')); + }, 8000); + }); + const result1 = await mineNewBlock1; + + // create a claim - before D-Day (12 seconds) (claim should fail) + const tx2 = await safientMain.connect(beneficiary).createClaim(safeId5, ''); + const txReceipt2 = await tx2.wait(); + const claimId2 = txReceipt2.events[0].args[2]; + const claimID2 = parseInt(claimId2._hex); + + // check claim status (DDayBased) + const safeId5ClaimResult2 = await safientMain.connect(accountX).getClaimStatus(safeId5, claimID2); + expect(safeId5ClaimResult2).to.equal(2); // claim got Failed (before D-Day) + + // mine a new block after 4 seconds + const mineNewBlock2 = new Promise((resolve, reject) => { + setTimeout(() => { + resolve(ethers.provider.send('evm_mine')); + }, 4000); + }); + const result2 = await mineNewBlock2; + + // create a claim - after D-Day (10 + 2 = 12 seconds) (claim should pass) + const tx3 = await safientMain.connect(beneficiary).createClaim(safeId5, ''); + const txReceipt3 = await tx3.wait(); + const claimId3 = txReceipt3.events[0].args[2]; + const claimID3 = parseInt(claimId3._hex); + + // check claim status (DDayBased) + const safeId5ClaimResult3 = await safientMain.connect(accountX).getClaimStatus(safeId5, claimID3); + expect(safeId5ClaimResult3).to.equal(1); // claim got Passed (after D-Day) + }); }); }); From 416af8670051c300ee3ea3972cd54aca762edf6b Mon Sep 17 00:00:00 2001 From: Koshik Raj Date: Fri, 21 Jan 2022 10:44:42 +0530 Subject: [PATCH 5/5] updates testnet contract addresses (#29) --- package.json | 8 ++++---- src/utils/networks.json | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 6d633a1..a8f68df 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@safient/contracts", - "version": "0.1.11-alpha", + "version": "0.1.12-alpha", "description": "JavaScript SDK to manage and interact with the safe claims on Safient protocol.", "keywords": [ "Web3", @@ -40,10 +40,10 @@ "devDependencies": { "@types/fs-extra": "^9.0.13", "@types/node": "^15.6.1", + "chalk": "^2.4.2", "prettier-plugin-solidity": "*", "typedoc": "^0.22.4", - "typescript": "^4.2.4", - "chalk": "^2.4.2" + "typescript": "^4.2.4" }, "publishConfig": { "access": "public" @@ -53,7 +53,7 @@ "@ethersproject/bignumber": "^5.2.0", "@ethersproject/contracts": "^5.0.5", "@ethersproject/logger": "^5.2.0", - "@ethersproject/providers": "^5.2.0", + "@ethersproject/providers": "^5.4.4", "@ethersproject/units": "^5.2.0", "@nomiclabs/hardhat-ethers": "^2.0.2", "@nomiclabs/hardhat-waffle": "^2.0.1", diff --git a/src/utils/networks.json b/src/utils/networks.json index 62a49c8..7549946 100644 --- a/src/utils/networks.json +++ b/src/utils/networks.json @@ -23,8 +23,8 @@ "kovan": { "chainId": 42, "addresses": { - "AutoAppealableArbitrator": "0xf54D6b97749ECD28F9EbF836Ed9cE0C387a2f0A1", - "SafientMain": "0xefa7ECd3cd8c2bFe71E8790Da8ce3FeE945044A7" + "AutoAppealableArbitrator": "0x823E2b7623aD287819674548f43F8965F38B2626", + "SafientMain": "0x8C2FA3dE952f5A1c463af0Fb42a9A812D3Ffe9e3" } }, "ropsten": {