@@ -81,6 +81,10 @@ service Transaction {
8181 // swap is funded.
8282 rpc StatefulSwap (stream StatefulSwapRequest ) returns (stream StatefulSwapResponse );
8383
84+ // StatelessSwap is like StatefulSwap, but without a state management system and a
85+ // best-effort submission system.
86+ rpc StatelessSwap (stream StatelessSwapRequest ) returns (stream StatelessSwapResponse );
87+
8488 // GetSwap gets metadata for a swap
8589 rpc GetSwap (GetSwapRequest ) returns (GetSwapResponse );
8690
@@ -777,6 +781,176 @@ message StatefulSwapResponse {
777781 }
778782}
779783
784+ message StatelessSwapRequest {
785+ oneof request {
786+ option (validate.required ) = true ;
787+
788+ Initiate initiate = 1 ;
789+ SubmitSignatures submit_signatures = 2 ;
790+ }
791+
792+ message Initiate {
793+ oneof kind {
794+ option (validate.required ) = true ;
795+
796+ CoinbaseStableSwapperClientParameters stablecoin = 1 ;
797+ }
798+
799+ // Client parameters for stateless swaps via the Coinbase Stable
800+ // Swapper program. Source funds are drawn from the owner's source-mint
801+ // ATA; destination is the owner's destination-mint VM Deposit ATA.
802+ message CoinbaseStableSwapperClientParameters {
803+ // The source mint that will be swapped from.
804+ common.v1.SolanaAccountId from_mint = 1 [(validate.rules ) .message.required = true ];
805+
806+
807+
808+ // The destination mint that will be swapped to.
809+ common.v1.SolanaAccountId to_mint = 2 [(validate.rules ) .message.required = true ];
810+
811+
812+
813+ // The amount to swap from the source mint in quarks.
814+ uint64 swap_amount = 3 [(validate.rules ) .uint64.gt = 0 ];
815+
816+
817+ }
818+
819+ // The owner account that owns the source ATA and the destination VM
820+ // Deposit ATA. The owner is the sole client-side signer of the swap
821+ // transaction.
822+ common.v1.SolanaAccountId owner = 2 [(validate.rules ) .message.required = true ];
823+
824+
825+
826+ // If true, server waits until the swap transaction is finalized before
827+ // returning Success. If false, server returns Success as soon as the
828+ // transaction is submitted to the cluster.
829+ bool wait_for_finalization = 3 ;
830+
831+ // The signature is of serialize(StatelessSwapRequest.Initiate) without
832+ // this field set using the private key of the owner account. This
833+ // provides an authentication mechanism to the RPC.
834+ common.v1.Signature signature = 4 [(validate.rules ) .message.required = true ];
835+
836+
837+ }
838+
839+ message SubmitSignatures {
840+ // The owner's signature over the locally constructed swap transaction.
841+ repeated common.v1.Signature transaction_signatures = 1 [(validate.rules ).repeated = {
842+ min_items : 1
843+ max_items : 1
844+ }];
845+
846+
847+ }
848+ }
849+
850+ message StatelessSwapResponse {
851+ oneof response {
852+ option (validate.required ) = true ;
853+
854+ ServerParameters server_parameters = 1 ;
855+ Success success = 2 ;
856+ Error error = 3 ;
857+ }
858+
859+ message ServerParameters {
860+ oneof kind {
861+ option (validate.required ) = true ;
862+
863+ CoinbaseStableSwapperServerParameter stablecoin = 1 ;
864+ }
865+
866+ // Server parameters for executing stateless swap flows against the
867+ // Coinbase Stable Swapper program.
868+ //
869+ // Supported Solana transaction version: v0
870+ //
871+ // Instruction format:
872+ // 1. [Optional] ComputeBudget::SetComputeUnitLimit
873+ // 2. [Optional] ComputeBudget::SetComputeUnitPrice
874+ // 3. [Optional] Memo::Memo
875+ // 4. AssociatedTokenAccount::CreateIdempotent (open owner's to_mint VM Deposit ATA)
876+ // 5. CoinbaseStableSwapper::Swap (owner's from_mint ATA -> owner's to_mint VM Deposit ATA)
877+ message CoinbaseStableSwapperServerParameter {
878+ // Subsidizer account that will pay the transaction fee.
879+ common.v1.SolanaAccountId payer = 1 [(validate.rules ) .message.required = true ];
880+
881+
882+
883+ // The Solana blockhash to set on the transaction. This is a
884+ // regular recent blockhash, not a durable nonce.
885+ common.v1.Blockhash blockhash = 2 [(validate.rules ) .message.required = true ];
886+
887+
888+
889+ // ALTs that should be used when constructing the versioned transaction
890+ repeated common.v1.SolanaAddressLookupTable alts = 3 ;
891+
892+ // Compute unit limit provided to the ComputeBudget::SetComputeUnitLimit
893+ // instruction. If the value is 0, then the instruction can be omitted.
894+ uint32 compute_unit_limit = 4 ;
895+
896+ // Compute unit price provided in the ComputeBudget::SetComputeUnitPrice
897+ // instruction. If the value is 0, then the instruction can be omitted.
898+ uint64 compute_unit_price = 5 ;
899+
900+ // Value provided into the Memo::Memo instruction. If the value length is 0,
901+ // then the instruction can be omitted.
902+ string memo_value = 6 [(validate.rules ) .string.max_len = 64 ];
903+
904+
905+
906+ // The CoinbaseStableSwapper liquidity pool's configured fee recipient,
907+ // sourced from the on-chain LiquidityPool account. Required by the
908+ // CoinbaseStableSwapper::Swap instruction.
909+ common.v1.SolanaAccountId pool_fee_recipient = 7 [(validate.rules ) .message.required = true ];
910+
911+
912+ }
913+ }
914+
915+ message Success {
916+ Code code = 1 ;
917+ enum Code {
918+ // Transaction was forwarded to the cluster. Returned when
919+ // wait_for_finalization = false.
920+ SUBMITTED = 0 ;
921+ // Transaction was finalized on-chain. Returned when
922+ // wait_for_finalization = true.
923+ FINALIZED = 1 ;
924+ }
925+
926+ // The signature of the submitted swap transaction. Clients may use
927+ // this to look up the transaction on-chain.
928+ common.v1.Signature transaction_signature = 2 [(validate.rules ) .message.required = true ];
929+
930+
931+ }
932+
933+ message Error {
934+ Code code = 1 ;
935+ enum Code {
936+ // Denied by a guard (spam, money laundering, etc)
937+ DENIED = 0 ;
938+ // There is an issue with the provided transaction signature
939+ SIGNATURE_ERROR = 1 ;
940+ // The swap parameters failed server-side validation (eg.
941+ // unsupported mint pair, insufficient source balance, swap amount
942+ // out of allowed range)
943+ INVALID_SWAP = 2 ;
944+ // The transaction was submitted but reverted on-chain, or its
945+ // blockhash expired before confirmation. Only relevant when
946+ // wait_for_finalization = true.
947+ TRANSACTION_FAILED = 3 ;
948+ }
949+
950+ repeated ErrorDetails error_details = 2 ;
951+ }
952+ }
953+
780954message GetSwapRequest {
781955 common.v1.SwapId id = 1 [(validate.rules ) .message.required = true ];
782956
0 commit comments