diff --git a/concepts/policies/examples/solana.mdx b/concepts/policies/examples/solana.mdx index eec936dd..d07ab1b2 100644 --- a/concepts/policies/examples/solana.mdx +++ b/concepts/policies/examples/solana.mdx @@ -6,6 +6,13 @@ sidebarTitle: "Solana" Note: see the [language section](/concepts/policies/language#solana) for various approaches on writing Solana policies. + + For sponsored Solana transactions, start with + [Solana Rent Sponsorship](/networks/solana-rent-refunds) before applying the + examples below. That guide covers account-creation risk, rent refunds, and + mitigation strategy for sponsored flows. + + #### Allow IDL-specific program instructions See [here](../../../concepts/policies/smart-contract-interfaces) for more information and examples. diff --git a/concepts/transaction-management.mdx b/concepts/transaction-management.mdx index 9be62851..a5899ab9 100644 --- a/concepts/transaction-management.mdx +++ b/concepts/transaction-management.mdx @@ -11,5 +11,6 @@ import SendTxConcepts from "/snippets/shared/send-tx-concepts.mdx"; For implementation guides, see: -- [Sending Sponsored Transactions (React)](/embedded-wallets/code-examples/sending-sponsored-transactions) - Using `@turnkey/react-wallet-kit` +- [Sending Sponsored EVM Transactions (React)](/embedded-wallets/code-examples/sending-sponsored-transactions) - Using `@turnkey/react-wallet-kit` +- [Sending Sponsored Solana Transactions (React)](/embedded-wallets/code-examples/sending-sponsored-solana-transactions) - Using `@turnkey/react-wallet-kit` - [Sending Sponsored Transactions](/company-wallets/code-examples/sending-sponsored-transactions) - Using `@turnkey/core` directly \ No newline at end of file diff --git a/docs.json b/docs.json index ac5e93ec..6a820235 100644 --- a/docs.json +++ b/docs.json @@ -171,6 +171,7 @@ "embedded-wallets/code-examples/authenticate-user-passkey", "embedded-wallets/code-examples/create-passkey-session", "embedded-wallets/code-examples/sending-sponsored-transactions", + "embedded-wallets/code-examples/sending-sponsored-solana-transactions", "reference/tron-gasless-transactions", "embedded-wallets/code-examples/client-side-signing", "embedded-wallets/code-examples/create-user-email", @@ -231,6 +232,8 @@ "pages": [ "networks/ethereum", "networks/solana", + "networks/solana-transaction-construction", + "networks/solana-rent-refunds", "networks/bitcoin", "networks/hyperliquid", "networks/cosmos", diff --git a/embedded-wallets/code-examples/sending-sponsored-solana-transactions.mdx b/embedded-wallets/code-examples/sending-sponsored-solana-transactions.mdx new file mode 100644 index 00000000..63bf36a2 --- /dev/null +++ b/embedded-wallets/code-examples/sending-sponsored-solana-transactions.mdx @@ -0,0 +1,86 @@ +--- +title: "Sending Sponsored Solana Transactions" +description: "Send sponsored Solana transactions using Turnkey's solSendTransaction API" +--- + +import SendSolanaTxSdkOverview from "/snippets/shared/send-solana-tx-sdk-overview.mdx"; + + + + + This example shows how to submit a sponsored Solana transaction, but your + application is still responsible for validating transaction contents. If the + transaction may create accounts that require rent, ensure `Sponsor Solana + Rent` has been enabled in the dashboard first. Review whether the unsigned + transaction creates accounts, closes accounts, or routes rent refunds back to + the signer. See + [Solana Rent Sponsorship](/networks/solana-rent-refunds) for rent setup and + refund-path guidance, and [Solana transaction construction for sponsored + flows](/networks/solana-transaction-construction) for payer-model and + account-creation caveats. + + +## Using `handleSendTransaction` (React) + +This handler wraps everything: intent creation, signing, Turnkey submission, polling, modal UX, and final success UI. + +### Step 1 — Configure the Provider +```tsx +import { TurnkeyProvider } from "@turnkey/react-wallet-kit"; + +const turnkeyConfig = { + apiBaseUrl: "https://api.turnkey.com", + defaultOrganizationId: process.env.NEXT_PUBLIC_TURNKEY_ORG_ID, + rpId: window.location.hostname, + iframeUrl: "https://auth.turnkey.com", +}; + +export default function App({ children }) { + return ( + + {children} + + ); +} +``` + +### Step 2 — Use `handleSendTransaction` for Solana +```tsx +const { handleSendTransaction, wallets } = useTurnkey(); + +const walletAccount = wallets + .flatMap((w) => w.accounts) + .find((a) => a.addressFormat === "ADDRESS_FORMAT_SOLANA"); + +if (!walletAccount) { + throw new Error("No Solana wallet account found"); +} + +await handleSendTransaction({ + transaction: { + signWith: walletAccount.address, + unsignedTransaction: "", + caip2: "solana:mainnet", + sponsor: true, + }, +}); +``` + +This automatically: +- Opens the Turnkey modal +- Shows the chain logo +- Polls until `INCLUDED` +- Displays success page + explorer link + +## Checking Gas Usage + +You can configure gas limits for both sub-orgs and all orgs. We recommend checking sub-org gas usage against the limit on the client side so your application can handle edge cases when approaching or exceeding the gas limit. +```tsx +const resp = await httpClient?.getGasUsage({}); +if (resp?.usageUsd! > resp?.windowLimitUsd!) { + console.error("Gas usage limit exceeded for sponsored transactions"); + return; +} +``` + +For additional references leveraging these endpoints, check out our [Swapping Example](/cookbook/jupiter) and [Sweeping Example](/cookbook/sweeping). \ No newline at end of file diff --git a/embedded-wallets/code-examples/sending-sponsored-transactions.mdx b/embedded-wallets/code-examples/sending-sponsored-transactions.mdx index 210b7c41..5faf79d1 100644 --- a/embedded-wallets/code-examples/sending-sponsored-transactions.mdx +++ b/embedded-wallets/code-examples/sending-sponsored-transactions.mdx @@ -1,5 +1,5 @@ --- -title: "Sending Sponsored Transactions" +title: "Sending Sponsored EVM Transactions" description: "In this guide, we’ll walk through the process of setting up sponsored transactions, with abstractions for transaction construction, broadcast, and gas management, using React." --- diff --git a/faq.mdx b/faq.mdx index 8abeec68..42354660 100644 --- a/faq.mdx +++ b/faq.mdx @@ -85,6 +85,8 @@ title: "FAQ" This limit is on a **per IP address** basis: if you have multiple servers making requests to the turnkey API under a different IP address, each server is subject to the 60 RPS limit individually. + In addition, the **broadcast transaction endpoints** (`ethSendTransaction` and `solSendTransaction`) are subject to a separate global limit of **10 RPS**, applied uniformly across all plans. + Please get in touch with us ([help@turnkey.com](mailto:help@turnkey.com)) if you need this limit adjusted for your use-case. @@ -116,9 +118,9 @@ title: "FAQ" We handle gassing and our battle-tested broadcast logic ensures inclusion even under adverse network conditions. You and your users never touch gas tokens or deal with stuck transactions. - While we'e abstracted gas sponsorship, you're always able to bring in your own gas service, and we can handle the rest. + While we've abstracted gas sponsorship, you're always able to bring in your own gas service, and we can handle the rest. - Please note that this functionality is supported for a limited number of select EVM chains, however are are aggressively expanding the coverage area. For more detail visit [Transaction Management](/concepts/transaction-management) overview page. + This functionality is currently supported for EVM chains (Base, Polygon, Ethereum) and Solana. We're actively expanding coverage — reach out if you need a specific chain. For more detail visit the [Transaction Management](/concepts/transaction-management) overview page. In the ECDSA context, messages are hashed before signing. Turnkey can perform this hashing for you, as we support two hash functions: `HASH_FUNCTION_KECCAK256` and `HASH_FUNCTION_SHA256` (for Ethereum and Bitcoin ecosystems respectively). If your message had already been hashed, you should use the `HASH_FUNCTION_NO_OP` option to sign the raw hash, in which case Turnkey will sign the payload as is. `HASH_FUNCTION_NO_OP` also has privacy implications: if a raw hashed message is passed in, Turnkey has no knowledge of the underlying pre-image. diff --git a/images/concepts/network/enable_rent_sponsorship.png b/images/concepts/network/enable_rent_sponsorship.png new file mode 100644 index 00000000..e4f26b9a Binary files /dev/null and b/images/concepts/network/enable_rent_sponsorship.png differ diff --git a/networks/ethereum.mdx b/networks/ethereum.mdx index 962e7fab..4bbf69d2 100644 --- a/networks/ethereum.mdx +++ b/networks/ethereum.mdx @@ -14,6 +14,42 @@ To construct and sign an EVM transaction with Turnkey, we offer: - [@turnkey/viem](https://github.com/tkhq/sdk/tree/main/packages/viem): contains a `createAccount` method to create a Turnkey-powered [custom account](https://viem.sh/docs/accounts/local) which [Viem](https://viem.sh/) can use seamlessly. - [@turnkey/ethers](https://github.com/tkhq/sdk/tree/main/packages/ethers): contains a `TurnkeySigner` which implements Ethers' `AbstractSigner` interface. See [Ethers docs](https://docs.ethers.org/v6/api/providers/abstract-signer/#AbstractSigner). +## Transaction management & Gas sponsorship + +Turnkey's [Transaction Management](/concepts/transaction-management) handles the full lifecycle of EVM transactions — construction, broadcast, nonce management, and status monitoring — down to a few API calls. + +### What Turnkey auto-fills + +When you submit a transaction via `ethSendTransaction`, Turnkey automatically manages: + +- **Nonce**: set correctly to order transactions and prevent conflicts +- **Gas estimation**: calculated to ensure inclusion under current network conditions +- **Priority fee (tip)**: set to target timely block inclusion per EIP-1559 + +### Gas sponsorship (fee abstraction) + +Set `sponsor: true` to enable fee sponsorship — your users never need to hold native tokens to pay gas. Turnkey covers fees on your behalf and passes costs through as a monthly line item. + +**Supported networks:** +- Base (eip155:8453) +- Polygon (eip155:137) +- Ethereum (eip155:1) +- Base Sepolia, Polygon Amoy, Ethereum Sepolia (testnets) + + + To enable gas sponsorship, ensure it is activated in your Turnkey dashboard before setting `sponsor: true`. + + +### Non-sponsored transactions + +Set `sponsor: false` to have gas paid by the sender's wallet. Turnkey still manages nonce, gas estimation, tip fees, broadcast, and status monitoring — you just don't get fee abstraction. + +### Transaction status + +After broadcast, Turnkey monitors your transaction until it is included in a block or fails, with structured error decoding for smart contract reverts. Query status via the [Get Send Transaction Status](/api-reference/queries/get-send-transaction-status) endpoint. + +For a full walkthrough, see [Sending Sponsored EVM Transactions](/embedded-wallets/code-examples/sending-sponsored-transactions). + ## Transaction parsing, policies, and signing Turnkey has built an EVM parser which runs in a secure enclave, to parse unsigned EVM transactions and extract useful metadata: transaction source, destination, amount, chain ID, and more. See the `EthereumTransaction` struct in our [policy language](/concepts/policies/language) page for a full list. diff --git a/networks/solana-rent-refunds.mdx b/networks/solana-rent-refunds.mdx new file mode 100644 index 00000000..1c4a2364 --- /dev/null +++ b/networks/solana-rent-refunds.mdx @@ -0,0 +1,156 @@ +--- +title: "Solana Rent Sponsorship" +description: "Understand how Solana rent sponsorship works, when rent is pre-funded, and how to reduce rent-refund leakage in sponsored flows." +sidebarTitle: "Rent Sponsorship" +--- + +## Overview + +On Solana, fee sponsorship and rent sponsorship are separate. + +Fee sponsorship covers the network fee for a transaction. Rent sponsorship covers the rent-exempt lamports needed when instructions create new accounts. + +If an instruction creates a new account and the user signer is the payer, Turnkey pre-funds that signer for the rent-exempt amount. The amount is based on the size of the new account data and is intended to make the account rent exempt. + +When enabled, sponsored rent is added to your monthly gas bill and counts toward the same spend limits used for sponsored transaction fees. See [Spend limits](/concepts/transaction-management#spend-limits). + +Rent sponsorship is disabled by default and must be enabled separately in the Turnkey dashboard. + +For the broader transaction-construction model behind sponsored Solana flows, including payer behavior and account-creation caveats, see [Solana transaction construction for sponsored flows](/networks/solana-transaction-construction). + +## Enable rent sponsorship + +If your sponsored Solana transactions may create accounts, you must explicitly enable rent sponsorship in the Turnkey dashboard. + +1. Enable gas sponsorship. +2. Turn on `Sponsor Solana Rent`. +3. Click `Save Configuration`. + +Turnkey dashboard showing Sponsor Solana Rent enabled + + + Refunded rent from later-closed accounts follows Solana account rules. It + does not automatically return to the sponsor. + + +## Rent extraction risk + +On Solana, when an account is later closed, the rent previously deposited into that account is returned according to Solana account rules, usually to the configured destination for the close operation. + +That destination is usually the signer or account owner, not the sponsor that originally funded the rent. + +This creates a rent extraction risk for sponsored Solana transactions: the sponsor covers the rent needed to create the account, but the refunded rent can later flow back to the signer instead. + +This is not necessarily malicious. It can happen in ordinary product flows. + +A common example is a swap that temporarily wraps SOL into wSOL, uses that account during execution, and then closes the temporary account before the transaction completes. + +In a self-funded flow, the rent simply returns to the user. In a sponsored flow, that same rent may have been pre-funded by the sponsor and then refunded back to the signer. + +## Mitigations and guardrails + +The best mitigation depends on how much transaction flexibility your product allows. + +- Reuse a constrained set of token accounts where possible instead of creating and closing them repeatedly. +- Avoid or strip `CloseAccount` patterns from sponsored flows when that works for your product. +- Prefer backend-generated or backend-validated transactions for higher-control flows. +- Use spend caps, rate limits, monitoring, and alerts to bound and detect repeated leakage. +- Treat account creation and account closure as first-class review criteria for sponsored Solana transactions. + +### Strip `CloseAccount` instructions before submission + +One practical guardrail is to inspect the transaction payload before submission and remove SPL Token `CloseAccount` instructions. + +This is especially useful when you receive a prebuilt transaction from a routing service such as Jupiter and want to keep your sponsored flow from immediately refunding rent back to the signer. + +In the SPL Token program, `CloseAccount` is instruction discriminator `9`. A simple filter can remove those instructions before you hand the transaction to Turnkey: + +```ts +const SPL_TOKEN_PROGRAM_IDS = new Set([ + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", +]); + +const CLOSE_ACCOUNT_INSTRUCTION_DISCRIMINATOR = 9; + +function isCloseAccountInstruction(ix: TransactionInstruction): boolean { + return ( + SPL_TOKEN_PROGRAM_IDS.has(ix.programId.toBase58()) && + ix.data[0] === CLOSE_ACCOUNT_INSTRUCTION_DISCRIMINATOR + ); +} + +const filteredInstructions = txMessage.instructions.filter( + (ix) => !isCloseAccountInstruction(ix), +); +``` + +This does not eliminate all rent-related risk, but it removes one of the most common leakage paths in sponsored swap flows. + +### Disable Jupiter auto wrap and unwrap for SOL flows + +Another useful guardrail is to disable Jupiter's automatic SOL wrapping and unwrapping behavior when you request the swap transaction. + +When `wrapAndUnwrapSol` is enabled, Jupiter may create a temporary wSOL account for the transaction and then close it before completion. In a sponsored flow, that pattern can create a rent refund path back to the signer. + +To prevent that, set `wrapAndUnwrapSol` to `false` in the Jupiter API request: + +```ts +body: JSON.stringify({ + quoteResponse, + userPublicKey: request.signWith, + wrapAndUnwrapSol: false, + dynamicComputeUnitLimit: true, + prioritizationFeeLamports: "auto", +}) +``` + +With this setting disabled, your application should manage wSOL explicitly instead of relying on Jupiter to create and close a temporary account on the user's behalf. + +This higher-control approach is often a better fit for sponsored flows because it lets you: + +- reuse a persistent wSOL account instead of creating a fresh one per swap +- avoid automatic close-account behavior in the routed transaction +- review account lifecycle decisions on the backend before submission + +For products with tighter controls, the strongest approach is usually to combine both mitigations: disable auto wrap and unwrap where possible, and still validate or sanitize the final instruction payload before sending it. + +## Key custody matters + +These mitigations are weaker if end users can export or independently control the signer key. + +Even if your application removes account-close instructions from the original sponsored flow, a user who later controls the signer can submit a separate transaction to close previously created accounts and reclaim rent. + +If you need stronger protection, keep transaction submission behind your backend and avoid giving end users independent signer control. + +## Policy guidance + +These example deny policies can help reduce common Solana rent-leakage patterns in sponsored flows. + +### Deny sponsored Solana `CloseAccount` + +```json +{ + "effect": "EFFECT_DENY", + "condition": "solana.tx.instructions.any(i, (i.program_key == 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' || i.program_key == 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb') && i.instruction_data_hex == '09')" +} +``` + +### Deny sponsored Solana account lifecycle ops + +```json +{ + "effect": "EFFECT_DENY", + "condition": "solana.tx.instructions.any(i, i.program_key == 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL') || solana.tx.instructions.any(i, (i.program_key == 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' || i.program_key == 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb') && (i.instruction_data_hex == '09' || i.instruction_data_hex == '11'))" +} +``` + +## Next steps + +- See [Solana (SVM) support on Turnkey](/networks/solana) +- See [Solana transaction construction for sponsored flows](/networks/solana-transaction-construction) +- See [Sending Sponsored Solana Transactions](/embedded-wallets/code-examples/sending-sponsored-solana-transactions) +- See [Solana policy examples](/concepts/policies/examples/solana) diff --git a/networks/solana-transaction-construction.mdx b/networks/solana-transaction-construction.mdx new file mode 100644 index 00000000..ead8abe6 --- /dev/null +++ b/networks/solana-transaction-construction.mdx @@ -0,0 +1,52 @@ +--- +title: "Solana transaction construction for sponsored flows" +description: "Understand what Turnkey manages for sponsored Solana transactions, what your application still controls, and the current transaction-construction caveats." +sidebarTitle: "Transaction Construction" +--- + +## Overview + +This page explains how Turnkey handles sponsored Solana transactions at submission time. + +The focus here is not how to build a Solana transaction from scratch. It is how Turnkey behaves when you submit an unsigned transaction through `solSendTransaction`: which values Turnkey preserves, which values Turnkey fills in if they are missing, and which rent-sponsorship constraints can affect account-creation flows. + +This is especially relevant if you accept prebuilt transactions from a backend, router, or third-party API. + +## What Turnkey auto-manages + +Turnkey preserves the transaction values you provide where supported and fills in missing broadcast-time fields when needed. + +- **Recent blockhash**: if your transaction already includes a blockhash, Turnkey uses it as provided. This lets you time-bound the transaction yourself. If you do not provide one, Turnkey fetches and sets a fresh blockhash at broadcast time. +- **Compute budget instructions**: if your transaction already includes compute budget instructions for compute unit limit or compute unit price, Turnkey uses those values. If you do not provide them, Turnkey estimates and sets competitive values at broadcast time. +- **Broadcast and monitoring**: Turnkey broadcasts the transaction and tracks its lifecycle. You can retrieve the latest status through the [Get Send Transaction Status](/api-reference/queries/get-send-transaction-status) endpoint. + +## Current Solana transaction-construction constraints + +Sponsored Solana transaction support is intentionally conservative in the current implementation. + +- Turnkey currently requires the `System Program` to appear in the transaction's static account keys, not through an address lookup table. +- Turnkey currently supports one Turnkey signer per transaction. +- That signer model has an important consequence for account creation in sponsored flows: Turnkey does not currently support top-level `createAccount` or `createAccountWithSeed` instructions, because those outer account-creation instructions require two signatures. + +In practice, this does not mean account creation is uncommon in sponsored Solana flows. In many applications, accounts are created inside program execution through `invoke_signed` rather than as top-level system instructions. + +If your sponsored flow depends on account creation, prefer program-driven flows and validate any prebuilt transaction before submission. + +## Designing safe sponsored flows + +For most products, the safest approach is to validate or construct sponsored Solana transactions on the backend rather than blindly forwarding arbitrary user-supplied payloads. + +Recommended guardrails: + +- treat account creation and account closure as first-class review criteria +- prefer a constrained set of known transaction patterns over arbitrary routed transactions +- reuse persistent token accounts where possible instead of creating and closing temporary ones repeatedly +- inspect third-party-built transactions before submission, especially when they may wrap and unwrap SOL or close accounts automatically + +If you use a routing service such as Jupiter, review the final instruction payload carefully. Temporary account creation and `CloseAccount` behavior are common sources of rent leakage and sponsorship surprises. See [Solana Rent Sponsorship](/networks/solana-rent-refunds) for refund-path risk and mitigation guidance. + +## Next steps + +- See [Solana (SVM) support on Turnkey](/networks/solana) +- See [Solana Rent Sponsorship](/networks/solana-rent-refunds) +- See [Sending Sponsored Solana Transactions](/embedded-wallets/code-examples/sending-sponsored-solana-transactions) diff --git a/networks/solana.mdx b/networks/solana.mdx index b29f16be..773b86f5 100644 --- a/networks/solana.mdx +++ b/networks/solana.mdx @@ -11,6 +11,52 @@ Turnkey supports Solana address derivation with `ADDRESS_TYPE_SOLANA`. Solana ad To construct and sign a Solana transaction we offer a `@turnkey/solana` NPM package. It offers a `TurnkeySigner` which integrates our remote signer with the official Solana [`web3js`](https://solana-labs.github.io/solana-web3.js/) library. +## Transaction management & Gas sponsorship + +Turnkey's [Transaction Management](/concepts/transaction-management) handles the full lifecycle of Solana transactions — construction, broadcast, and status monitoring — down to a few API calls. + +### What Turnkey auto-fills + +When you submit a transaction via `solSendTransaction`, Turnkey automatically manages: + +- **Recent blockhash**: fetched and set at broadcast time to ensure validity +- **Compute unit limit**: estimated and set to avoid failed transactions +- **Priority fee**: set to ensure timely inclusion under current network conditions + +### Gas sponsorship (fee abstraction) + +Set `sponsor: true` to enable fee sponsorship — your users never need to hold SOL to pay transaction fees. Turnkey covers fees on your behalf and passes costs through as a monthly line item. + +**Supported networks:** +- Solana mainnet +- Solana devnet (for testing) + + + To enable gas sponsorship, ensure it is activated in your Turnkey dashboard before setting `sponsor: true`. + + +For sponsored Solana flows, especially when you accept prebuilt transactions, see [Solana transaction construction for sponsored flows](/networks/solana-transaction-construction) for the current payload constraints and account-creation caveats. + +### Solana rent sponsorship + +Solana rent sponsorship is separate from general gas sponsorship and is disabled by default. + +If an instruction creates a new account and the user signer is the payer, Turnkey pre-funds that signer for the rent-exempt amount only after you enable `Sponsor Solana Rent` in the dashboard and save the configuration. + +If those accounts are later closed, the refunded rent follows Solana account rules and can go back to the signer rather than the sponsor. + +See [Solana Rent Sponsorship](/networks/solana-rent-refunds) for setup steps, the dashboard flow, and mitigation guidance. + +### Non-sponsored transactions + +Set `sponsor: false` to have the transaction fee paid by the sender's wallet. Turnkey still manages blockhash, compute units, priority fees, broadcast, and status monitoring — you just don't get fee abstraction. + +### Transaction status + +After broadcast, Turnkey monitors your transaction until it is confirmed or fails. Query status via the [Get Send Transaction Status](/api-reference/queries/get-send-transaction-status) endpoint. + +For a full walkthrough, see [Sending Sponsored Solana Transactions](/embedded-wallets/code-examples/sending-sponsored-solana-transactions). + ## Transaction parsing, policies, and signing Turnkey has built a Solana parser which runs in a secure enclave, to parse unsigned transactions and extract metadata. Solana transactions are a list of instructions. We offer details about program keys, accounts, signers, and more. See the `SolanaTransaction` struct in our [policy language](/concepts/policies/language) page for a full list. diff --git a/reference/aa-wallets.mdx b/reference/aa-wallets.mdx index a0d64120..afd60bd0 100644 --- a/reference/aa-wallets.mdx +++ b/reference/aa-wallets.mdx @@ -3,6 +3,10 @@ title: "Account Abstraction Wallets" description: "Turnkey offers flexible infrastructure to create and manage keys. These keys can be used as a signer inside of an [Account Abstraction wallet](https://www.erc4337.io/), and we've partnered with [Alchemy](https://www.alchemy.com/) and [ZeroDev](https://zerodev.app/) to integrate in a few lines of code." --- + + For gas sponsorship without third-party AA providers, Turnkey's native Transaction Management supports sponsored transactions for EVM and Solana directly. See [Transaction Management](/concepts/transaction-management) to get started without an AA stack. + + ## Alchemy's Account Kit You can use Turnkey with Alchemy's Account Kit via the [aa-signers](https://accountkit.alchemy.com/signer/what-is-a-signer) package to generate embedded wallets, and leverage [aa-alchemy](https://accountkit.alchemy.com/signer/custom-signer#implementing-smartaccountsigner) to create smart accounts for your users. diff --git a/sdks/web3/gas-station.mdx b/sdks/web3/gas-station.mdx index 86428f19..d42e81e8 100644 --- a/sdks/web3/gas-station.mdx +++ b/sdks/web3/gas-station.mdx @@ -4,6 +4,10 @@ description: "A reusable SDK for implementing gasless transactions using EIP-770 mode: wide --- + + Looking for a turnkey solution? If you don't want to build your own paymaster, Turnkey's native Transaction Management handles gas sponsorship for both EVM and Solana out of the box. See the [Transaction Management](/concepts/transaction-management) overview to get started. + + The Gas Station SDK enables you to implement gasless transactions using EIP-7702 delegation and EIP-712 signed intents. This SDK is designed to work with Turnkey-managed paymaster wallets within your organization, allowing you to sponsor transactions for your users so they can execute transactions without needing ETH for gas fees. While your paymaster wallet should be managed by Turnkey, the user wallets signing the EIP-712 intents can be flexible - they can be Turnkey-managed or external wallets. Your Turnkey paymaster can broadcast intents signed by any compatible wallet. The SDK provides clean abstractions for EIP-7702 authorization, intent signing, and paymaster execution, supporting any onchain action through generic execution parameters. diff --git a/snippets/shared/send-solana-tx-sdk-overview.mdx b/snippets/shared/send-solana-tx-sdk-overview.mdx new file mode 100644 index 00000000..33bd1a88 --- /dev/null +++ b/snippets/shared/send-solana-tx-sdk-overview.mdx @@ -0,0 +1,32 @@ +The SDK primarily abstracts three endpoints: `sol_send_transaction`, `get_send_transaction_status`, and `get_gas_usage`. + +You can sign and broadcast Solana transactions in two primary ways: + +- **Using the React handler (`handleSendTransaction`) from `@turnkey/react-wallet-kit`** + + This gives you: + - modals + - spinner + chain logo + - success screen + - explorer link + - built-in polling + +- **Using low-level functions in `@turnkey/core`** + + You manually call: + - `solSendTransaction` → submit + - `pollTransactionStatus` → wait for confirmation + +- **Using server-side `@turnkey/sdk-server`** + + This is the right choice for Node.js backends. It exposes the same methods via the server SDK client. + +This page walks you through the React flow with full code examples. For using `@turnkey/core` directly, see [Sending Sponsored Transactions](/company-wallets/code-examples/sending-sponsored-transactions). + + + Before sponsoring Solana transactions, review + [Solana Rent Sponsorship](/networks/solana-rent-refunds). Rent sponsorship is + opt-in, disabled by default, and must be enabled in the dashboard first. This + is especially important if you sponsor transactions from swap providers or + other third-party builders that may create and close accounts. + \ No newline at end of file diff --git a/snippets/shared/send-tx-concepts.mdx b/snippets/shared/send-tx-concepts.mdx index 267c790d..92030e71 100644 --- a/snippets/shared/send-tx-concepts.mdx +++ b/snippets/shared/send-tx-concepts.mdx @@ -3,110 +3,152 @@ Traditionally, sending blockchain transactions onchain has been painful: - You need to fund wallets with native gas tokens, creating onboarding friction -- Network congestion and gas spikes can cause transactions to stall or get dropped altogether +- Network congestion and fee spikes can cause transactions to stall or get dropped altogether -Turnkey reduces this to a couple of API calls. We handle gassing and our battle-tested broadcast logic ensures inclusion even under adverse network conditions. You and your users never touch gas tokens or deal with stuck transactions. +Turnkey reduces this to a couple of API calls. We handle fees and our battle-tested broadcast logic ensures inclusion even under adverse network conditions. You and your users never touch gas tokens or deal with stuck transactions. -**Chain Support:** +## Supported chains + +**EVM (sponsored):** - **Base** - eip155:8453 - **Polygon** - eip155:137 - **Ethereum** - eip155:1 -> Interested in another chain? Reach out to us! - -**Testnet Chain Support:** +**EVM testnets (sponsored):** - **Base (Sepolia)** - eip155:84532 - **Polygon (Amoy)** - eip155:80002 - **Ethereum (Sepolia)** - eip155:11155111 +**Solana (sponsored):** + +- **Solana mainnet** - solana:mainnet +- **Solana devnet** - solana:devnet + +> Interested in another chain? Reach out to us! + - To access the supported networks, ensure that Gas Sponsorship is first enabled within your Turnkey dashboard. Then update the caip2 parameter with the corresponding chain ID. + To access sponsored transactions, ensure that Gas Sponsorship is first enabled within your Turnkey dashboard. Then set `sponsor: true` and update the `caip2` parameter with the corresponding chain identifier. ## Concepts ### Gas sponsorship (aka gas abstraction, gasless transactions, fee abstraction) -A single endpoint lets you toggle between standard EIP-1559 transactions and sponsored transactions. EIP-1559 is the modern Ethereum fee model where transactions specify a base fee (determined by network congestion) and a priority fee (a tip to validators for faster inclusion). With sponsorship enabled, your users never need to hold native tokens to pay these fees—Turnkey covers them. Set `sponsor: true` to enable sponsorship. +A single endpoint lets you toggle between standard and sponsored transactions. With sponsorship enabled, your users never need to hold native tokens to pay transaction fees — Turnkey covers them. Set `sponsor: true` to enable sponsorship, or `sponsor: false` to have fees paid by the sender's wallet. + +Either way, Turnkey handles construction, signing, broadcast, and status monitoring. The `sponsor` flag only controls who pays the fee. ### Construction and Broadcast -A successful EVM transaction requires several components: +#### EVM + +A successful EVM transaction requires: - **Transaction construction**: assembling the payload (recipient, value, calldata) -- **Nonce, gas and tip fee**: setting the correct nonce to order transactions, estimating gas usage and tip fees to ensure inclusion even during network congestion +- **Nonce**: set correctly to order transactions and prevent conflicts +- **Gas and tip fee**: estimated to ensure inclusion even during network congestion - **Signature**: cryptographically signing the transaction with the sender's private key - **Broadcast**: submitting the signed transaction to the network and monitoring for inclusion -Turnkey handles all of this for you. Whether or not you use sponsorship, you pass through minimal payloads that define the contents of your transaction and we take care of construction, signing, and broadcast. We auto-fill any fields you omit. +Turnkey handles all of this for you via `ethSendTransaction`. Whether or not you use sponsorship, you pass through minimal payloads and we take care of the rest. We auto-fill any fields you omit. + +This endpoint supports arbitrary EVM transactions — not just simple sends. You can interact with smart contracts, deploy contracts, or execute any valid EVM operation. -This endpoint supports arbitrary EVM transactions, not just simple sends. You can interact with smart contracts, deploy contracts, or execute any valid EVM operation. +#### Solana -### Transaction status and enriched transaction errors +A successful Solana transaction requires: -After you send a transaction, Turnkey monitors its status until it fails or gets included in a block. +- **Transaction construction**: assembling the list of instructions (program, accounts, data) +- **Recent blockhash**: fetched and attached at broadcast time to ensure the transaction is valid +- **Compute unit limit**: estimated and set to prevent failed transactions due to insufficient compute +- **Priority fee**: set to ensure timely inclusion under current network conditions +- **Signature**: cryptographically signing the transaction with the sender's private key +- **Broadcast**: submitting the signed transaction to the network and monitoring for confirmation + +Turnkey handles all of this for you via `solSendTransaction`. Whether or not you use sponsorship, you pass through a minimal payload and we manage the rest. + + + On Solana, fee sponsorship and rent sponsorship are separate. `Sponsor Solana + Rent` is disabled by default and must be enabled in the dashboard before + Turnkey will pre-fund rent for account creation. If created accounts are later + closed, refunded rent can go back to the signer rather than the sponsor. See + [Solana Rent Sponsorship](/networks/solana-rent-refunds). For payer behavior, + static-key requirements, and account-creation caveats in sponsored flows, see + [Solana transaction construction for sponsored flows](/networks/solana-transaction-construction). + -For transactions that experience reversion errors, Turnkey runs a transaction simulation to produce structured execution traces and decode common revert reasons. The result: actionable error messages that tell you exactly what went wrong, so you can debug and fix issues quickly instead of parsing opaque hex data. +### Transaction status and enriched errors -### **Transaction Statuses** +After you send a transaction, Turnkey monitors its status until it fails or is confirmed on-chain. -| **Status** | **Description** | -| ------------ | --------------------------------------------------------------------------------------------------------------------------------- | -| INITIALIZED | Turnkey has constructed and signed the transaction, and prepared gas sponsorship, but the transaction has not yet been broadcast. | -| BROADCASTING | Turnkey is actively broadcasting the sponsored transaction to the network and awaiting inclusion. | -| INCLUDED | The sponsored transaction has been included in a block. | -| FAILED | The sponsored transaction could not be included on-chain and will not be retried automatically. | +### Transaction Statuses -### **Ethereum Smart Contract Transaction Errors** +The following statuses apply to both EVM and Solana transactions: -| **Status** | **Description** | -| :--------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ | -| UNKNOWN | The transaction reverted during on-chain execution or simulation, but the revert reason could not be decoded (e.g. missing ABI or unverified contract). | -| NATIVE | The transaction reverted due to a built-in Solidity error, such as `require()`, `assert()`, or a plain `revert()`. | -| CUSTOM | The transaction reverted due to a contract-defined custom error declared using Solidity’s `error` keyword. | +| **Status** | **Description** | +| ------------ | ---------------------------------------------------------------------------------------------------------------------------- | +| INITIALIZED | Turnkey has constructed and signed the transaction and prepared fees, but it has not yet been broadcast. | +| BROADCASTING | Turnkey is actively broadcasting the transaction to the network and awaiting inclusion. | +| INCLUDED | The transaction has been included in a block (EVM) or confirmed on-chain (Solana). | +| FAILED | The transaction could not be included on-chain and will not be retried automatically. | + +### EVM Smart Contract Transaction Errors + +For EVM transactions that revert, Turnkey runs a simulation to produce structured execution traces and decode common revert reasons — giving you actionable error messages instead of opaque hex data. + +| **Error type** | **Description** | +| :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ | +| UNKNOWN | The transaction reverted during on-chain execution or simulation, but the revert reason could not be decoded (e.g. missing ABI or unverified contract). | +| NATIVE | The transaction reverted due to a built-in Solidity error, such as `require()`, `assert()`, or a plain `revert()`. | +| CUSTOM | The transaction reverted due to a contract-defined custom error declared using Solidity's `error` keyword. | - **Note:** Turnkey application-level errors (e.g. signing failures, policy rejections) are not classified under these error types and are instead surfaced via `Error.Message`. + These error types describe how an EVM smart contract reverted during on-chain execution or pre-flight simulation. Turnkey application-level errors (e.g. signing failures, policy rejections) are not classified here and are instead surfaced via `Error.Message`. ### Spend limits -Turnkey provides tools to manage your gas sponsorship budget. You configure USD gas limits at two levels: across all orgs and per sub-org. This gives you control over both total spend and per-user spend. You can set limit values and time windows through the dashboard. +Turnkey provides tools to manage your gas sponsorship budget. You configure USD fee limits at two levels: across all orgs and per sub-org. This gives you control over both total spend and per-user spend. You can set limit values and time windows through the dashboard. You can query current gas usage and limits through our endpoints. - Turnkey provides paymaster (gas sponsorship) and transaction broadcasting services only. In high-fee or congested network conditions, delays or non-inclusion may occur. It is the developer's responsability to ensure appropriate spend limits are in place. + Turnkey provides fee sponsorship and transaction broadcasting services only. In high-fee or congested network conditions, delays or non-inclusion may occur. It is the developer's responsibility to ensure appropriate spend limits are in place. ### Policy engine -You can write policies against both sponsored and non-sponsored transactions using the normal `eth.tx` namespace in Turnkey's policy DSL. This means you can seamlessly switch between sponsored and non-sponsored transactions and still use the same policies. +You can write policies against both sponsored and non-sponsored transactions using Turnkey's policy DSL: + +- **EVM**: use the `eth.tx` namespace +- **Solana**: use the `solana.tx` namespace + +This means you can seamlessly switch between sponsored and non-sponsored transactions and still use the same policies. -_Note:_ Turnkey sets all gas-related fields to 0 for sponsored transactions. +_Note:_ Turnkey sets all fee-related fields to 0 for sponsored transactions. ### Billing -Turnkey passes gas costs through to you and includes them as a line item at the end of the month. You pay based on the USD value of gas at time of broadcast; Turnkey internalizes the inventory risk of gas token price changes. Our battle-tested gas estimation aims to be cost efficient while ensuring quick transaction inclusion. +Turnkey passes transaction fee costs through to you as a line item at the end of the month. You pay based on the USD value of fees at time of broadcast; Turnkey internalizes the inventory risk of token price changes. Our battle-tested fee estimation aims to be cost-efficient while ensuring quick transaction inclusion. ### Advanced -#### Gas sponsorship smart contracts +#### Gas sponsorship smart contracts (EVM) -We could not find a satisfactory setup for gas sponsorship contracts that were both fast and safe, so we made our own. The contracts are open source and you can check them out on [github](https://github.com/tkhq/gas-station). +We could not find a satisfactory setup for gas sponsorship contracts that were both fast and safe, so we made our own. The contracts are open source and you can check them out on [GitHub](https://github.com/tkhq/gas-station). -Based on our benchmarks, these are the most efficient gas sponsorship contracts on the market. They achieve this through optimized logic, calldata encoding, and using assembly extensively, which reduces gas overhead per sponsored transaction. The result: lower costs for you and faster execution for your users. +Based on our benchmarks, these are the most efficient gas sponsorship contracts on the market. They achieve this through optimized logic, calldata encoding, and extensive use of assembly, which reduces gas overhead per sponsored transaction. The result: lower costs for you and faster execution for your users. #### Security -Some gas sponsorship setups by other providers are subject to replay attacks. If a malicious actor compromises the provider infrastructure, they can replay the gas sponsorship request multiple times with different nonces to create multiple transactions from a single request. Concretely, this means if Bob signs a request to send Alice 1 ETH, a malicious actor could replay that request many times, draining all of Bob's ETH. +Some gas sponsorship setups by other providers are subject to replay attacks. If a malicious actor compromises the provider infrastructure, they can replay the gas sponsorship request multiple times with different nonces to create multiple transactions from a single request. -At Turnkey, we never cut corners on security: we perform transaction construction in enclaves, and as long as the request includes the relevant nonce, only one transaction can be created from it. Since the user's authenticator signs requests and the enclave verifies signatures, a malicious actor cannot modify or replay the request. This is inline with Turnkey's core system design principal: everything can be compromised outside of the enclaves and funds will still be safe. +At Turnkey, we never cut corners on security: we perform transaction construction in enclaves, and as long as the request includes the relevant nonce or blockhash, only one transaction can be created from it. Since the user's authenticator signs requests and the enclave verifies signatures, a malicious actor cannot modify or replay the request. This is in line with Turnkey's core system design principle: everything can be compromised outside of the enclaves and funds will still be safe. By default, our SDKs include a special gas station nonce for sponsored transaction requests. ### RPCs -Turnkey's send transaction and transaction status endpoints eliminate the need for third-party RPC providers. You save costs and reduce latency because we holistically incorporate internal data and minimize calls. \ No newline at end of file +Turnkey's send transaction and transaction status endpoints eliminate the need for third-party RPC providers. You save costs and reduce latency because we holistically incorporate internal data and minimize external calls. \ No newline at end of file