Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ pub fn call_contract<T: State + StateReader>(
calldata: Vec<Felt252>,
state: &mut T,
block_context: BlockContext,
caller_address: Address,
) -> Result<Vec<Felt252>, TransactionError> {
let contract_address = Address(contract_address);
let class_hash = state.get_class_hash_at(&contract_address)?;
Expand All @@ -118,7 +119,6 @@ pub fn call_contract<T: State + StateReader>(
let signature = vec![];
let max_fee = 1000000000;
let initial_gas = 1000000000;
let caller_address = Address(0.into());
let version = 0;

let execution_entrypoint = ExecutionEntryPoint::new(
Expand Down Expand Up @@ -319,6 +319,7 @@ mod test {
calldata,
&mut state,
BlockContext::default(),
Address(0.into()),
)
.unwrap();

Expand Down
254 changes: 254 additions & 0 deletions src/testing/erc20.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
#![allow(unused_imports)]
use std::{collections::HashMap, io::Bytes, path::Path, vec};

use crate::{
call_contract,
definitions::{
block_context::{BlockContext, StarknetChainId},
constants::CONSTRUCTOR_ENTRY_POINT_SELECTOR,
},
execution::{
execution_entry_point::ExecutionEntryPoint, CallType, TransactionExecutionContext,
},
services::api::contract_classes::deprecated_contract_class::ContractClass,
state::{
cached_state::CachedState,
in_memory_state_reader::InMemoryStateReader,
state_api::{State, StateReader},
ExecutionResourcesManager,
},
transaction::{error::TransactionError, DeployAccount, InvokeFunction},
utils::calculate_sn_keccak,
EntryPointType, Felt252,
};
use cairo_lang_starknet::casm_contract_class::CasmContractClass;
use cairo_vm::felt::felt_str;
use lazy_static::lazy_static;
use num_traits::Zero;
pub const ERC20_CONTRACT_PATH: &str = "starknet_programs/cairo2/ERC20.casm";
use crate::{
state::state_cache::StorageEntry,
utils::{felt_to_hash, Address, ClassHash},
};

use super::{
get_contract_class, new_starknet_block_context_for_testing, ACCOUNT_CONTRACT_PATH, ACTUAL_FEE,
TEST_ACCOUNT_CONTRACT_ADDRESS, TEST_ACCOUNT_CONTRACT_CLASS_HASH, TEST_CLASS_HASH,
TEST_CONTRACT_ADDRESS, TEST_CONTRACT_PATH, TEST_ERC20_ACCOUNT_BALANCE_KEY,
TEST_ERC20_CONTRACT_CLASS_HASH,
};

#[test]
fn test_erc20_cairo2() {
// data to deploy
let erc20_class_hash: ClassHash = [2; 32];
let test_data = include_bytes!("../../starknet_programs/cairo2/erc20.casm");
let test_contract_class: CasmContractClass = serde_json::from_slice(test_data).unwrap();

// Create the deploy contract class
let program_data = include_bytes!("../../starknet_programs/cairo2/deploy_erc20.casm");
let contract_class: CasmContractClass = serde_json::from_slice(program_data).unwrap();
let entrypoints = contract_class.clone().entry_points_by_type;
let entrypoint_selector = &entrypoints.external.get(0).unwrap().selector;

// Create state reader with class hash data
let mut contract_class_cache = HashMap::new();

let address = Address(1111.into());
let class_hash: ClassHash = [1; 32];
let nonce = Felt252::zero();

contract_class_cache.insert(class_hash, contract_class);
contract_class_cache.insert(erc20_class_hash, test_contract_class);

let mut state_reader = InMemoryStateReader::default();
state_reader
.address_to_class_hash_mut()
.insert(address.clone(), class_hash);
state_reader
.address_to_nonce_mut()
.insert(address.clone(), nonce);

// Create state from the state_reader and contract cache.
let mut state = CachedState::new(state_reader, None, Some(contract_class_cache));

let name_ = Felt252::from_bytes_be(b"some-token");
let symbol_ = Felt252::from_bytes_be(b"my-super-awesome-token");
let decimals_ = Felt252::from(24);
let initial_supply = Felt252::from(1000);
let recipient =
felt_str!("397149464972449753182583229366244826403270781177748543857889179957856017275");
let erc20_salt = felt_str!("1234");
// arguments of deploy contract
let calldata = vec![
Felt252::from_bytes_be(&erc20_class_hash),
erc20_salt,
recipient,
name_,
decimals_,
initial_supply,
symbol_,
];
// set up remaining structures

let caller_address = Address(0000.into());
let entry_point_type = EntryPointType::External;

let exec_entry_point = ExecutionEntryPoint::new(
address,
calldata,
Felt252::new(entrypoint_selector.clone()),
caller_address,
entry_point_type,
Some(CallType::Delegate),
Some(class_hash),
100_000_000_000,
);

// Execute the entrypoint
let block_context = BlockContext::default();
let mut tx_execution_context = TransactionExecutionContext::new(
Address(0.into()),
Felt252::zero(),
Vec::new(),
0,
10.into(),
block_context.invoke_tx_max_n_steps(),
1.into(),
);
let mut resources_manager = ExecutionResourcesManager::default();

let call_info = exec_entry_point
.execute(
&mut state,
&block_context,
&mut resources_manager,
&mut tx_execution_context,
false,
)
.unwrap();
let erc20_address = call_info.retdata.get(0).unwrap().clone();

// ACCOUNT 1
let program_data_account =
include_bytes!("../../starknet_programs/cairo2/hello_world_account.casm");
let contract_class_account: CasmContractClass =
serde_json::from_slice(program_data_account).unwrap();

state
.set_compiled_class(&felt_str!("1"), contract_class_account)
.unwrap();

let contract_address_salt =
felt_str!("2669425616857739096022668060305620640217901643963991674344872184515580705509");

let internal_deploy_account = DeployAccount::new(
felt_str!("1").to_be_bytes(),
0,
1.into(),
Felt252::zero(),
vec![2.into()],
vec![
felt_str!(
"3233776396904427614006684968846859029149676045084089832563834729503047027074"
),
felt_str!(
"707039245213420890976709143988743108543645298941971188668773816813012281203"
),
],
contract_address_salt,
StarknetChainId::TestNet.to_felt(),
None,
)
.unwrap();

let account_address_1 = internal_deploy_account
.execute(&mut state, &Default::default())
.unwrap()
.validate_info
.unwrap()
.contract_address;

// ACCOUNT 2
let program_data_account =
include_bytes!("../../starknet_programs/cairo2/hello_world_account.casm");
let contract_class_account: CasmContractClass =
serde_json::from_slice(program_data_account).unwrap();

state
.set_compiled_class(&felt_str!("1"), contract_class_account)
.unwrap();

let contract_address_salt = felt_str!("123123123123123");

let internal_deploy_account = DeployAccount::new(
felt_str!("1").to_be_bytes(),
0,
1.into(),
Felt252::zero(),
vec![2.into()],
vec![
felt_str!(
"3233776396904427614006684968846859029149676045084089832563834729503047027074"
),
felt_str!(
"707039245213420890976709143988743108543645298941971188668773816813012281203"
),
],
contract_address_salt,
StarknetChainId::TestNet.to_felt(),
None,
)
.unwrap();

let account_address_2 = internal_deploy_account
.execute(&mut state, &Default::default())
.unwrap()
.validate_info
.unwrap()
.contract_address;

// TRANSFER
let entrypoint_selector = Felt252::from_bytes_be(&calculate_sn_keccak(b"transfer"));
let calldata = vec![account_address_2.clone().0, Felt252::from(123)];

let retdata = call_contract(
erc20_address.clone(),
entrypoint_selector,
calldata,
&mut state,
BlockContext::default(),
account_address_1.clone(),
)
.unwrap();

assert!(retdata.is_empty());

// GET BALANCE ACCOUNT 1
let entrypoint_selector = Felt252::from_bytes_be(&calculate_sn_keccak(b"balance_of"));
let retdata = call_contract(
erc20_address.clone(),
entrypoint_selector,
vec![account_address_1.clone().0],
&mut state,
BlockContext::default(),
account_address_1.clone(),
)
.unwrap();

assert_eq!(retdata, vec![877.into()]);

// GET BALANCE ACCOUNT 2
let entrypoint_selector = Felt252::from_bytes_be(&calculate_sn_keccak(b"balance_of"));
let retdata = call_contract(
erc20_address,
entrypoint_selector,
vec![account_address_2.0],
&mut state,
BlockContext::default(),
account_address_1,
)
.unwrap();

assert_eq!(retdata, vec![123.into()]);
}
1 change: 1 addition & 0 deletions src/testing/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod erc20;
pub mod state;
pub mod state_error;
pub mod type_utils;
Expand Down
35 changes: 35 additions & 0 deletions starknet_programs/cairo2/deploy_erc20.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use starknet::contract_address::ContractAddress;
use starknet::class_hash::ClassHash;
#[starknet::interface]
trait IDeployTest<TContractState> {
fn deploy_test(self: @TContractState, class_hash: ClassHash, contract_address_salt: felt252, recipient: felt252, name: felt252, decimals: felt252, initial_supply: felt252, symbol: felt252) -> (core::starknet::contract_address::ContractAddress, core::array::Span::<core::felt252>);
}

#[starknet::contract]
mod DeployTest {
use core::result::ResultTrait;
use starknet::syscalls::deploy_syscall;
use starknet::class_hash::ClassHash;
use starknet::contract_address::ContractAddress;
use starknet::class_hash::Felt252TryIntoClassHash;
use option::OptionTrait;
use traits::TryInto;
use array::ArrayTrait;

#[storage]
struct Storage {
}

#[external(v0)]
impl DeployTest of super::IDeployTest<ContractState> {
fn deploy_test(self: @ContractState, class_hash: ClassHash, contract_address_salt: felt252, recipient: felt252, name: felt252, decimals: felt252, initial_supply: felt252, symbol: felt252) -> (core::starknet::contract_address::ContractAddress, core::array::Span::<core::felt252>) {
let mut calldata = ArrayTrait::new();
calldata.append(recipient);
calldata.append(name);
calldata.append(decimals);
calldata.append(initial_supply);
calldata.append(symbol);
deploy_syscall(class_hash, contract_address_salt, calldata.span(), false).unwrap()
}
}
}
Loading