diff --git a/src/interfaces.cairo b/src/interfaces.cairo index 5696a43..71d3fe0 100644 --- a/src/interfaces.cairo +++ b/src/interfaces.cairo @@ -190,6 +190,16 @@ trait IZToken { /// Returns the actual amount transferred. fn transfer_all(ref self: TContractState, recipient: ContractAddress) -> felt252; + /// Emits raw balances of a list of users via the `EchoRawBalance` event. + /// + /// This function (and the event) exists as there used to be a bug in this contract where the + /// `RawTransfer` event was missing in some cases, making it impossible to track accurate raw + /// balances using `RawTransfer`. The bug itself has been fixed but the `RawTransfer` history of + /// users before the fix is broken. This event enables indexers to calibrate raw balances. Once + /// deployed, this event must be emitted for any user who has ever placed a deposit before the + /// contract upgrade. + fn echo_raw_balances(ref self: TContractState, users: Span); + // // Permissioned entrypoints // diff --git a/src/z_token.cairo b/src/z_token.cairo index 860756e..e21b06c 100644 --- a/src/z_token.cairo +++ b/src/z_token.cairo @@ -6,6 +6,7 @@ mod errors; #[starknet::contract] mod ZToken { + use core::array::SpanTrait; use starknet::{ClassHash, ContractAddress}; // Hack to simulate the `crate` keyword @@ -35,6 +36,7 @@ mod ZToken { Transfer: Transfer, Approval: Approval, RawTransfer: RawTransfer, + EchoRawBalance: EchoRawBalance, ContractUpgraded: ContractUpgraded, OwnershipTransferred: OwnershipTransferred, } @@ -62,6 +64,12 @@ mod ZToken { face_value: felt252, } + #[derive(Drop, PartialEq, starknet::Event)] + struct EchoRawBalance { + user: ContractAddress, + raw_balance: felt252, + } + #[derive(Drop, PartialEq, starknet::Event)] struct ContractUpgraded { new_class_hash: ClassHash, @@ -178,6 +186,10 @@ mod ZToken { external::transfer_all(ref self, recipient) } + fn echo_raw_balances(ref self: ContractState, mut users: Span) { + external::echo_raw_balances(ref self, users) + } + fn upgrade(ref self: ContractState, new_implementation: ClassHash) { external::upgrade(ref self, new_implementation) } diff --git a/src/z_token/external.cairo b/src/z_token/external.cairo index 2bf4411..4ff1a4b 100644 --- a/src/z_token/external.cairo +++ b/src/z_token/external.cairo @@ -167,6 +167,20 @@ fn transfer_all(ref self: ContractState, recipient: ContractAddress) -> felt252 transferred_amount } +fn echo_raw_balances(ref self: ContractState, mut users: Span) { + while let Option::Some(user) = users + .pop_front() { + self + .emit( + contract::Event::EchoRawBalance( + contract::EchoRawBalance { + user: *user, raw_balance: self.raw_balances.read(*user) + } + ) + ); + }; +} + fn upgrade(ref self: ContractState, new_implementation: ClassHash) { ownable::assert_only_owner(@self); replace_class_syscall(new_implementation).unwrap_syscall();