Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make return type to dictionary for discoverability of vault types #127

Merged
merged 3 commits into from
Mar 16, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions contracts/FungibleToken.cdc
Original file line number Diff line number Diff line change
@@ -112,25 +112,25 @@ pub contract interface FungibleToken {

/// Below is referenced from the FLIP #69 https://github.com/onflow/flips/blob/main/flips/20230206-fungible-token-vault-type-discovery.md
///
/// Returns the Vault types that the the receiver is able to accept in its `deposit` method
/// this then it would return `[Type<@FlowToken.Vault>()]` and if any custom receiver
/// uses the default implementation then it would return empty array as its parent
/// Returns the dictionary of Vault types that the the receiver is able to accept in its `deposit` method
/// this then it would return `{Type<@FlowToken.Vault>(): true}` and if any custom receiver
/// uses the default implementation then it would return empty dictionary as its parent
/// resource doesn't conform with the `FungibleToken.Vault` resource.
///
/// Custom receiver implementations are expected to upgrade their contracts to add an implementation
/// that supports this method because it is very valuable for various applications to have.
///
/// @return list of supported deposit vault types by the implementing resource.
/// @return dictionary of supported deposit vault types by the implementing resource.
///
pub fun getSupportedVaultTypes(): [Type] {
pub fun getSupportedVaultTypes(): {Type: Bool} {
// Below check is implemented to make sure that run-time type would
// only get returned when the parent resource conforms with `FungibleToken.Vault`.
if self.getType().isSubtype(of: Type<@FungibleToken.Vault>()) {
return [self.getType()]
return {self.getType(): true}
} else {
// Return an empty array as the default value for resource who don't
// Return an empty dictionary as the default value for resource who don't
// implement `FungibleToken.Vault`, such as `FungibleTokenSwitchboard`, `TokenForwarder` etc.
return []
return {}
}
}
}
11 changes: 8 additions & 3 deletions contracts/FungibleTokenSwitchboard.cdc
Original file line number Diff line number Diff line change
@@ -230,9 +230,14 @@ pub contract FungibleTokenSwitchboard {
/// A getter function that returns the token types supported by this resource,
/// which can be deposited using the 'deposit' function.
///
/// @return Array of FT types that can be deposited.
pub fun getSupportedVaultTypes(): [Type] {
return self.getVaultTypes()
/// @return Dictionary of FT types that can be deposited.
pub fun getSupportedVaultTypes(): {Type: Bool} {
let supportedVaults: {Type: Bool} = {}
let vaultTypes = self.getVaultTypes()
for vaultT in vaultTypes {
supportedVaults.insert(key: vaultT, true)
}
return supportedVaults
}

init() {
8 changes: 5 additions & 3 deletions contracts/utility/TokenForwarding.cdc
Original file line number Diff line number Diff line change
@@ -56,12 +56,14 @@ pub contract TokenForwarding {
/// which can be deposited using the 'deposit' function.
///
/// @return Array of FT types that can be deposited.
pub fun getSupportedVaultTypes(): [Type] {
pub fun getSupportedVaultTypes(): {Type: Bool} {
if !self.recipient.check<&{FungibleToken.Receiver}>() {
return []
return {}
}
let vaultRef = self.recipient.borrow<&{FungibleToken.Receiver}>()!
return [vaultRef.getType()]
let supportedVaults: {Type: Bool} = {}
supportedVaults[vaultRef.getType()] = true
return supportedVaults
}

init(recipient: Capability) {
18 changes: 9 additions & 9 deletions lib/go/contracts/internal/assets/assets.go

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions lib/go/templates/internal/assets/assets.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/js/test/core_features.test.js
Original file line number Diff line number Diff line change
@@ -131,7 +131,7 @@ describe("CoreFeatures", ()=>{
});


test("should return an empty type array for custom receivers", async () => {
test("should return an empty type dictionary for custom receivers", async () => {
await shallPass(
sendTransaction({
code: setup_token_switchboard_tx,
25 changes: 14 additions & 11 deletions lib/js/test/mocks/contracts/Token.cdc
Original file line number Diff line number Diff line change
@@ -116,22 +116,25 @@ pub contract interface Token {

/// Below is referenced from the FLIP #69 https://github.com/onflow/flips/blob/main/flips/20230206-fungible-token-vault-type-discovery.md
///
/// Returns the type of implementing resource i.e If `FlowToken.Vault` implements
/// this then it would return `[Type<@FlowToken.Vault>()]` and if any custom receiver
/// uses the default implementation then it would return empty array as its parent
/// resource doesn't conform with the `Token.Vault` resource.
/// Returns the dictionary of Vault types that the the receiver is able to accept in its `deposit` method
/// this then it would return `{Type<@FlowToken.Vault>(): true}` and if any custom receiver
/// uses the default implementation then it would return empty dictionary as its parent
/// resource doesn't conform with the `FungibleToken.Vault` resource.
///
/// @return list of supported vault types by the implemented resource.
/// Custom receiver implementations are expected to upgrade their contracts to add an implementation
/// that supports this method because it is very valuable for various applications to have.
///
/// @return dictionary of supported deposit vault types by the implementing resource.
///
pub fun getSupportedVaultTypes() :[Type] {
pub fun getSupportedVaultTypes(): {Type: Bool} {
// Below check is implemented to make sure that run-time type would
// only get returned when the parent resource conforms with `Token.Vault`.
// only get returned when the parent resource conforms with `FungibleToken.Vault`.
if self.getType().isSubtype(of: Type<@Token.Vault>()) {
return [self.getType()]
return {self.getType(): true}
} else {
// Return empty array as the default value for the resource who don't
// implements `Token.Vault`, such as `FungibleTokenSwitchboard`, `TokenForwarder` etc.
return []
// Return an empty dictionary as the default value for resource who don't
// implement `FungibleToken.Vault`, such as `FungibleTokenSwitchboard`, `TokenForwarder` etc.
return {}
}
}
}
8 changes: 4 additions & 4 deletions lib/js/test/mocks/contracts/TokenForwarding.cdc
Original file line number Diff line number Diff line change
@@ -55,13 +55,13 @@ pub contract TokenForwarding {
/// A getter function that returns the token types supported by this resource,
/// which can be deposited using the 'deposit' function.
///
/// @return Array of FT types that can be deposited.
pub fun getSupportedVaultTypes(): [Type] {
/// @return Dictionary of FT types that can be deposited.
pub fun getSupportedVaultTypes(): {Type: Bool} {
if !self.recipient.check<&{Token.Receiver}>() {
return []
return {}
}
let vaultRef = self.recipient.borrow<&{Token.Receiver}>()!
return [vaultRef.getType()]
return {vaultRef.getType(): true}
}

init(recipient: Capability) {
2 changes: 1 addition & 1 deletion lib/js/test/mocks/transactions/safe_generic_transfer.cdc
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ transaction(amount: UFix64, to: Address, senderPath: StoragePath, receiverPath:
let receiverRef = getAccount(to).getCapability<&{Token.Receiver}>(receiverPath).borrow()!
let supportedVaultTypes = receiverRef.getSupportedVaultTypes()
// Only transfer tokens when the receiver is willing to receive the targeted FT.
if supportedVaultTypes.contains(self.tempVault.getType()) {
if supportedVaultTypes.containsKey(self.tempVault.getType()) {
// Transfer tokens from the signer's stored vault to the receiver capability
receiverRef.deposit(from: <-self.tempVault)
} else {
Original file line number Diff line number Diff line change
@@ -12,5 +12,5 @@ pub fun main(target: Address, targetPath: PublicPath): [Type] {
.borrow()
?? panic("Unable to borrow capability with restricted sub type {Token.Receiver} from path".concat(targetPath.toString()))
// Return the supported vault types.
return capabilityRef.getSupportedVaultTypes()
return (capabilityRef.getSupportedVaultTypes()).keys
}
2 changes: 1 addition & 1 deletion transactions/safe_generic_transfer.cdc
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ transaction(amount: UFix64, to: Address, senderPath: StoragePath, receiverPath:
let receiverRef = getAccount(to).getCapability<&{FungibleToken.Receiver}>(receiverPath).borrow()!
let supportedVaultTypes = receiverRef.getSupportedVaultTypes()
// Only transfer tokens when the receiver is willing to receive the targeted FT.
if supportedVaultTypes.contains(self.tempVault.getType()) {
if supportedVaultTypes.containsKey(self.tempVault.getType()) {
// Transfer tokens from the signer's stored vault to the receiver capability
receiverRef.deposit(from: <-self.tempVault)
} else {
2 changes: 1 addition & 1 deletion transactions/scripts/get_supported_vault_types.cdc
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ import FungibleToken from "../../contracts/FungibleToken.cdc"
/// `target` address should hold the capability which conforms with FungibleToken.Receiver restricted type
/// while it doesn't matter whether capability refers to fungible token or a custom receiver like
/// `FungibleTokenSwitchboard` or `TokenReceiver`. However `targetPath` tells where the capability stores
pub fun main(target: Address, targetPath: PublicPath): [Type] {
pub fun main(target: Address, targetPath: PublicPath): {Type: Bool} {

// Access the capability for the provided target address
let capabilityRef = getAccount(target)