address 0x2 { module Base { struct B has key {} public fun BASE_ADDR(): address { @0x2 } public fun put_b(s: &signer) { move_to(s, B {}); // the global invariants in 0x2::Test is instrumented here // but this instrumentation causes a warning becaues we do // not know how to instantiate the parameter T } spec module { fun has_b(): bool { exists(BASE_ADDR()) } } } module Test { use 0x2::Base; struct R has key { f: T, } public fun put_r(s: &signer, v: T) { Base::put_b(s); move_to(s, R { f: v }); // the global invariants in 0x2::Test is instrumented here // as well, not causing a warning and not verified. } spec module { fun has_r(): bool { exists>(Base::BASE_ADDR()) } } spec module { invariant update Base::has_b() ==> (has_r() ==> old(has_r())); // The above invariant should not verify, here is a counterexample: // // suppose we starts with an empty state, // put_r(@0x2, false) will violate the invariant, because // - Base::has_b() is true, // - has_r() is true, but // - old(has_r()) is false } } }