From de0956e63a4d3aba52e6a650cb3f17b3712cfdab Mon Sep 17 00:00:00 2001 From: MSG <59928086+MSghais@users.noreply.github.com> Date: Thu, 27 Jun 2024 12:17:28 +0200 Subject: [PATCH] Claim_to (#192) * add claim_to function with starknet recipient in nostr event content * clean claim to * change contract address + rename * format to felt into encode function + change signature claim_to * scarb fmt --- onchain/src/social/deposit.cairo | 196 ++++++++++++++++++++++++++++--- 1 file changed, 182 insertions(+), 14 deletions(-) diff --git a/onchain/src/social/deposit.cairo b/onchain/src/social/deposit.cairo index 870288d4..0b39f18d 100644 --- a/onchain/src/social/deposit.cairo +++ b/onchain/src/social/deposit.cairo @@ -1,20 +1,41 @@ +use core::fmt::Display; +use core::to_byte_array::FormatAsByteArray; use starknet::{get_caller_address, get_contract_address, get_tx_info, ContractAddress}; use super::request::{SocialRequest, SocialRequestImpl, SocialRequestTrait, Encode, Signature}; pub type DepositId = felt252; +#[derive(Clone, Debug, Drop, Serde)] +pub struct ClaimToContent { + pub deposit_id: DepositId, + pub starknet_recipient: ContractAddress +} + + impl DepositIdEncodeImpl of Encode { fn encode(self: @DepositId) -> @ByteArray { @format!("claim {}", self) } } +impl ClaimToContentEncodeImpl of Encode { + fn encode(self: @ClaimToContent) -> @ByteArray { + let recipient_address_user_felt: felt252 = self + .starknet_recipient + .clone() + .try_into() + .unwrap(); + @format!("claim {} to {:?}", self.deposit_id, recipient_address_user_felt) + } +} + + type NostrPublicKey = u256; #[derive(Copy, Debug, Drop, Serde)] pub enum DepositResult { Transfer: ContractAddress, - Deposit: DepositId, + Deposit: DepositId } #[derive(Copy, Debug, Drop, PartialEq, starknet::Store, Serde)] @@ -38,6 +59,7 @@ pub trait IDepositEscrow { ) -> DepositResult; fn cancel(ref self: TContractState, deposit_id: DepositId); fn claim(ref self: TContractState, request: SocialRequest); + fn claim_to(ref self: TContractState, request: SocialRequest); } #[starknet::contract] @@ -55,6 +77,7 @@ pub mod DepositEscrow { use super::{ Deposit, DepositId, DepositResult, IDepositEscrow, NostrPublicKey, DepositIdEncodeImpl, + ClaimToContent }; impl DepositDefault of Default { @@ -252,6 +275,38 @@ pub mod DepositEscrow { } ); } + + + fn claim_to(ref self: ContractState, request: SocialRequest) { + let deposit_content = request.content.clone(); + let deposit_id = deposit_content.deposit_id; + // let starknet_recipient: ContractAddress = deposit_content.starknet_recipient; + let starknet_recipient: ContractAddress = deposit_content + .starknet_recipient + .try_into() + .unwrap(); + let deposit = self.deposits.read(deposit_id); + assert!(deposit != Default::default(), "can't find deposit"); + assert!(request.public_key == deposit.recipient, "invalid recipient"); + request.verify().expect('can\'t verify signature'); + + let erc20 = IERC20Dispatcher { contract_address: deposit.token_address }; + erc20.transfer(starknet_recipient, deposit.amount); + + self.nostr_to_sn.write(request.public_key, starknet_recipient); + self.deposits.write(deposit_id, Default::default()); + self + .emit( + ClaimEvent { + deposit_id, + sender: get_caller_address(), + nostr_recipient: request.public_key, + amount: deposit.amount, + starknet_recipient: starknet_recipient, + token_address: deposit.token_address + } + ); + } } } @@ -264,16 +319,17 @@ mod tests { use snforge_std::{ declare, ContractClass, ContractClassTrait, spy_events, SpyOn, EventSpy, EventFetcher, Event, EventAssertions, start_cheat_caller_address, cheat_caller_address_global, - stop_cheat_caller_address_global, start_cheat_block_timestamp + stop_cheat_caller_address_global, start_cheat_block_timestamp, }; use starknet::{ ContractAddress, get_block_timestamp, get_caller_address, get_contract_address, - contract_address_const + contract_address_const, + // contract_address_try_from_felt252 }; use super::super::request::{SocialRequest, Signature, Encode}; use super::super::transfer::Transfer; - use super::{Deposit, DepositId, DepositResult, IDepositEscrow, NostrPublicKey}; + use super::{Deposit, DepositId, DepositResult, IDepositEscrow, NostrPublicKey, ClaimToContent}; use super::{IDepositEscrowDispatcher, IDepositEscrowDispatcherTrait}; fn declare_escrow() -> ContractClass { @@ -319,7 +375,8 @@ mod tests { NostrPublicKey, ContractAddress, IERC20Dispatcher, - IDepositEscrowDispatcher + IDepositEscrowDispatcher, + SocialRequest ) { // recipient private key: 59a772c0e643e4e2be5b8bac31b2ab5c5582b03a84444c81d6e2eec34a5e6c35 // just for testing, do not use for anything else @@ -332,6 +389,11 @@ mod tests { let escrow = deploy_escrow(escrow_class); + let recipient_address_user: ContractAddress = 678.try_into().unwrap(); + + let recipient_address_user_felt: felt252 = recipient_address_user.try_into().unwrap(); + + // TODO how format it to use this starknet address on the test data Nostr event // for test data see: https://replit.com/@maciejka/WanIndolentKilobyte-2 let request = SocialRequest { @@ -346,7 +408,29 @@ mod tests { } }; - (request, recipient_public_key, sender_address, erc20, escrow) + // TODO change with the correct signature with the content deposit id and strk recipient + // for test data see claim to: https://replit.com/@msghais135/WanIndolentKilobyte-claimto#index.js + + let claim_content = ClaimToContent { + deposit_id: 1, starknet_recipient: recipient_address_user + }; + + // @TODO format the content and get the correct signature + let request_claim_to = SocialRequest { + public_key: recipient_public_key, + created_at: 1716285235_u64, + kind: 1_u16, + tags: "[]", + content: claim_content, + sig: Signature { + r: 0x3d9628eeb7ff7333bdea8e48e2371279363a4aac5c8da19144e909d9744ebc82_u256, + s: 0xe9f41be1e8f1719ab1da3b69c74cad3045fcc06b0020d989eb8b42f1e88574da_u256 + // r: 0xf61fa9ab434b047a13a6b679fa8b2152ed20f6859bf566987b2e6430dae8a0c2_u256, + // s: 0xafdfd907640f7d17805541429e7da3633ae4a39d9ad091edf283e9500a689c81_u256, + } + }; + + (request, recipient_public_key, sender_address, erc20, escrow, request_claim_to) } fn request_fixture() -> ( @@ -354,7 +438,8 @@ mod tests { NostrPublicKey, ContractAddress, IERC20Dispatcher, - IDepositEscrowDispatcher + IDepositEscrowDispatcher, + SocialRequest ) { let erc20_class = declare_erc20(); let escrow_class = declare_escrow(); @@ -363,7 +448,7 @@ mod tests { #[test] fn deposit_claim() { - let (request, recipient_nostr_key, sender_address, erc20, escrow) = request_fixture(); + let (request, recipient_nostr_key, sender_address, erc20, escrow, _) = request_fixture(); let recipient_address: ContractAddress = 345.try_into().unwrap(); let amount = 100_u256; @@ -378,10 +463,30 @@ mod tests { escrow.claim(request); } + #[test] + fn deposit_claim_to() { + let (request, recipient_nostr_key, sender_address, erc20, escrow, request_claim_to) = + request_fixture(); + let recipient_address: ContractAddress = 345.try_into().unwrap(); + let recipient_address_user: ContractAddress = 678.try_into().unwrap(); + let amount = 100_u256; + + cheat_caller_address_global(sender_address); + erc20.approve(escrow.contract_address, amount); + stop_cheat_caller_address_global(); + + start_cheat_caller_address(escrow.contract_address, sender_address); + escrow.deposit(amount, erc20.contract_address, recipient_nostr_key, 0_u64); + + start_cheat_caller_address(escrow.contract_address, recipient_address); + // escrow.claim_to(request_claim_to, recipient_address_user); + escrow.claim_to(request_claim_to); + } + #[test] #[should_panic(expected: 'can\'t verify signature')] fn claim_incorrect_signature() { - let (request, recipient_nostr_key, sender_address, erc20, escrow) = request_fixture(); + let (request, recipient_nostr_key, sender_address, erc20, escrow, _) = request_fixture(); let recipient_address: ContractAddress = 345.try_into().unwrap(); let amount = 100_u256; @@ -405,9 +510,72 @@ mod tests { escrow.claim(request); } + #[test] + #[should_panic(expected: 'can\'t verify signature')] + fn claim_incorrect_signature_claim_to() { + let (request, recipient_nostr_key, sender_address, erc20, escrow, request_claim_to) = + request_fixture(); + let recipient_address: ContractAddress = 345.try_into().unwrap(); + let recipient_address_user: ContractAddress = 678.try_into().unwrap(); + + let amount = 100_u256; + + cheat_caller_address_global(sender_address); + erc20.approve(escrow.contract_address, amount); + stop_cheat_caller_address_global(); + + start_cheat_caller_address(escrow.contract_address, sender_address); + escrow.deposit(amount, erc20.contract_address, recipient_nostr_key, 0_u64); + + start_cheat_caller_address(escrow.contract_address, recipient_address); + + let request = SocialRequest { + sig: Signature { + r: 0x2570a9a0c92c180bd4ac826c887e63844b043e3b65da71a857d2aa29e7cd3a4e_u256, + s: 0x1c0c0a8b7a8330b6b8915985c9cd498a407587213c2e7608e7479b4ef966605f_u256, + }, + ..request_claim_to, + }; + + // escrow.claim_to(request, recipient_address_user); + escrow.claim_to(request); + } + + + #[test] + #[should_panic(expected: 'can\'t verify signature')] + fn claim_incorrect_signature_claim_to_incorrect_recipient() { + let (request, recipient_nostr_key, sender_address, erc20, escrow, request_claim_to) = + request_fixture(); + let recipient_address: ContractAddress = 345.try_into().unwrap(); + let recipient_address_user: ContractAddress = 789.try_into().unwrap(); + + let amount = 100_u256; + + cheat_caller_address_global(sender_address); + erc20.approve(escrow.contract_address, amount); + stop_cheat_caller_address_global(); + + start_cheat_caller_address(escrow.contract_address, sender_address); + escrow.deposit(amount, erc20.contract_address, recipient_nostr_key, 0_u64); + + start_cheat_caller_address(escrow.contract_address, recipient_address); + + let request = SocialRequest { + sig: Signature { + r: 0x2570a9a0c92c180bd4ac826c887e63844b043e3b65da71a857d2aa29e7cd3a4e_u256, + s: 0x1c0c0a8b7a8330b6b8915985c9cd498a407587213c2e7608e7479b4ef966605f_u256, + }, + ..request_claim_to, + }; + + // escrow.claim_to(request, recipient_address_user); + escrow.claim_to(request); + } + #[test] fn deposit_cancel_no_timelock() { - let (_, recipient_nostr_key, sender_address, erc20, escrow) = request_fixture(); + let (_, recipient_nostr_key, sender_address, erc20, escrow, _) = request_fixture(); let amount = 100_u256; @@ -429,7 +597,7 @@ mod tests { #[test] #[should_panic(expected: "can't cancel before timelock expiration")] fn deposit_cancel_before_timelock() { - let (_, recipient_nostr_key, sender_address, erc20, escrow) = request_fixture(); + let (_, recipient_nostr_key, sender_address, erc20, escrow, _) = request_fixture(); let amount = 100_u256; @@ -448,7 +616,7 @@ mod tests { #[test] fn deposit_cancel_timelock() { - let (_, recipient_nostr_key, sender_address, erc20, escrow) = request_fixture(); + let (_, recipient_nostr_key, sender_address, erc20, escrow, _) = request_fixture(); let amount = 100_u256; @@ -471,7 +639,7 @@ mod tests { #[test] #[should_panic(expected: "not authorized")] fn not_authorized_cancel() { - let (_, recipient_nostr_key, sender_address, erc20, escrow) = request_fixture(); + let (_, recipient_nostr_key, sender_address, erc20, escrow, _) = request_fixture(); let amount = 100_u256; @@ -490,7 +658,7 @@ mod tests { } fn deposit_claim_deposit() { - let (request, recipient_nostr_key, sender_address, erc20, escrow) = request_fixture(); + let (request, recipient_nostr_key, sender_address, erc20, escrow, _) = request_fixture(); let recipient_address: ContractAddress = 345.try_into().unwrap(); let amount = 100_u256;