diff --git a/aptos-move/framework/aptos-framework/doc/primary_fungible_store.md b/aptos-move/framework/aptos-framework/doc/primary_fungible_store.md
index fe8d3418f93d7..28b1374e4f850 100644
--- a/aptos-move/framework/aptos-framework/doc/primary_fungible_store.md
+++ b/aptos-move/framework/aptos-framework/doc/primary_fungible_store.md
@@ -25,6 +25,9 @@ fungible asset to it. This emits an deposit event.
- [Function `primary_store_address`](#0x1_primary_fungible_store_primary_store_address)
- [Function `primary_store`](#0x1_primary_fungible_store_primary_store)
- [Function `primary_store_exists`](#0x1_primary_fungible_store_primary_store_exists)
+- [Function `primary_store_address_inlined`](#0x1_primary_fungible_store_primary_store_address_inlined)
+- [Function `primary_store_inlined`](#0x1_primary_fungible_store_primary_store_inlined)
+- [Function `primary_store_exists_inlined`](#0x1_primary_fungible_store_primary_store_exists_inlined)
- [Function `balance`](#0x1_primary_fungible_store_balance)
- [Function `is_balance_at_least`](#0x1_primary_fungible_store_is_balance_at_least)
- [Function `is_frozen`](#0x1_primary_fungible_store_is_frozen)
@@ -280,6 +283,86 @@ Return whether the given account's primary store exists.
+
+
+
+
+## Function `primary_store_address_inlined`
+
+Get the address of the primary store for the given account.
+Use instead of the corresponding view functions for dispatchable hooks to avoid circular dependencies of modules.
+
+
+
public fun primary_store_address_inlined<T: key>(owner: address, metadata: object::Object<T>): address
+
+
+
+
+
+Implementation
+
+
+public inline fun primary_store_address_inlined<T: key>(owner: address, metadata: Object<T>): address {
+ let metadata_addr = object::object_address(&metadata);
+ object::create_user_derived_object_address(owner, metadata_addr)
+}
+
+
+
+
+
+
+
+
+## Function `primary_store_inlined`
+
+Get the primary store object for the given account.
+Use instead of the corresponding view functions for dispatchable hooks to avoid circular dependencies of modules.
+
+
+public fun primary_store_inlined<T: key>(owner: address, metadata: object::Object<T>): object::Object<fungible_asset::FungibleStore>
+
+
+
+
+
+Implementation
+
+
+public inline fun primary_store_inlined<T: key>(owner: address, metadata: Object<T>): Object<FungibleStore> {
+ let store = primary_store_address_inlined(owner, metadata);
+ object::address_to_object(store)
+}
+
+
+
+
+
+
+
+
+## Function `primary_store_exists_inlined`
+
+Return whether the given account's primary store exists.
+Use instead of the corresponding view functions for dispatchable hooks to avoid circular dependencies of modules.
+
+
+public fun primary_store_exists_inlined<T: key>(account: address, metadata: object::Object<T>): bool
+
+
+
+
+
+Implementation
+
+
+public inline fun primary_store_exists_inlined<T: key>(account: address, metadata: Object<T>): bool {
+ fungible_asset::store_exists(primary_store_address_inlined(account, metadata))
+}
+
+
+
+
diff --git a/aptos-move/framework/aptos-framework/sources/primary_fungible_store.move b/aptos-move/framework/aptos-framework/sources/primary_fungible_store.move
index 18b410c0373e1..fc20e1cf311a6 100644
--- a/aptos-move/framework/aptos-framework/sources/primary_fungible_store.move
+++ b/aptos-move/framework/aptos-framework/sources/primary_fungible_store.move
@@ -104,6 +104,26 @@ module aptos_framework::primary_fungible_store {
fungible_asset::store_exists(primary_store_address(account, metadata))
}
+ /// Get the address of the primary store for the given account.
+ /// Use instead of the corresponding view functions for dispatchable hooks to avoid circular dependencies of modules.
+ public inline fun primary_store_address_inlined(owner: address, metadata: Object): address {
+ let metadata_addr = object::object_address(&metadata);
+ object::create_user_derived_object_address(owner, metadata_addr)
+ }
+
+ /// Get the primary store object for the given account.
+ /// Use instead of the corresponding view functions for dispatchable hooks to avoid circular dependencies of modules.
+ public inline fun primary_store_inlined(owner: address, metadata: Object): Object {
+ let store = primary_store_address_inlined(owner, metadata);
+ object::address_to_object(store)
+ }
+
+ /// Return whether the given account's primary store exists.
+ /// Use instead of the corresponding view functions for dispatchable hooks to avoid circular dependencies of modules.
+ public inline fun primary_store_exists_inlined(account: address, metadata: Object): bool {
+ fungible_asset::store_exists(primary_store_address_inlined(account, metadata))
+ }
+
#[view]
/// Get the balance of `account`'s primary store.
public fun balance(account: address, metadata: Object): u64 {
diff --git a/aptos-move/move-examples/fungible_asset/stablecoin/sources/usdk.move b/aptos-move/move-examples/fungible_asset/stablecoin/sources/usdk.move
index 666d85cfb0a8a..d96baececf837 100644
--- a/aptos-move/move-examples/fungible_asset/stablecoin/sources/usdk.move
+++ b/aptos-move/move-examples/fungible_asset/stablecoin/sources/usdk.move
@@ -328,8 +328,10 @@ module stablecoin::usdk {
// Check that the account is not denylisted by checking the frozen flag on the primary store
fun assert_not_denylisted(account: address) {
let metadata = metadata();
- if (primary_fungible_store::primary_store_exists(account, metadata)) {
- assert!(!fungible_asset::is_frozen(primary_fungible_store::primary_store(account, metadata)), EDENYLISTED);
+ // CANNOT call into pfs::store_exists in our withdraw/deposit hooks as it creates possibility of a circular dependency.
+ // Instead, we will call the inlined version of the function.
+ if (primary_fungible_store::primary_store_exists_inlined(account, metadata)) {
+ assert!(!fungible_asset::is_frozen(primary_fungible_store::primary_store_inlined(account, metadata)), EDENYLISTED);
}
}