-
Notifications
You must be signed in to change notification settings - Fork 39
chore:verify recipient signature via snip12 #130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,9 @@ | ||
| #[starknet::contract] | ||
| pub mod PaymentStream { | ||
| use core::ecdsa::check_ecdsa_signature; | ||
| use core::hash::{HashStateExTrait, HashStateTrait}; | ||
| use core::num::traits::{Bounded, Zero}; | ||
| use core::pedersen::PedersenTrait; | ||
| use core::traits::Into; | ||
| use fundable::interfaces::IPaymentStream::IPaymentStream; | ||
| use openzeppelin::access::accesscontrol::AccessControlComponent; | ||
|
|
@@ -13,6 +16,10 @@ pub mod PaymentStream { | |
| use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl}; | ||
| use openzeppelin::upgrades::UpgradeableComponent; | ||
| use openzeppelin::upgrades::interface::IUpgradeable; | ||
| // use openzeppelin::utils::cryptography::interface::ISRC6; | ||
| use openzeppelin::utils::cryptography::snip12::{ | ||
| OffchainMessageHash, SNIP12Metadata, StructHash, | ||
| }; | ||
| use starknet::storage::{ | ||
| Map, MutableVecTrait, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess, | ||
| Vec, | ||
|
|
@@ -22,10 +29,11 @@ pub mod PaymentStream { | |
| }; | ||
| use crate::base::errors::Errors::{ | ||
| DECIMALS_TOO_HIGH, FEE_TOO_HIGH, INSUFFICIENT_ALLOWANCE, INSUFFICIENT_AMOUNT, | ||
| INVALID_RECIPIENT, INVALID_TOKEN, NON_TRANSFERABLE_STREAM, ONLY_NFT_OWNER_CAN_DELEGATE, | ||
| OVERDEPOSIT, SAME_COLLECTOR_ADDRESS, SAME_OWNER, STREAM_CANCELED, STREAM_HAS_DELEGATE, | ||
| STREAM_NOT_ACTIVE, STREAM_NOT_PAUSED, TOO_SHORT_DURATION, UNEXISTING_STREAM, | ||
| WRONG_RECIPIENT, WRONG_RECIPIENT_OR_DELEGATE, WRONG_SENDER, ZERO_AMOUNT, | ||
| INVALID_RECIPIENT, INVALID_RECIPIENT_SIGNATURE, INVALID_TOKEN, NON_TRANSFERABLE_STREAM, | ||
| ONLY_NFT_OWNER_CAN_DELEGATE, OVERDEPOSIT, SAME_COLLECTOR_ADDRESS, SAME_OWNER, | ||
| STREAM_CANCELED, STREAM_HAS_DELEGATE, STREAM_NOT_ACTIVE, STREAM_NOT_PAUSED, | ||
| TOO_SHORT_DURATION, UNEXISTING_STREAM, WRONG_RECIPIENT, WRONG_RECIPIENT_OR_DELEGATE, | ||
| WRONG_SENDER, ZERO_AMOUNT, | ||
| }; | ||
| use crate::base::types::{ProtocolMetrics, Stream, StreamMetrics, StreamStatus}; | ||
|
|
||
|
|
@@ -312,6 +320,30 @@ pub mod PaymentStream { | |
|
|
||
| #[generate_trait] | ||
| impl InternalImpl of InternalTrait { | ||
| fn get_message_hash(self: @ContractState, stream_id: u256, approved: felt252) -> felt252 { | ||
| let mut hash_state = PedersenTrait::new(0); | ||
| hash_state = hash_state.update('CancelStreamMessage'); | ||
| hash_state = hash_state.update(stream_id.low.into()); | ||
| hash_state = hash_state.update(stream_id.high.into()); | ||
| hash_state = hash_state.update(approved); | ||
| hash_state.finalize() | ||
| } | ||
|
Comment on lines
+323
to
+330
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add replay protection and domain separation to message hash The current message hash implementation has critical security issues:
Consider adding:
🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| fn mutual_cancel( | ||
| self: @ContractState, | ||
| stream_id: u256, | ||
| sig_r: felt252, | ||
| sig_s: felt252, | ||
| recipient_pubkey: felt252, | ||
| ) -> bool { | ||
| let message_hash = self | ||
| .get_message_hash(stream_id, '1'); // 1 recipient has approve the cancellation | ||
| let is_valid = check_ecdsa_signature(message_hash, recipient_pubkey, sig_r, sig_s); | ||
| assert(is_valid, INVALID_RECIPIENT_SIGNATURE); | ||
| return true; | ||
| } | ||
|
Comment on lines
+323
to
+345
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainVerify test coverage for signature verification The new signature verification functions lack test coverage. Please ensure comprehensive tests for:
🏁 Script executed: #!/bin/bash
# Search for tests related to mutual cancellation or signature verification
echo "Searching for signature verification tests..."
fd -e cairo -e rs test | xargs rg -l "mutual_cancel|recipient.*signature|snip12" | head -20
echo -e "\nSearching for any test files that might test the payment stream cancel functionality..."
fd -e cairo test | xargs rg -l "cancel.*stream|StreamCanceled" | head -10Length of output: 532 Add comprehensive tests for I didn’t find any existing tests covering the
Suggested locations:
🤖 Prompt for AI Agents
Comment on lines
+333
to
+345
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainFix signature verification logic and validate recipient Several issues with the
🏁 Script executed: #!/bin/bash
# Check if mutual_cancel is called anywhere in the codebase
echo "Searching for mutual_cancel function calls..."
rg "mutual_cancel" --type cairo -A 3 -B 3Length of output: 172 Here's a refined check to locate any invocations of 🏁 Script executed: #!/bin/bash
echo "Searching for calls to mutual_cancel..."
rg -n "mutual_cancel(" .Length of output: 194 Let’s retry locating any calls (escaping the parenthesis): 🏁 Script executed: #!/bin/bash
echo "Searching for calls to mutual_cancel..."
rg -n 'mutual_cancel\(' .Length of output: 173 Revise and integrate The new
🤖 Prompt for AI Agents |
||
|
|
||
| fn assert_stream_exists(self: @ContractState, stream_id: u256) { | ||
| let stream = self.streams.read(stream_id); | ||
| assert(!stream.sender.is_zero(), UNEXISTING_STREAM); | ||
|
|
@@ -970,6 +1002,8 @@ pub mod PaymentStream { | |
| } | ||
|
|
||
| fn cancel(ref self: ContractState, stream_id: u256) { | ||
| // check for mutual cancel approval via SNIP12 | ||
|
|
||
|
Comment on lines
1004
to
+1006
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incomplete implementation - signature verification not integrated The comment indicates intent to check mutual cancellation approval, but the
Either:
Would you like me to help implement the complete signature verification flow in the cancel function? 🤖 Prompt for AI Agents |
||
| self.reentrancy_guard.start(); | ||
|
|
||
| // Ensure the caller is the stream sender | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unused imports and implement proper SNIP12 message hashing
The SNIP12 imports (
OffchainMessageHash,SNIP12Metadata,StructHash) are imported but not used. The currentget_message_hashimplementation uses basic Pedersen hashing instead of SNIP12's structured message hashing with domain separation.For proper SNIP12 compliance, either:
🤖 Prompt for AI Agents