From e887ac6df0c589c13fb8acae444370848b8cea99 Mon Sep 17 00:00:00 2001 From: Tom French Date: Mon, 23 Mar 2020 22:30:31 +0000 Subject: [PATCH 01/21] start direct deposit --- packages/contracts/contracts/NoteStream.sol | 19 ++++-- .../contracts/contracts/StreamUtilities.sol | 60 +++++++++++++++++++ packages/subgraph/abis/NoteStream.json | 11 +++- 3 files changed, 83 insertions(+), 7 deletions(-) diff --git a/packages/contracts/contracts/NoteStream.sol b/packages/contracts/contracts/NoteStream.sol index e3047fa..60bcd76 100644 --- a/packages/contracts/contracts/NoteStream.sol +++ b/packages/contracts/contracts/NoteStream.sol @@ -144,7 +144,7 @@ contract NoteStream is Pausable, ReentrancyGuard { * Throws if the contract is not allowed to transfer enough tokens. * Throws if there is a token transfer failure. * @param recipient The address towards which the money is streamed. - * @param noteHash The note of a zkAsset to be streamed. + * @param proof The JoinSplit proof transfering a zkAsset to be streamed. * @param tokenAddress The zkAsset to use as streaming currency. * @param startTime The unix timestamp for when the stream starts. * @param stopTime The unix timestamp for when the stream stops. @@ -152,7 +152,8 @@ contract NoteStream is Pausable, ReentrancyGuard { */ function createStream( address recipient, - bytes32 noteHash, + bytes memory proof, + bytes memory proofSignature, address tokenAddress, uint256 startTime, uint256 stopTime @@ -166,10 +167,20 @@ contract NoteStream is Pausable, ReentrancyGuard { ); require(stopTime > startTime, "Stream duration not greater than zero"); + // Transfer the ZkAsset to the streaming contract + bytes32 streamNoteHash = StreamUtilities._processDeposit( + proof, + proofSignature, + aceContractAddress, + msg.sender, + recipient, + tokenAddress + ); + /* Create and store the stream object. */ uint256 streamId = nextStreamId; streams[streamId] = Types.AztecStream({ - noteHash: noteHash, + noteHash: streamNoteHash, sender: msg.sender, recipient: recipient, startTime: startTime, @@ -187,7 +198,7 @@ contract NoteStream is Pausable, ReentrancyGuard { msg.sender, recipient, tokenAddress, - noteHash, + streamNoteHash, startTime, stopTime ); diff --git a/packages/contracts/contracts/StreamUtilities.sol b/packages/contracts/contracts/StreamUtilities.sol index b1ba4ff..51e2332 100644 --- a/packages/contracts/contracts/StreamUtilities.sol +++ b/packages/contracts/contracts/StreamUtilities.sol @@ -51,6 +51,66 @@ library StreamUtilities { return za.mul(scalingFactor).div(zb); } + function _processDeposit( + bytes memory _proof, + bytes memory _proofSignature, + address _aceContractAddress, + address _sender, + address _recipient, + address _tokenAddress + ) internal returns (bytes32 streamNoteHash) { + // Validate Join-Split proof + bytes memory proofOutputs = IACE(_aceContractAddress) + .validateProof(JOIN_SPLIT_PROOF, address(this), _proof) + .get(0); + + // Extract notes used in proof + (, bytes memory _proofOutputNotes, , ) = proofOutputs + .extractProofOutput(); + + // Ensure that there is only a single output note to avoid loss of funds + require( + _proofOutputNotes.getLength() == 1, + "Incorrect number of output notes" + ); + + Note memory streamNote = _noteCoderToStruct(_proofOutputNotes.get(0)); + + // Require that stream note is owned by contract + require( + streamNote.owner == address(this), + "stream note is not owned by stream contract" + ); + + // Require that sender and receiver have view access to stream note + require( + MetaDataUtils.extractAddress(streamNote.metaData, 0) == _sender, + "stream sender can't view stream note" + ); + require( + MetaDataUtils.extractAddress(streamNote.metaData, 1) == _recipient, + "stream recipient can't view stream note" + ); + + // Approve contract to spend stream note + IZkAsset(_tokenAddress).approveProof( + JOIN_SPLIT_PROOF, + proofOutputs, + address(this), + true, + _proofSignature + ); + + // Send transfer + IZkAsset(_tokenAddress).confidentialTransferFrom( + JOIN_SPLIT_PROOF, + proofOutputs + ); + + // Return stream note hash + streamNoteHash = streamNote.noteHash; + } + function _validateRatioProof( address _aceContractAddress, bytes memory _proof1, diff --git a/packages/subgraph/abis/NoteStream.json b/packages/subgraph/abis/NoteStream.json index 95b5bbd..e2fc46a 100644 --- a/packages/subgraph/abis/NoteStream.json +++ b/packages/subgraph/abis/NoteStream.json @@ -173,9 +173,14 @@ "type": "address" }, { - "internalType": "bytes32", - "name": "noteHash", - "type": "bytes32" + "internalType": "bytes", + "name": "proof", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "proofSignature", + "type": "bytes" }, { "internalType": "address", From 4d8877b5e566ecefb3166acf30d93822895ce571 Mon Sep 17 00:00:00 2001 From: Tom French Date: Thu, 9 Apr 2020 15:16:57 +0100 Subject: [PATCH 02/21] refactor: move stream creation methods to utils --- .../components/modals/CreateStreamModal.tsx | 23 ++++--- .../react-app/src/utils/proofs/deposit.ts | 30 +++++++++ packages/react-app/src/utils/proofs/index.ts | 1 + .../react-app/src/utils/stream/creation.ts | 64 +++---------------- 4 files changed, 53 insertions(+), 65 deletions(-) create mode 100644 packages/react-app/src/utils/proofs/deposit.ts diff --git a/packages/react-app/src/components/modals/CreateStreamModal.tsx b/packages/react-app/src/components/modals/CreateStreamModal.tsx index f908872..4d1e0ca 100644 --- a/packages/react-app/src/components/modals/CreateStreamModal.tsx +++ b/packages/react-app/src/components/modals/CreateStreamModal.tsx @@ -235,21 +235,26 @@ export default function CreateStreamDialog({