Skip to content

Instantly share code, notes, and snippets.

@ioanSL
Last active January 24, 2024 08:20
Show Gist options
  • Save ioanSL/ac85ad942bf16ae3a68f86f7e3e27d10 to your computer and use it in GitHub Desktop.
Save ioanSL/ac85ad942bf16ae3a68f86f7e3e27d10 to your computer and use it in GitHub Desktop.
Starknet batch messages
%lang starknet
from starkware.cairo.common.alloc import alloc
from starkware.cairo.common.cairo_builtins import HashBuiltin
from starkware.cairo.common.math import assert_nn
from starkware.starknet.common.messages import send_message_to_l1
from starkware.starknet.common.syscalls import (
get_caller_address,
)
//TODO: Change address to L1 contract able to handle multiple messages
const L1_CONTRACT_ADDRESS = (
0x23ba0C1766c2FcE5593917f0595f502137508408);
const MESSAGE_WITHDRAW = 0;
struct Message {
id: felt,
user: felt,
amount: felt,
executed: felt,
}
// A mapping from a user (L1 Ethereum address) to their balance.
@storage_var
func balance(user: felt) -> (res: felt) {
}
@storage_var
func _next_nonce() -> (res: felt) {
}
@storage_var
func _messages(nonce: felt, field: felt) -> (res: felt) {
}
// ******************TRANSACTIONS******************
func require_valid_nonce{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
nonce: felt
) {
let (next_nonce) = _next_nonce.read();
with_attr error_message("Invalid nonce") {
assert nonce = next_nonce;
}
return ();
}
@external
func submit_message{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
id: felt, user: felt, amount: felt, nonce: felt
) {
alloc_locals;
require_valid_nonce(nonce);
//let (caller) = get_caller_address();
// Store the tx descriptor
_messages.write(nonce=nonce, field=Message.id, value=id);
_messages.write(nonce=nonce, field=Message.user, value=user);
_messages.write(nonce=nonce, field=Message.amount, value=amount);
_next_nonce.write(value=nonce + 1);
return ();
}
@view
func get_next_nonce{
syscall_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
}() -> (nonce: felt){
let (nonce) = _next_nonce.read();
return (nonce=nonce);
}
@external
func execute_messages{
syscall_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
}(nonce: felt) -> (message_length: felt) {
// Make sure 'amount' is positive.
alloc_locals;
let (message_payload: felt*) = alloc();
let (message_len) = _recursively_build_message(nonce=nonce, message_payload=message_payload, ptr=0);
send_message_to_l1(
to_address=L1_CONTRACT_ADDRESS,
payload_size=message_len,
payload=message_payload,
);
return (message_length=message_len);
}
func _recursively_build_message{
syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr
}(nonce: felt, message_payload: felt*, ptr: felt) -> (message_payload_len: felt) {
let (next_nonce) = _next_nonce.read();
if (nonce == next_nonce) {
return (message_payload_len=ptr);
}
let (id) = _messages.read(nonce=nonce, field=Message.id);
let (user) = _messages.read(nonce=nonce, field=Message.user);
let (amount) = _messages.read(nonce=nonce, field=Message.amount);
let (executed) = _messages.read(nonce=nonce, field=Message.executed);
// Update balance
let (res) = balance.read(user=user);
tempvar new_balance = res - amount;
// Make sure the new balance will be positive.
assert_nn(new_balance);
// Update the new balance.
balance.write(user, new_balance);
// Build message
assert message_payload[ptr] = id;
assert message_payload[ptr + 1] = user;
assert message_payload[ptr + 2] = amount;
return _recursively_build_message(nonce + 1, message_payload, ptr + 3);
//return (message_payload_len=ptr);
}
@view
func get_message{
syscall_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
}(nonce: felt) -> (msg: Message){
let (id) = _messages.read(nonce=nonce, field=Message.id);
let (user) = _messages.read(nonce=nonce, field=Message.user);
let (amount) = _messages.read(nonce=nonce, field=Message.amount);
let (executed) = _messages.read(nonce=nonce, field=Message.executed);
// Read messages
let msg = Message(
id=id,
user=user,
amount=amount,
executed=executed,
);
return (msg=msg);
}
// ******************L1<->L2 Messages******************
@view
func get_balance{
syscall_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
}(user: felt) -> (balance: felt) {
let (res) = balance.read(user=user);
return (balance=res);
}
@external
func increase_balance{
syscall_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
}(user: felt, amount: felt) {
let (res) = balance.read(user=user);
balance.write(user, res + amount);
return ();
}
@l1_handler
func deposit{
syscall_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
}(from_address: felt, user: felt, amount: felt) {
// Make sure the message was sent by the intended L1 contract.
assert from_address = L1_CONTRACT_ADDRESS;
// Read the current balance.
let (res) = balance.read(user=user);
// Compute and update the new balance.
tempvar new_balance = res + amount;
balance.write(user, new_balance);
return ();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment