-
Notifications
You must be signed in to change notification settings - Fork 62
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
[spec] v2.2 - action chaining #18
Conversation
- providing multiple transactions (and eventually sign message) to a user | ||
- customized action metadata based on the user's wallet address | ||
- refreshing the blink metadata after a successful transaction | ||
- receive an API callback with the transaction signature for additional |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also proposing to explicitly highlight the behaviour on tx failed during confirmation - my proposal is to always send the tx signature to API regardless of confirmation status to enable basic error handling in all cases
- tx confirmed
- tx failed
- tx timed out
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the transaction failed to confirm, I would assume the action could be called again via the blink UI to attempt to repeat it. Is this not the case?
Having the ability to achieve a callback based on each of these solana transaction lifecycle events could be useful though. But it does feel like scope creep...
- How do you propose the blink-client denotes each of these lifecycle statuses?
- What should the UI do after the getting a response from the callback?
- Should only a single callback url for all these lifecycle events be supported? Or should the developer be able to define specific callback urls for each lifecycle event?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we generally have 2 options
a) As you proposing, assume the action should be called again via the blink UI to attempt to repeat it. I think it will work fine, but can be a bit annoying if you have a long chain and want to repeat only last action.
b) If next action with POST
type is defined, always pass the tx signature to backend regardless of confirmation result - backend can check signature status and make a decision about the next step, e.g. retrying last action, rather than to repeat the entire chain from the beginning
So, blink client in (b) just needs to always send tx signature to callback, backend then will return the next state that should be shown to user
How do you propose the blink-client denotes each of these lifecycle statuses?
No need for any special behaviour, just always pass tx signature to callback after tx confirmation stage finished
What should the UI do after the getting a response from the callback
Just render it, as it would do it for the any other next action
Should only a single callback url for all these lifecycle events be supported? Or should the developer be able to define specific callback urls for each lifecycle event?
I think single would be already good for the start - developers can just check signature status on their backend to decide what should be done next
So (b) just gives a bit more options to developer to handle potential tx errors, we just need to always send tx sig to callback. Does it still feels like scope creep to you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a) As you proposing, assume the action should be called again via the blink UI to attempt to repeat it. I think it will work fine, but can be a bit annoying if you have a long chain and want to repeat only last action.
I would not expect the blink-client to attempt to repeat the entire action chain from the start if the current action failed to confirm. That would be foolish lol. I would only the client to reattempt the current action.
No need for any special behaviour, just always pass tx signature to callback after tx confirmation stage finished
there would have to be some way to denote each of the lifecycle status you suggested ones though: tx confirmed
, tx failed
, and tx timed out
.
A transaction can fail for many reason on the client side. "tx failed" would be a generic failure vs "tx timeout" would be a specific one like an expired blockhash. it could fail preflight checks performed by the blink-client and or wallet.
many causes of a transaction failing of which would result in no tx id existing on chain. Therefore not giving much useful info to the action api to actually handle various error states. there would not always be a tx id to give to process on-chain errored transaction
Does it still feels like scope creep to you?
It does, but if we opt for a simple design that we can flush out quickly, I'm okay with it being in this spec update. It will for sure be useful for devlopers!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Long story short: I believe it's good enough to go with just reattempting the last action, we can improve error handling later as a separate sRFC.
I would not expect the blink-client to attempt to repeat the entire action chain from the start if the current action failed to confirm. That would be foolish lol. I would only the client to reattempt the current action.
Ahh, ok, then I've misunderstood. Reattempting the last action instead of the entire chain is good for the start
there would have to be some way to denote each of the lifecycle status you suggested ones though: tx confirmed, tx failed, and tx timed out.
In the future could still be a single callback, but with different payloads. Generally errors should have an error code + error message, that is useful info to pass to API together with the signature if it's available. E.g. see phantom deeplink callback https://docs.phantom.app/phantom-deeplinks/provider-methods/signandsendtransaction#reject. Not advocating to use the same structures, but this just gives an idea of data we could include.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To summarize, imo gtg with reattempting the last action
Let's skip error handling callback improvements and make them as a separate spec update, seems like we need broader discussion here
…roposal stricter & more extensible definition for next action
* the previous was successful. | ||
*/ | ||
next: NextActionLink; | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ActionPostResponse
should be as follows, allowing for form-like use-cases where tx approval is not required for each action and maybe just the last action in the chain required the approval.
export interface ActionPostResponse<T extends ActionType = ActionType> {
/**
* If the current action requires a transaction to be signed then this should be a base64 encoded serialized transaction
* If the current action does not require a transaction to be signed, then this should be null
*/
transaction: string | null;
/** describes the nature of the transaction */
message?: string;
links?: {
/**
* The next action in a successive chain of actions to be obtained after
* the previous was successful.
*/
next: NextActionLink;
};
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Form-like is needed. From a UX point of view, you don't want to sign more than once. So ideally, at every new screen, the developer gets new information and packages a final instruction for the user to sign. If you want to make users sign every screen, then you can too.
I would even make every chain/screen transaction optional. Maybe you sign on the first screen and the last screen is an optional survey. Maybe there is no transaction at all, simply collecting info, e.g. pubkeys
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, that's why the transaction can be either string
or null
, making the transaction optional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this is a useful thing to support form-like experiences, actions are still currently required to return a transaction, since the user is required to sign a transaction.
Implementing something like this is planned in general, but not within this spec change / proposal. When sign message support is added, maybe in there?
@thearyanag maybe you could post a more complete sRFC with details about a proposal to support some sort of "non signing action" support? My gut is that something like this should not be allowed on the root action, so the user is still required to "initiate a session" within the blink by signing a transaction (or eventually a message), then they could complete form-like experiences
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the user required to sign transaction?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Blink will become inconvenient if you have to sign more than once. Unless it is a feature of that blink to sign multiple times, I believe requiring more than one signature is UX misstep.
Fill form, sign, fill new form, sign again. Devs stuck with partial signs to handle. Find the Blink again, load the partial properly.
At which point you might as well redirect the user to an external site to provide a streamline experience.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you on form based things. I agree that the idea of the user not being always required to sign something in every single action is a good one. It can unlock some interesting new experiences within blinks.
I'm saying it is out of scope for this specific PR/spec change. This spec change has already gone through much discussion on the Solana forum for several weeks now and is effectively finalized.
Hence my original request:
post a more complete sRFC with details about a proposal to support some sort of "non signing action" support
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Within the upcoming spec proposal for sign message, we are planning to suggest a session token that can be passed back and forth between the action api server and the blink client. Think JWT passed between server and client, but within a blink.
Something like this would also make the idea of non-signing actions even more powerful and useful. The user initiates an authenticated session (by signing a message via their wallet in the first action in a chain), the api server verifies the signature in their backend, the api server provides their token
for the client interactions.
Off the top of my head:
Going with a pure "this is a form and does not require the user to sign anything" approach you seem to be suggesting is easily abused since a bot can spam the action api server to submit the form data. But never truly connect or verify a wallet. Ripe for abuse.
Hence my suggestion of:
to be a different sRFC and discussion. It would need additional discussion and thought
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair. I'm late to the discussion and this is a needed step anyhow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this is a useful thing to support form-like experiences, actions are still currently required to return a transaction, since the user is required to sign a transaction.
Implementing something like this is planned in general, but not within this spec change / proposal. When sign message support is added, maybe in there?
@thearyanag maybe you could post a more complete sRFC with details about a proposal to support some sort of "non signing action" support? My gut is that something like this should not be allowed on the root action, so the user is still required to "initiate a session" within the blink by signing a transaction (or eventually a message), then they could complete form-like experiences
agreed, I'll post a more detailed sRFC
TLDR
Actions can be chained together in successive series up to a depth of
n
. Each action can provide a callback url to fetch the next action in the series (being provided thesignature
from the previous action`) which can then be presented to users via action aware clients.Action chaining allows developer to build more complex and dynamic experiences within blinks, including:
validation and logic on the Action API server
Rationale
Blinks and actions are currently limited to a single depth of interaction. After the user signs a transaction, it concludes the experience. Action chaining allows developers to provide a depth of
n
actions, creating more dynamic and comprehensive experiences.sRFC: https://forum.solana.com/t/srfc-28-blinks-chaining/1734