address 0x0 { module A { struct S has key { x: u64 } public fun read_at(addr: address): u64 acquires S { let s = borrow_global(addr); s.x } spec read_at { pragma opaque = true; aborts_if !exists(addr); ensures result == global(addr).x; } public fun mutate_at(addr: address) acquires S { let s = borrow_global_mut(addr); s.x = 2; } spec mutate_at { pragma opaque = true; ensures global(addr).x == 2; aborts_if !exists(addr); modifies global(addr); } } module B { use 0x0::A; struct T has key { x: u64 } public fun mutate_at_test_incorrect(addr1: address, addr2: address) acquires T { let x0 = A::read_at(addr2); let t = borrow_global_mut(addr1); t.x = 2; let x1 = A::read_at(addr2); spec { assert x0 == x1; }; } spec mutate_at_test_incorrect { pragma opaque = true; modifies global(addr2); } public fun move_to_test_incorrect(account: &signer, addr2: address) { let x0 = A::read_at(addr2); move_to(account, T{x: 2}); let x1 = A::read_at(addr2); spec { assert x0 == x1; }; } spec move_to_test_incorrect { pragma opaque = true; modifies global(addr2); } public fun move_from_test_incorrect(addr1: address, addr2: address): T acquires T { let x0 = A::read_at(addr2); let v = move_from(addr1); let x1 = A::read_at(addr2); spec { assert x0 == x1; }; v } spec move_from_test_incorrect { pragma opaque = true; modifies global(addr2); } public fun mutate_S_test1_incorrect(addr1: address, addr2: address) { let x0 = A::read_at(addr2); A::mutate_at(addr1); let x1 = A::read_at(addr2); spec { assert x0 == x1; }; } spec mutate_S_test1_incorrect { requires addr1 != addr2; modifies global(addr2); } public fun mutate_S_test2_incorrect(addr: address) { let x0 = A::read_at(addr); A::mutate_at(addr); let x1 = A::read_at(addr); spec { assert x0 == x1; }; } spec mutate_S_test2_incorrect { modifies global(addr); } } }