Last active
January 24, 2024 08:20
-
-
Save ioanSL/ac85ad942bf16ae3a68f86f7e3e27d10 to your computer and use it in GitHub Desktop.
Starknet batch messages
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%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