Skip to content

Conversation

@sisyphusSmiling
Copy link
Contributor

@sisyphusSmiling sisyphusSmiling commented Jul 31, 2025

This FLIP is tracked by: #338

@sisyphusSmiling sisyphusSmiling self-assigned this Jul 31, 2025
@sisyphusSmiling sisyphusSmiling added the flip: application Application FLIP label Jul 31, 2025
@bluesign
Copy link
Collaborator

bluesign commented Aug 1, 2025

This is very interesting approach; looks a bit like my FLIX alternative ( composeability part ) but also I think lines are harder here.

To be honest I would love to see DefiActions as a subset of Actions framework, I believe it would be more meaningful.

I just read super fast, mostly code parts, I will try to dive deeper next week. ( torturing myself with linux DE this weekend )

@sisyphusSmiling
Copy link
Contributor Author

Thanks for the initial feedback @bluesign! I don't remember seeing your FLIX alternative @bluesign, but I'm interested in hearing more about it.

To be honest I would love to see DefiActions as a subset of Actions framework, I believe it would be more meaningful.

What do you mean "as a subset of Actions framework"? Is that your FLIX alternative or are you speaking to a broader potential standard?

3. **Swapper**: Exchanges one token type for another (e.g. targetted DEX trades, multi-protocol aggregated swaps)
4. **PriceOracle**: Provides price data for assets (e.g. external price feeds, DEX prices, price caching)
5. **Flasher**: Provides flash loans with atomic repayment (e.g. arbitrage, liquidations)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We ran into a usecase which didn't fit into the above model: Adding liquidity to a pool. It's basically a swap between two token types and LP tokens.
We solved for now by implementing "zap" instead: adding liquidity with one token type (it does an extra swap to the second token to have both tokens)

@sisyphusSmiling sisyphusSmiling marked this pull request as ready for review August 4, 2025 22:43
@sisyphusSmiling sisyphusSmiling requested review from Kay-Zee, dete, joshuahannan and kgrgpg and removed request for kgrgpg August 4, 2025 22:43
@bluesign
Copy link
Collaborator

bluesign commented Aug 5, 2025

@sisyphusSmiling I was talking general. i think this is great idea to standardize things like lego blocks. But I think it is also important to build on something generic.

Like now we have DefiActions; later we can have NFTActions, TopshotActions, etc ( something like MetadataViews ). As we did in metadataViews, it would be nice to define base Action, and build on it.

Not sure if interface is the best way to go here.

@sisyphusSmiling
Copy link
Contributor Author

@bluesign while ideating there were mentions of expanding the underlying concept of DeFi Actions to other use cases - DAO Actions, Gaming Actions, NFT Actions, etc. And the existence of DeFiActions certainly doesn't prevent additional types of actions from existing. In fact, it's a hope that the mental model of an "action" as a composable, tightly scoped component with single responsibility enhances composable architectures. Though I have difficulty thinking of a way to create an ecosystem of composable parts for specific use cases (DeFi, governance, NFTs, etc) without common interfaces given we lack generics in Cadence. Did you have any ideas on that front?

Also, the FLIP has been updated to place DeFi Actions under the broader umbrella of "actions" as a concept and way of thinking about composable contract development.

