From 55a3f58f938e2de2f2ae92dd44af7801e49e4555 Mon Sep 17 00:00:00 2001 From: nanspro Date: Thu, 19 Dec 2019 09:27:35 +0530 Subject: [PATCH 1/3] Adding erasurebay docs --- erasurebay-docs/bay-overview.md | 326 +++++++++++++++++++++++++++++++- 1 file changed, 325 insertions(+), 1 deletion(-) diff --git a/erasurebay-docs/bay-overview.md b/erasurebay-docs/bay-overview.md index 273aad5..56016dd 100644 --- a/erasurebay-docs/bay-overview.md +++ b/erasurebay-docs/bay-overview.md @@ -1,4 +1,328 @@ # ErasureBay Overview -c_oming soon_ +ErasureBay is a dapp on the Erasure protocol. It’s a marketplace for information of any kind. It’s Numerai’s demonstration of the power of Erasure to improve the Web itself. +**How it works** +* Post data to storage that no one owns +* Stake money on your claims. Encrypt them, then reveal them, to prove you knew something. +* Sell them under a smart contract that must be enforced. + +## Step by Step Walkthrough + +Let's see how erasure bay interacts with erasure protocol + +### New User Registration + +- New User connects to Erasure Client. ErasureClient generates asymmetric encryption keys `PubKey`, `PrivKey` +```js +const keypair = ErasureHelper.crypto.asymmetric.generateKeyPair(sig, salt); +``` + +- ErasureClient uploads `PubKey` to `Erasure_Users` +```js +const ethers = require("ethers"); +const ErasureUsersArtifact = require("Erasure_Users.json"); +const user = PubKey; +const data = 16; //any data + +// UserData in bytes +const userData = ethers.utils.keccak256( + ethers.utils.toUtf8Bytes(data.toString()) + ); +// Registering a User +const txn = await ErasureUsersArtifact.from(user).registerUser(userData); +``` +***Erasure_Users.sol*** +```js +function registerUser(bytes memory data) public { + require(!_users.exists(msg.sender), "user already exists"); + + // add user + _users.insert(msg.sender); + + // set metadata + _metadata[msg.sender] = data; + + // emit event + emit UserRegistered(msg.sender, data); +} +``` +Adds user to set of `Users`, sets it metadata and then emits an event saying `UserRegistered` + + +To remove a user just call method `removeUser`, it removes the user/sender from `_users` set then deletes it's metadata from mapping `_metadata` and finally emits an event `UserRemoved` +```js +function removeUser() public { + // require user is registered + require(_users.exists(msg.sender), "user does not exist"); + + // remove user + _users.remove(msg.sender); + + // delete metadata + delete _metadata[msg.sender]; + + // emit event + emit UserRemoved(msg.sender); +} +``` + +To get any user's metadata +```js +function getUserData(address user) public view returns (bytes memory data) { + data = _metadata[user]; +} +``` +### Creating a Post +A Feed_Factory is a factory contract for managing feeds. +- Seller first creates a `Feed` template contract from Feed_Factory by calling method `create` + +```js +function create(bytes memory callData) public returns (address instance) { + // deploy new contract: initialize it & write minimal proxy to runtime. + instance = Spawner._spawn(msg.sender, getTemplate(), callData); + + _createHelper(instance, callData); + + return instance; +} +``` +- It creates a clone of `Feed` template using a nonce, the nonce is same for clones with same calldata. The nonce can also be used to determine the address of the new contract before creation. + +_Blob of abi-encoded calldata is used to initialize the template. It returns the instance address of the clone that was created_ + +- Generates a symmetric encryption key and it's hash +```js +const hexlify = utf8str => + ethers.utils.hexlify(ethers.utils.toUtf8Bytes(utf8str)); + +const nonce = ErasureHelper.crypto.asymmetric.generateNonce() +const symmetricKey = ErasureHelper.crypto.symmetric.generateKey() + +// Uses nonce, symmetricKey and above generated asymmetric key's secret +const keyHash = + ErasureHelper.crypto.asymmetric.secretBox.encryptMessage(symmetricKey, + nonce, keypair.secretKey) +``` + +- Encrypt rawData with the symmetric key and gets it ipfs path +```js +let buf = Buffer.from(rawData); +let dataEncoded = buf.toString('base64'); +const encryptedFile = ErasureHelper.crypto.symmetric.encryptMessage( + symmetricKey, dataEncoded) +const rawHash = await ErasureHelper.ipfs.onlyHash(buf) +const rawDataHash = ErasureHelper.ipfs.hashToHex(rawHash) +``` +- Get encryptedData's ipfs path +```js +const encryptedFileIpfsPath = await ipfs.pinata.pinTextToIPFS(encryptedFile) +``` + +- Preparing metadata +```js +const metaData = { + nonce, + rawDataHash + keyHash, + encryptedFileIpfsPath, +} +``` + +- Submitting proofHash to our `Feed` +```js +const proofHash = await +ErasureHelper.multihash({input:JSON.stringify(metaData), inputType:'raw', +outputType:'digest'}) + +let confirmedTx = await this.submitProof(proofHash) +``` + +Feed contract's submitHash method is called to add this proof as hash to feed. +```js +function submitHash(bytes32 proofHash) public { + // only operator or creator of this template can call submit proofHash + require(Template.isCreator(msg.sender) || + Operated.isOperator(msg.sender), "only operator or creator"); + + // submit proofHash + ProofHashes._submitHash(proofHash); +} +``` + + +ProofHashes.sol +```js +function _submitHash(bytes32 hash) internal { + emit HashSubmitted(hash); // event emitted whenever submits proofHash +} +``` + +- Finally submitting metadata to ipfs +```js +const metadataJsonIpfsPath = await ipfs.pinata.pinJSONToIPFS(metadata) +const metadataHex = ErasureHelper.ipfs.hashToHex(metadataJsonIpfsPath) +``` +### Selling a Post + +Once the post is created, it's time to sell. +- Seller creates `Escrow` using CountdownGriefingEscrow_Factory.create() with `calldata` as parameter. This is exactly same as creating a Feed Template as Feed_Factory and CountdownGriefingEscrow_Factory are both factory contracts and method `create` is a factory method. + +CountdownGriefingEscrow_Factory.sol +```js +constructor(address instanceRegistry, address templateContract) public { + CountdownGriefingEscrow template; + + // here instance type is Escrow + bytes4 instanceType = bytes4(keccak256(bytes('Escrow'))); + // here initSelector is a Escrow template + bytes4 initSelector = template.initialize.selector; + // initializing factory contract + Factory._initialize(instanceRegistry, templateContract, instanceType, initSelector); +} +``` + +`CountdownGriefingEscrow_Factory.create(calldata)` will return a Factory Contract with template Escrow. + +`_data` is a struct Data of this form +```js +struct Data { + address buyer; + address seller; + uint128 paymentAmount; // amount to be deposited by buyer as payment + uint128 stakeAmount; // amount to be staked by seller + EscrowStatus status; + AgreementParams agreementParams; +} +``` +When this escrow template is created, we can provide some params which are then set in _data struct. + +`buyer` and `seller` are optional params, if not provide then the first one to stake amount will become seller, the first one to deposit amount will become buyer. + +EscrowStatus is an enum, `enum EscrowStatus { isOpen, onlyStakeDeposited, onlyPaymentDeposited, isDeposited, isFinalized, isCancelled }` + +- Seller deposits the required stake using `Escrow.depositStake()` + + +```js +function depositStake() public { + // Only seller(the one who created this template) or operator can call + require(isSeller(msg.sender) || Operated.isOperator(msg.sender), "only + seller or operator"); + + // There should be a seller + require(_data.seller != address(0), "seller not yet set"); + + // deposit stake + _depositStake(); +} + +function _depositStake() private { + require(isOpen() || onlyPaymentDeposited(), "can only deposit stake + once"); + + // declare storage variables in memory + address seller = _data.seller; + uint256 stakeAmount = uint256(_data.stakeAmount); + + // Increase the current stake amount + if (stakeAmount != uint256(0)) { + Staking._addStake(seller, msg.sender, stakeAmount); + } + + // emit event + emit StakeDeposited(seller, stakeAmount); + + // If payment is deposited, finalize the escrow + if (onlyPaymentDeposited()) { + _data.status = EscrowStatus.isDeposited; + finalize(); + } else { + _data.status = EscrowStatus.onlyStakeDeposited; + } +} +``` + +- Buyer deposits the required payment using `Escrow.depositPayment()` +```js +function depositPayment() public { + require(isBuyer(msg.sender) || Operated.isOperator(msg.sender), + "only buyer or operator"); + + // restrict state machine + require(_data.buyer != address(0), "buyer not yet set"); + + // deposit payment + _depositPayment(); +} + +function _depositPayment() private { + require(isOpen() || onlyStakeDeposited(), "can only deposit payment + once"); + + // declare storage variables in memory + address buyer = _data.buyer; + uint256 paymentAmount = uint256(_data.paymentAmount); + + // Add the payment as a stake + if (paymentAmount != uint256(0)) { + Staking._addStake(buyer, msg.sender, paymentAmount); + } + + // emit event + emit PaymentDeposited(buyer, paymentAmount); + + // If stake is deposited, start countdown for seller to finalize + if (onlyStakeDeposited()) { + _data.status = EscrowStatus.isDeposited; + Countdown._start(); + } else { + _data.status = EscrowStatus.onlyPaymentDeposited; + } +} +``` + +`Countdown._start()` will start the countdown based on currentblock timestamp, and will return the timestamp at the end of countdown. + +- Retrieve buyer's `PubKey` from Erasure_Users +- Computes encryptedSymKey_Buyer = PubKey_Buyer.encrypt(SymKey) +- Computes metadata +- Finalize escrow with creating a griefing agreement `Agreement` + +Calling `Escrow.finalize()` +(1) Will create the agreement +(2) Transfer the stake and deposit to agreement +(3) Start the countdown for agreement `CountdownGriefing(agreement).startCountdown();` + +- Uploads metadata to ipfs +```js +const metadataJsonIpfsPath = await ipfs.pinata.pinJSONToIPFS(metadata) +const metadataHex = ErasureHelper.ipfs.hashToHex(metadataJsonIpfsPath) +``` + +- Submitting proofHash to buyer +```js +const proofHash = await +ErasureHelper.multihash({input:JSON.stringify(metaData), inputType:'raw', +outputType:'digest'}) + +let tx = Escrow.submitData(proofHash) +``` + +Submitting data to the buyer +```js +function submitData(bytes memory data) public { + require(isSeller(msg.sender) || Operated.isOperator(msg.sender), "only + seller or operator"); + + // Can only submit after finalized + require(isFinalized(), "only after finalized"); + + // emit event + emit DataSubmitted(data); +} +``` + +- Retrives +- Computes +### Revealing a Post From c18e3221bf0e315644dc67a5b3835b3377586438 Mon Sep 17 00:00:00 2001 From: nanspro Date: Fri, 20 Dec 2019 03:36:46 +0530 Subject: [PATCH 2/3] Adding onchain interactions --- erasurebay-docs/bay-overview.md | 117 +++++++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 11 deletions(-) diff --git a/erasurebay-docs/bay-overview.md b/erasurebay-docs/bay-overview.md index 56016dd..de3b10a 100644 --- a/erasurebay-docs/bay-overview.md +++ b/erasurebay-docs/bay-overview.md @@ -1,28 +1,123 @@ -# ErasureBay Overview - -ErasureBay is a dapp on the Erasure protocol. It’s a marketplace for information of any kind. It’s Numerai’s demonstration of the power of Erasure to improve the Web itself. +# Erasure Bay +ErasureBay is a dapp built upon the Erasure protocol. It’s a marketplace for buying/selling information of any kind. It’s Numerai’s demonstration of the power of Erasure to improve the Web itself. **How it works** -* Post data to storage that no one owns +* Post data to storage that no one owns(ex: ipfs) * Stake money on your claims. Encrypt them, then reveal them, to prove you knew something. * Sell them under a smart contract that must be enforced. -## Step by Step Walkthrough + +### State Machine Architecture + +Erasure uses shared registries to establish a single source of truth for the Erasure Protocol. So far, the registries developed are: + +* Erasure_Agreements: To keep track of Griefing templates. +* Erasure_Posts: To keep track of Feed and Post templates +* Erasure_Users: To keep track of users and their data +* Erasure_Escrows + +**Clone Factories** + +Using the Spawner library, every item on Erasure is created as a clone of a previously deployed template. We call these Clone Factories. Every clone is also registered in a registry which provides a single source of truth on the status of the protocol. + +![](https://i.imgur.com/bEUAp0H.png) + +**Staking** + +![](https://i.imgur.com/JELJwhJ.png) + +**Agreements** + +When two parties decide to engage, they begin by staking NMR and agreeing on a set of conditions for punishment. We call this combination of skin in the game and rules of engagement an Erasure_Agreement. + +> Griefing is an example of an Agreement which allows two parties to come to a resolution without a third party arbitrator through punishing one another at a cost. + +Griefing has two main methods: `_grief()` and `setRatio` +- `_grief` returns the cost of the punishment and is taken form the account of the punisher. Therefore requires appropriate ERC-20 token approval +- `setRatio` Set the grief ratio and type for a given staker. The ratio represents the cost in NMR to burn 1 NMR of the counterparty. + +**First example of Griefing is *SimpleGriefing*** +> SimpleGriefing agreement allows a staker to grant permission to a counterparty to punish, reward, or release their stake + +![](https://i.imgur.com/w0ab7n7.png) + +- increaseStake() +Can be called by staker only to increase the stake + +- reward() +Called by the counterparty to increase the stake + +- releaseStake() +Called by the counterparty to release the stake to the staker + +- punish() +Called by the counterparty to punish the staker +```js +function punish(uint256 punishment, bytes memory message) public returns +(uint256 cost) { + // restrict access + require(isCounterparty(msg.sender) || Operated.isOperator(msg.sender), + "only counterparty or operator"); + + // execute griefing + cost = Griefing._grief(msg.sender, _data.staker, punishment, message); +} +``` +`punishment`: amount of NMR (18 decimals) to be burned from the stake +`message`: data to emit as event giving reason for the punishment + + +**Second Example is *CountdownGriefing*** +> CountdownGriefing agreement allows a staker to grant permission to a counterparty to punish, reward, or release their stake until the countdown is completed. +> +![](https://i.imgur.com/DXy1lte.png) + +It behaves similar to SimpleGriefing with an extra touch of a countdown. + +`startCountdown` +Called by the staker to begin countdown to finalize the agreement +```js +function startCountdown() public returns (uint256 deadline) { + require(isStaker(msg.sender) || Operated.isOperator(msg.sender), "only + staker or operator"); + + // require countdown is not started + require(isInitialized(), "deadline already set"); + + // start countdown + return Countdown._start(); +} +``` + +**Countdown** makes use of block timestamps to determine start time and end time. +`_start()` Starts the countdown based on the current block timestamp and returns `deadline` which is timestamp of the end of the countdown(current timestamp + countdown length) + +Once the countdown is over, the stake can call `retrieveStake()` to retrieve the remaining stake as the agreement has ended. + +**CountdownGriefingEscrow** +This contract acts as escrow and allows for a buyer and a seller to deposit their stake and payment before sending it to a CountdownGriefing agreement. + +This contract is designed such that there is only two end states: deposits are returned to the buyer and the seller OR the agreement is successfully created. +![](https://i.imgur.com/89jQMVf.png) + +We'll go into it's details below + +### Step by Step Walkthrough Let's see how erasure bay interacts with erasure protocol -### New User Registration +**New User Registration** - New User connects to Erasure Client. ErasureClient generates asymmetric encryption keys `PubKey`, `PrivKey` ```js const keypair = ErasureHelper.crypto.asymmetric.generateKeyPair(sig, salt); ``` -- ErasureClient uploads `PubKey` to `Erasure_Users` +- ErasureClient registers user to `Erasure_Users` and uploading it's data ```js const ethers = require("ethers"); const ErasureUsersArtifact = require("Erasure_Users.json"); -const user = PubKey; +const user = keypair.publicKey; // Public Key const data = 16; //any data // UserData in bytes @@ -73,7 +168,7 @@ function getUserData(address user) public view returns (bytes memory data) { data = _metadata[user]; } ``` -### Creating a Post +**Creating a Post** A Feed_Factory is a factory contract for managing feeds. - Seller first creates a `Feed` template contract from Feed_Factory by calling method `create` @@ -163,7 +258,7 @@ function _submitHash(bytes32 hash) internal { const metadataJsonIpfsPath = await ipfs.pinata.pinJSONToIPFS(metadata) const metadataHex = ErasureHelper.ipfs.hashToHex(metadataJsonIpfsPath) ``` -### Selling a Post +**Selling a Post** Once the post is created, it's time to sell. - Seller creates `Escrow` using CountdownGriefingEscrow_Factory.create() with `calldata` as parameter. This is exactly same as creating a Feed Template as Feed_Factory and CountdownGriefingEscrow_Factory are both factory contracts and method `create` is a factory method. @@ -325,4 +420,4 @@ function submitData(bytes memory data) public { - Retrives - Computes -### Revealing a Post +**Revealing a Post** From a273499a0ed4646d1989da10d32e39d4a71467bd Mon Sep 17 00:00:00 2001 From: nanspro Date: Fri, 20 Dec 2019 04:40:13 +0530 Subject: [PATCH 3/3] Adding reveal and sell --- erasurebay-docs/bay-overview.md | 143 ++++++++++++++++++++++++-------- 1 file changed, 107 insertions(+), 36 deletions(-) diff --git a/erasurebay-docs/bay-overview.md b/erasurebay-docs/bay-overview.md index de3b10a..0028ba4 100644 --- a/erasurebay-docs/bay-overview.md +++ b/erasurebay-docs/bay-overview.md @@ -1,13 +1,13 @@ # Erasure Bay ErasureBay is a dapp built upon the Erasure protocol. It’s a marketplace for buying/selling information of any kind. It’s Numerai’s demonstration of the power of Erasure to improve the Web itself. -**How it works** +## How it works * Post data to storage that no one owns(ex: ipfs) * Stake money on your claims. Encrypt them, then reveal them, to prove you knew something. * Sell them under a smart contract that must be enforced. -### State Machine Architecture +## State Machine Architecture Erasure uses shared registries to establish a single source of truth for the Erasure Protocol. So far, the registries developed are: @@ -16,17 +16,17 @@ Erasure uses shared registries to establish a single source of truth for the Era * Erasure_Users: To keep track of users and their data * Erasure_Escrows -**Clone Factories** +### Clone Factories Using the Spawner library, every item on Erasure is created as a clone of a previously deployed template. We call these Clone Factories. Every clone is also registered in a registry which provides a single source of truth on the status of the protocol. ![](https://i.imgur.com/bEUAp0H.png) -**Staking** +### Staking ![](https://i.imgur.com/JELJwhJ.png) -**Agreements** +### Agreements When two parties decide to engage, they begin by staking NMR and agreeing on a set of conditions for punishment. We call this combination of skin in the game and rules of engagement an Erasure_Agreement. @@ -41,16 +41,16 @@ Griefing has two main methods: `_grief()` and `setRatio` ![](https://i.imgur.com/w0ab7n7.png) -- increaseStake() +- ***increaseStake()*** Can be called by staker only to increase the stake -- reward() +- ***reward()*** Called by the counterparty to increase the stake -- releaseStake() +- ***releaseStake()*** Called by the counterparty to release the stake to the staker -- punish() +- ***punish()*** Called by the counterparty to punish the staker ```js function punish(uint256 punishment, bytes memory message) public returns @@ -94,7 +94,7 @@ function startCountdown() public returns (uint256 deadline) { Once the countdown is over, the stake can call `retrieveStake()` to retrieve the remaining stake as the agreement has ended. -**CountdownGriefingEscrow** +### CountdownGriefingEscrow This contract acts as escrow and allows for a buyer and a seller to deposit their stake and payment before sending it to a CountdownGriefing agreement. This contract is designed such that there is only two end states: deposits are returned to the buyer and the seller OR the agreement is successfully created. @@ -102,18 +102,28 @@ This contract is designed such that there is only two end states: deposits are r We'll go into it's details below -### Step by Step Walkthrough +## Packages +- [Erasure Crypto + IPFS Helpers](packages/crypto-ipfs) +This package contains the crypto system used on erasurequant.com plus some IPFS helper functions. +- [GraphQL API](packages/the-graph) +This is the code for our subgraph running on The Graph (a query protocol which listens for events on smart contracts and cache data which can be accessed by a graphql query). This subgraph provides a GraphQL API for querying all the data of the Erasure protocol. +Here's the deployed subgraph for erasure protocol https://thegraph.com/explorer/subgraph/jgeary/erasure + +- [Local Dev Environment](packages/testenv) +Instantiate a ganache instance with NMR and erasure protocol. + +## Step by Step Walkthrough Let's see how erasure bay interacts with erasure protocol -**New User Registration** +### New User Registration -- New User connects to Erasure Client. ErasureClient generates asymmetric encryption keys `PubKey`, `PrivKey` +- ***New User connects to Erasure Client. ErasureClient generates asymmetric encryption keys `PubKey`, `PrivKey`*** ```js const keypair = ErasureHelper.crypto.asymmetric.generateKeyPair(sig, salt); ``` -- ErasureClient registers user to `Erasure_Users` and uploading it's data +- ***ErasureClient registers user to `Erasure_Users` and uploading it's data*** ```js const ethers = require("ethers"); const ErasureUsersArtifact = require("Erasure_Users.json"); @@ -168,7 +178,7 @@ function getUserData(address user) public view returns (bytes memory data) { data = _metadata[user]; } ``` -**Creating a Post** +### Creating a Post A Feed_Factory is a factory contract for managing feeds. - Seller first creates a `Feed` template contract from Feed_Factory by calling method `create` @@ -182,11 +192,11 @@ function create(bytes memory callData) public returns (address instance) { return instance; } ``` -- It creates a clone of `Feed` template using a nonce, the nonce is same for clones with same calldata. The nonce can also be used to determine the address of the new contract before creation. +- ***It creates a clone of `Feed` template using a nonce, the nonce is same for clones with same calldata. The nonce can also be used to determine the address of the new contract before creation.*** _Blob of abi-encoded calldata is used to initialize the template. It returns the instance address of the clone that was created_ -- Generates a symmetric encryption key and it's hash +- ***Generates a symmetric encryption key and it's hash*** ```js const hexlify = utf8str => ethers.utils.hexlify(ethers.utils.toUtf8Bytes(utf8str)); @@ -200,7 +210,7 @@ const keyHash = nonce, keypair.secretKey) ``` -- Encrypt rawData with the symmetric key and gets it ipfs path +- ***Encrypt rawData with the symmetric key and gets it ipfs path*** ```js let buf = Buffer.from(rawData); let dataEncoded = buf.toString('base64'); @@ -209,12 +219,12 @@ const encryptedFile = ErasureHelper.crypto.symmetric.encryptMessage( const rawHash = await ErasureHelper.ipfs.onlyHash(buf) const rawDataHash = ErasureHelper.ipfs.hashToHex(rawHash) ``` -- Get encryptedData's ipfs path +- ***Get encryptedData's ipfs path*** ```js const encryptedFileIpfsPath = await ipfs.pinata.pinTextToIPFS(encryptedFile) ``` -- Preparing metadata +- ***Preparing metadata*** ```js const metaData = { nonce, @@ -224,7 +234,7 @@ const metaData = { } ``` -- Submitting proofHash to our `Feed` +- ***Submitting proofHash to our `Feed`*** ```js const proofHash = await ErasureHelper.multihash({input:JSON.stringify(metaData), inputType:'raw', @@ -253,12 +263,12 @@ function _submitHash(bytes32 hash) internal { } ``` -- Finally submitting metadata to ipfs +- ***Finally submitting metadata to ipfs*** ```js const metadataJsonIpfsPath = await ipfs.pinata.pinJSONToIPFS(metadata) const metadataHex = ErasureHelper.ipfs.hashToHex(metadataJsonIpfsPath) ``` -**Selling a Post** +### Selling a Post Once the post is created, it's time to sell. - Seller creates `Escrow` using CountdownGriefingEscrow_Factory.create() with `calldata` as parameter. This is exactly same as creating a Feed Template as Feed_Factory and CountdownGriefingEscrow_Factory are both factory contracts and method `create` is a factory method. @@ -296,7 +306,7 @@ When this escrow template is created, we can provide some params which are then EscrowStatus is an enum, `enum EscrowStatus { isOpen, onlyStakeDeposited, onlyPaymentDeposited, isDeposited, isFinalized, isCancelled }` -- Seller deposits the required stake using `Escrow.depositStake()` +- ***Seller deposits the required stake using `Escrow.depositStake()`*** ```js @@ -338,7 +348,7 @@ function _depositStake() private { } ``` -- Buyer deposits the required payment using `Escrow.depositPayment()` +- ***Buyer deposits the required payment using `Escrow.depositPayment()`*** ```js function depositPayment() public { require(isBuyer(msg.sender) || Operated.isOperator(msg.sender), @@ -379,23 +389,23 @@ function _depositPayment() private { `Countdown._start()` will start the countdown based on currentblock timestamp, and will return the timestamp at the end of countdown. -- Retrieve buyer's `PubKey` from Erasure_Users -- Computes encryptedSymKey_Buyer = PubKey_Buyer.encrypt(SymKey) -- Computes metadata -- Finalize escrow with creating a griefing agreement `Agreement` +- ***Retrieve buyer's `PubKey` from Erasure_Users*** +- ***Computes encryptedSymKey_Buyer = PubKey_Buyer.encrypt(SymKey)*** +- ***Computes metadata*** +- ***Finalize escrow with creating a griefing agreement `Agreement`*** Calling `Escrow.finalize()` (1) Will create the agreement (2) Transfer the stake and deposit to agreement (3) Start the countdown for agreement `CountdownGriefing(agreement).startCountdown();` -- Uploads metadata to ipfs +- ***Uploads metadata to ipfs*** ```js const metadataJsonIpfsPath = await ipfs.pinata.pinJSONToIPFS(metadata) const metadataHex = ErasureHelper.ipfs.hashToHex(metadataJsonIpfsPath) ``` -- Submitting proofHash to buyer +- ***Submitting proofHash to buyer*** ```js const proofHash = await ErasureHelper.multihash({input:JSON.stringify(metaData), inputType:'raw', @@ -403,8 +413,7 @@ outputType:'digest'}) let tx = Escrow.submitData(proofHash) ``` - -Submitting data to the buyer +- ***Submitting data to the buyer*** ```js function submitData(bytes memory data) public { require(isSeller(msg.sender) || Operated.isOperator(msg.sender), "only @@ -418,6 +427,68 @@ function submitData(bytes memory data) public { } ``` -- Retrives -- Computes -**Revealing a Post** +- ***Retriving Data from Buyer*** +From Erasure_Users (users registry), get buyer's public key by calling method `getUser(buyerAddr)` + +```js +// Encrypt symkey with buyer's pubkey +const encryptedSymkey = crypto.symmetric.encryptMessage(buyerPubkey, +Buffer.from(symKey)) +``` + +Send sellData ipfs path to CountdownEscrowGriefing +```js +const selldata = { + encryptedSymkey, + proofIpfsPath +} +const selldataIpfsPath = await +ErasureHelper.multihash({input:JSON.stringify(sellData), inputType:'raw', +outputType:'digest'}) + +const confirmedTx = await this.submitData(selldataIpfsPath) +``` + +- ***Retriving Data from Seller*** +Gets submitted data's ipfs path (`path`) from erasure's subgraph (graphQL api) using escrow address. Get data from that ipfs path +```js +const dataSubmittedIPFS = await +this.ipfsMini.catJSON(hexToHash(path)) +``` + +Get symmetricKey and metadata from ipfs +```js +// get encrypted symkey +const encryptedSymkey = dataSubmittedIPFS.encryptedSymkey +// decrypt it +const decryptedSymkey = crypto.symmetric.decryptMessage(keypair.privateKey, +Buffer.from(encryptedSymkey)) + +const proofIpfsPath = dataSubmittedIPFS.proofIpfsPath +const proofData = await this.ipfsMini.catJSON(proofIpfsPath) +``` + +Get encrypted data path from escrow and then encrypted data itself from it's ipfs path +```js +const encryptedDataIpfsPath = proofData.encryptedFileIpfsPath +const encryptedData = await this.ipfsMini.cat(encryptedDataIpfsPath) +``` + +Decrypt data +```js +const rawData = +ErasureHelper.crypto.symmetric.decryptMessage(decryptedSymkey, encryptedData) +``` +### Revealing a Post +- ***Seller uploads SymKey to ipfs*** +```js +const symkeyIpfsPath = await +ErasureHelper.multihash({input:JSON.stringify(SymKey), inputType:'raw', +outputType:'digest'}) +``` +- ***Seller uploads rawdata to ipfs*** +```js +const rawdataIpfsPath = await +ErasureHelper.multihash({input:JSON.stringify(rawData), inputType:'raw', +outputType:'digest'}) +```