Skip to content

Commit

Permalink
Merge pull request #3 from ermvrs/main
Browse files Browse the repository at this point in the history
Signing impl change and utils
  • Loading branch information
ermvrs authored Oct 24, 2024
2 parents 78e9c8d + ae50547 commit 896b1ee
Show file tree
Hide file tree
Showing 19 changed files with 7,094 additions and 42 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ target
dev_signer
dev_account
sepolia
sepolia_account
sepolia_account
deployment
47 changes: 9 additions & 38 deletions src/accounts/base.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub type EthPublicKey = starknet::secp256k1::Secp256k1Point;
use starknet::EthAddress;
use starknet::{EthAddress};
#[starknet::interface]
pub trait IRosettaAccount<TState> {
fn __execute__(self: @TState, calls: Array<felt252>) -> Array<Span<felt252>>;
Expand All @@ -8,16 +8,12 @@ pub trait IRosettaAccount<TState> {
fn supports_interface(self: @TState, interface_id: felt252) -> bool;
fn __validate_declare__(self: @TState, class_hash: felt252) -> felt252;
fn __validate_deploy__(
self: @TState, class_hash: felt252, contract_address_salt: felt252, public_key: EthPublicKey
self: @TState, class_hash: felt252, contract_address_salt: felt252, eth_public_key: EthPublicKey
) -> felt252;
fn get_public_key(self: @TState) -> EthPublicKey;
fn get_ethereum_address(self: @TState) -> EthAddress;
fn set_public_key(ref self: TState, new_public_key: EthPublicKey, signature: Span<felt252>);
// Camel case
fn isValidSignature(self: @TState, hash: felt252, signature: Array<felt252>) -> felt252;
fn getPublicKey(self: @TState) -> EthPublicKey;
fn getEthereumAddress(self: @TState) -> EthAddress;
fn setPublicKey(ref self: TState, newPublicKey: EthPublicKey, signature: Span<felt252>);
}

#[starknet::contract(account)]
Expand All @@ -28,7 +24,7 @@ pub mod RosettaAccount {
EthAddress, get_contract_address, get_caller_address, get_tx_info
};
use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};
use rosettacontracts::accounts::utils::{is_valid_eth_signature, Secp256k1PointStorePacking};
use rosettacontracts::accounts::utils::{is_valid_eth_signature, Secp256k1PointStorePacking, pubkey_to_eth_address};

pub mod Errors {
pub const INVALID_CALLER: felt252 = 'Rosetta: invalid caller';
Expand All @@ -45,8 +41,9 @@ pub mod RosettaAccount {
}

#[constructor]
fn constructor(ref self: ContractState, eth_account: EthAddress) {
self.ethereum_address.write(eth_account);
fn constructor(ref self: ContractState, eth_public_key: EthPublicKey) {
self.ethereum_public_key.write(eth_public_key);
self.ethereum_address.write(pubkey_to_eth_address(eth_public_key));
}
// TODO: Raw transaction tx.signature da, __execute__ parametresindede bit locationlar mı olacak??
#[abi(embed_v0)]
Expand Down Expand Up @@ -95,52 +92,30 @@ pub mod RosettaAccount {
self: @ContractState,
class_hash: felt252,
contract_address_salt: felt252,
public_key: EthPublicKey
eth_public_key: EthPublicKey
) -> felt252 {
// TODO: check if validations enough
self.validate_transaction()
}

fn get_public_key(self: @ContractState) -> EthPublicKey {
self.ethereum_public_key.read()
}

fn get_ethereum_address(self: @ContractState) -> EthAddress {
self.ethereum_address.read()
}

// We dont need that function
fn set_public_key(
ref self: ContractState, new_public_key: EthPublicKey, signature: Span<felt252>
) {}

fn isValidSignature(
self: @ContractState, hash: felt252, signature: Array<felt252>
) -> felt252 {
self.is_valid_signature(hash, signature)
}

fn getPublicKey(self: @ContractState) -> EthPublicKey {
self.get_public_key()
}

fn getEthereumAddress(self: @ContractState) -> EthAddress {
self.get_ethereum_address()
}

// We dont need that function
fn setPublicKey(
ref self: ContractState, newPublicKey: EthPublicKey, signature: Span<felt252>
) {
self.set_public_key(newPublicKey, signature)
}
}

#[generate_trait]
impl InternalImpl of InternalTrait {
fn initializer(ref self: ContractState, ethPubKey: EthPublicKey) {
// Write pubkey to storage
self._set_public_key(ethPubKey);
}

fn assert_only_self(self: @ContractState) {
Expand All @@ -149,12 +124,6 @@ pub mod RosettaAccount {
assert(self == caller, Errors::UNAUTHORIZED);
}

// Overwrites ethereum public key. We may remove that function since we only need to
// write during initialization.
fn _set_public_key(ref self: ContractState, new_public_key: EthPublicKey) {
self.ethereum_public_key.write(new_public_key);
}

/// Validates the signature for the current transaction.
/// Returns the short string `VALID` if valid, otherwise it reverts.
fn validate_transaction(self: @ContractState) -> felt252 {
Expand All @@ -170,6 +139,8 @@ pub mod RosettaAccount {
fn _is_valid_signature(
self: @ContractState, hash: felt252, signature: Span<felt252>
) -> bool {
// TODO verify transaction with eth address not pub key
// Kakarot calldata ile transactionu bir daha olusturup verify etmeye calismis
let public_key: EthPublicKey = self.ethereum_public_key.read();
is_valid_eth_signature(hash, public_key, signature)
}
Expand Down
13 changes: 13 additions & 0 deletions src/accounts/utils.cairo
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
use starknet::secp256_trait::{Signature};
use starknet::secp256_trait;
use rosettacontracts::accounts::base::{EthPublicKey};
use starknet::{EthAddress};
use starknet::eth_signature::{verify_eth_signature, public_key_point_to_eth_address};

#[derive(Copy, Drop, Serde)]
pub struct EthSignature {
pub r: u256,
pub s: u256,
}

pub fn pubkey_to_eth_address(public_key: EthPublicKey) -> EthAddress {
public_key_point_to_eth_address(public_key)
}

pub fn is_valid_eth_signature(
msg_hash: felt252, public_key: EthPublicKey, signature: Span<felt252>
) -> bool {
Expand All @@ -17,6 +24,12 @@ pub fn is_valid_eth_signature(
secp256_trait::is_valid_signature(msg_hash.into(), signature.r, signature.s, public_key)
}

pub fn is_valid_eth_signature_with_eth_address(
msg_hash:u256, signature: Signature, eth_address: EthAddress
) {
verify_eth_signature(msg_hash, signature, eth_address)
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts for Cairo v0.17.0 (account/utils/secp256k1.cairo)

Expand Down
182 changes: 182 additions & 0 deletions src/errors.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
use core::fmt::{Debug, Formatter, Error, Display};
use crate::utils::bytes::ToBytes;

// STACK

// INSTRUCTIONS
pub const PC_OUT_OF_BOUNDS: felt252 = 'KKT: pc >= bytecode length';

// TYPE CONVERSION
pub const TYPE_CONVERSION_ERROR: felt252 = 'KKT: type conversion error';

// NUMERIC OPERATIONS
pub const BALANCE_OVERFLOW: felt252 = 'KKT: balance overflow';

// JUMP
pub const INVALID_DESTINATION: felt252 = 'KKT: invalid JUMP destination';

// CALL
pub const VALUE_TRANSFER_IN_STATIC_CALL: felt252 = 'KKT: transfer value in static';
pub const ACTIVE_MACHINE_STATE_IN_CALL_FINALIZATION: felt252 = 'KKT: active state in end call';
pub const MISSING_PARENT_CONTEXT: felt252 = 'KKT: missing parent context';
pub const CALL_GAS_GT_GAS_LIMIT: felt252 = 'KKT: call gas gt gas limit';

// EVM STATE

// STARKNET_SYSCALLS
pub const READ_SYSCALL_FAILED: felt252 = 'KKT: read syscall failed';
pub const BLOCK_HASH_SYSCALL_FAILED: felt252 = 'KKT: block_hash syscall failed';
pub const WRITE_SYSCALL_FAILED: felt252 = 'KKT: write syscall failed';
pub const CONTRACT_SYSCALL_FAILED: felt252 = 'KKT: contract syscall failed';
pub const EXECUTION_INFO_SYSCALL_FAILED: felt252 = 'KKT: exec info syscall failed';

// CREATE
pub const CONTRACT_ACCOUNT_EXISTS: felt252 = 'KKT: Contract Account exists';
pub const EOA_EXISTS: felt252 = 'KKT: EOA already exists';
pub const ACCOUNT_EXISTS: felt252 = 'KKT: Account already exists';
pub const DEPLOYMENT_FAILED: felt252 = 'KKT: deployment failed';

// TRANSACTION ORIGIN
pub const CALLING_FROM_UNDEPLOYED_ACCOUNT: felt252 = 'EOA: from is undeployed EOA';
pub const CALLING_FROM_CA: felt252 = 'EOA: from is a contract account';

#[derive(Drop, Copy, PartialEq)]
pub enum EVMError {
StackOverflow,
StackUnderflow,
TypeConversionError: felt252,
NumericOperations: felt252,
InsufficientBalance,
ReturnDataOutOfBounds,
InvalidJump,
InvalidCode,
NotImplemented,
InvalidParameter: felt252,
InvalidOpcode: u8,
WriteInStaticContext,
Collision,
OutOfGas,
Assertion,
DepthLimit,
MemoryLimitOOG,
NonceOverflow
}

#[generate_trait]
pub impl EVMErrorImpl of EVMErrorTrait {
fn to_string(self: EVMError) -> felt252 {
match self {
EVMError::StackOverflow => 'stack overflow',
EVMError::StackUnderflow => 'stack underflow',
EVMError::TypeConversionError(error_message) => error_message,
EVMError::NumericOperations(error_message) => error_message,
EVMError::InsufficientBalance => 'insufficient balance',
EVMError::ReturnDataOutOfBounds => 'return data out of bounds',
EVMError::InvalidJump => 'invalid jump destination',
EVMError::InvalidCode => 'invalid code',
EVMError::NotImplemented => 'not implemented',
EVMError::InvalidParameter(error_message) => error_message,
// TODO: refactor with dynamic strings once supported
EVMError::InvalidOpcode => 'invalid opcode'.into(),
EVMError::WriteInStaticContext => 'write protection',
EVMError::Collision => 'create collision'.into(),
EVMError::OutOfGas => 'out of gas'.into(),
EVMError::Assertion => 'assertion failed'.into(),
EVMError::DepthLimit => 'max call depth exceeded'.into(),
EVMError::MemoryLimitOOG => 'memory limit out of gas'.into(),
EVMError::NonceOverflow => 'nonce overflow'.into(),
}
}

fn to_bytes(self: EVMError) -> Span<u8> {
let error_message: felt252 = self.to_string();
let error_message: u256 = error_message.into();
error_message.to_be_bytes()
}
}

pub impl DebugEVMError of Debug<EVMError> {
fn fmt(self: @EVMError, ref f: Formatter) -> Result<(), Error> {
let error_message = (*self).to_string();
Display::fmt(@error_message, ref f)
}
}

#[inline(always)]
pub fn ensure(cond: bool, err: EVMError) -> Result<(), EVMError> {
if cond {
Result::Ok(())
} else {
Result::Err(err)
}
}

// LENGTH
pub const RLP_EMPTY_INPUT: felt252 = 'KKT: EmptyInput';
pub const RLP_INPUT_TOO_SHORT: felt252 = 'KKT: InputTooShort';

#[derive(Drop, Copy, PartialEq, Debug)]
pub enum RLPError {
EmptyInput,
InputTooShort,
InvalidInput,
Custom: felt252,
NotAString,
FailedParsingU128,
FailedParsingU256,
FailedParsingAddress,
FailedParsingAccessList,
NotAList
}


pub impl RLPErrorIntoU256 of Into<RLPError, u256> {
fn into(self: RLPError) -> u256 {
match self {
RLPError::EmptyInput => 'input is null'.into(),
RLPError::InputTooShort => 'input too short'.into(),
RLPError::InvalidInput => 'rlp input not conform'.into(),
RLPError::Custom(msg) => msg.into(),
RLPError::NotAString => 'rlp input is not a string'.into(),
RLPError::FailedParsingU128 => 'rlp failed parsing u128'.into(),
RLPError::FailedParsingU256 => 'rlp failed parsing u256'.into(),
RLPError::FailedParsingAddress => 'rlp failed parsing address'.into(),
RLPError::FailedParsingAccessList => 'rlp failed parsing access_list'.into(),
RLPError::NotAList => 'rlp input is not a list'.into()
}
}
}

#[generate_trait]
pub impl RLPErrorImpl<T> of RLPErrorTrait<T> {
fn map_err(self: Result<T, RLPError>) -> Result<T, EthTransactionError> {
match self {
Result::Ok(val) => Result::Ok(val),
Result::Err(error) => { Result::Err(EthTransactionError::RLPError(error)) }
}
}
}

#[derive(Drop, Copy, PartialEq, Debug)]
pub enum EthTransactionError {
RLPError: RLPError,
ExpectedRLPItemToBeList,
ExpectedRLPItemToBeString,
TransactionTypeError,
// the usize represents the encountered length of payload
TopLevelRlpListWrongLength: usize,
// the usize represents the encountered length of payload
LegacyTxWrongPayloadLength: usize,
// the usize represents the encountered length of payload
TypedTxWrongPayloadLength: usize,
IncorrectChainId,
IncorrectAccountNonce,
/// If the transaction's fee is less than the base fee of the block
FeeCapTooLow,
/// Thrown to ensure no one is able to specify a transaction with a tip higher than the total
/// fee cap.
TipAboveFeeCap,
/// Thrown to ensure no one is able to specify a transaction with a tip that is too high.
TipVeryHigh,
Other: felt252
}
5 changes: 2 additions & 3 deletions src/factory.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ pub mod Factory {
}

#[constructor]
fn constructor(ref self: ContractState, lens: ContractAddress, account_class: ClassHash, dev: ContractAddress) {
self.account_class.write(account_class);
self.lens.write(lens);
fn constructor(ref self: ContractState, dev: ContractAddress) {
// todo write initial values to storage
self.dev.write(dev);
}

Expand Down
3 changes: 3 additions & 0 deletions src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ pub mod accounts {
pub mod base;
pub mod utils;
}

pub mod utils;
pub mod errors;
Loading

0 comments on commit 896b1ee

Please sign in to comment.