@sisyphusSmiling sisyphusSmiling changed the title FLIP 338: DeFiActions Standard FLIP 338: Flow Actions: Composable Standards for Protocols Aug 5, 2025
Comment on lines +2972 to +2973
**Single Asset Type**
- Current [Sink](#sink-interface) and [Source](#source-interface) interfaces only support single Vault operations, which may not accommodate multi-asset actions such as liquidity provision or removal that require handling multiple Vaults simultaneously.
Copy link
Contributor

@jribbink jribbink Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a blocker we ran into building a Source on top of Increment Fi Staking. Because all rewards must be withdrawn at the same time, and a source can only provide a single token type, it was unclear in the current single asset model how the source should handle excess output tokens that do not match the requested type.

I've thought a bit more about this, and have came up with the following:

Intuitively, it feels that this can just be part of the implementation, and that this should simply be passed as an initialization parameter. e.g. something like:

access(all) struct SomeSourceThatOverflows: Source {
    init (
        overflow: { Type: Sink }
    )
    // ...
}

Where all possible tokens types correspond to a respecive handler (Sink) for any excess tokens encountered.

Thoughts @sisyphusSmiling ?

@bjartek
Copy link
Contributor

bjartek commented Aug 6, 2025

I think this is a good idea. I could see many options on how to visualize what a tx is doing in flowscan based on this.

I agree with @bluesign on the generic part.

It would be so good to have an action to:

  • Initialize a vault and publish link it correctly
  • Initialize a nft collection
  • List an nft for sale
  • Buy an nft for sale

I have an endless amount if boilerplate thar is repeated in find repos.

@bluesign
Copy link
Collaborator

In fact, it's a hope that the mental model of an "action" as a composable, tightly scoped component with single responsibility enhances composable architectures

This is great idea, but I think the main issue I have here is Action and Interface used as interchangeable here. I feel action should be more generic to be honest. It is not possible to predict everything, and things can go ugly fast.

Interfaces are lacking a lot to cover Actions, then you will have a lot of boilerplate. ( other structs interfaces implementing said interface etc )

@bjartek
Copy link
Contributor

bjartek commented Sep 17, 2025

Did a little overview of this and I have a suggestion. Can we create a super interface Actions that has some of the structs? Right now many things is in DEFI actions this means that if we want to create other types of actions that is hard conceptually.

@sisyphusSmiling
Copy link
Contributor Author

@bjartek sorry, not sure I follow. Correct me if I'm wrong - I think you're asking if all actions regardless of purpose can share a common interface. Tbh I'm not sure what that could be given the variety of use cases.

The idea of an "action" is more philosophical than anything - a building block that accomplishes some task with a tight scope of responsibility and graceful failure so that any given action can be interchanged as blocks in larger, more complex workflows.

Fundamentally, any given "action" may do very different things from each other - a price oracle fetches a price while a swapper swaps tokens and a sink accepts deposits. However, when interacting with two of the same connectors, you don't have to concern yourself with the underlying implementation. Without some degree of assurance that every different "action" connector will share at least some functionality, I'm not sure how a super interface comes into play.

This is complicated by the amount of abstraction that can be packaged under a single connector. One Sink may simply deposit tokens to some underlying Vault, while another could be funnel depositing tokens to a complex DeFi workflow (e.g. adding liquidity into an LP position; adding collateral to a loan & pushing any additional borrowable value to a yield-bearing strategy).

That's to say that even the initialization patterns between the same action could be very different. However, importantly using them can be simplified - I have tokens to deposit, I stick them in a Sink- I don't worry about where they go, providing a lot of flexibility in the logic beneath that surface.

Do you have a shared super interface in mind?

@bluesign
Copy link
Collaborator

@sisyphusSmiling I think what @bjartek says is pretty similar to what I was saying.

Basically Action should just provide "introspection" on some superior interface. Rest is ( where defined here as action ) is actually optional. ( Even wrong without a superior interface )

This usually leads to assignable input/output connectors and generic execute method. More like an invocation pattern.

So in the end you can understand and execute action over a single basic interface. This is a basic requirement in my opinion.

@bjartek
Copy link
Contributor

bjartek commented Sep 19, 2025

We are currently brainstorming how to visualize and enhance actions in flowscan.

We can analyze the source of a tx and find all vars that are DefiActions. But what about when there are other actions? Marketplace actions, nft actions etc? How would you make a Source for a single NFT with a given ID of a given type? (In find we call this a ViewPointer, or the AuthPointer where you can withdraw it)

The defining sink source et all structs live in DefiAcfions not in Action. I see now that a Sink is very specific to an FT, so maybe some structs that live in Actions that are supertypes of all types of Sinks/Sources?

Also how can i in code know more metadata about an action? Views could work or something.

Does that help make this clearer @sisyphusSmiling

@bjartek
Copy link
Contributor

bjartek commented Sep 19, 2025

Another question this a bit more detail focused

 // Derive the path keys from the token types
    let flowKey = SwapConfig.SliceTokenTypeIdentifierFromVaultType(vaultTypeIdentifier: Type<@FlowToken.Vault>().identifier)
    let usdcFlowKey = SwapConfig.SliceTokenTypeIdentifierFromVaultType(vaultTypeIdentifier: Type<@USDCFlow.Vault>().identifier)

    // Minimal path Flow -> USDCFlow
    let swapper = IncrementFiSwapConnectors.Swapper(
      path: [
        flowKey,
        usdcFlowKey
      ],
      inVault: Type<@FlowToken.Vault>(),
      outVault: Type<@USDCFlow.Vault>(),
      uniqueID: nil
    )
    

To me this is the wrong level of abstraction. Why do i have to know about this path and the swap config stuff in here? I know there are increment fi swaps that can have complex paths, but has anybody ever used them. And if that is the case this could be a MultiPathSwapper.

IMHO this code should be

    // Minimal path Flow -> USDCFlow
    let swapper = IncrementFiSwapConnectors.Swapper(
      inVault: Type<@FlowToken.Vault>(),
      outVault: Type<@USDCFlow.Vault>(),
      uniqueID: nil
    )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flip: application Application FLIP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants