Streams

Learn about how you can integrate SOL Pay Streams into your applications!

Introduction

SOL Pay Streams are an innovative, fully non-custodial feature that allows micropayments to be accumulated every second and sent automatically from a user's Stream Wallet once a threshold is reached without requiring a user to constantly interact with their wallet (other than to refill the Stream Wallet whenever the balance is not healthy and is not enough for a transfer of the threshold amount). The Stream Wallet is held non-custodially on the SOL Pay side of the application and is not directly accessible by the main application except through the SDK. All stream requests require user approval, and no lamports will be sent from the Stream Wallet to the receiving address until the threshold amount has been reached.

Warning:

The SOL Pay Stream Wallet should not be considered as a permanent wallet. While the Stream Wallet can theoretically hold funds even after the main application has been closed, there is no guarantee that the Stream Wallet will be able to hold funds over a long period of time, especially across browser restarts or crashes. It is highly recommended that applications prompt users to back up their Stream Wallet using the backupStreamWallet method and restore their Stream Wallet at solpay.togatech.org/stream-wallet.

Start Streaming

You can start a stream easily in just a few lines of code (a single line of additional code after connecting to a user's wallet and the Solana network)! The below example streams 0.0000025 SOL per second and transfers at least 0.00015 SOL (the threshold amount) per minute from the pending stream balance to the receiving address. The Stream Wallet is refilled with 0.01 SOL whenever the balance is no longer healthy (not able to cover a transfer of the threshold amount).

Make sure to import the SOL Pay SDK using the instructions from the Quick Start page.

For more details about the code below, see the streamLamports method.

(async() => {
    /* Connect to wallet and network */
    await SOLPay.connectNetwork();
    await SOLPay.connectWallet();
    
    /* Start stream:                                   */
    /* 0.0000025 SOL accumulated per second            */
    /* 0.00015 SOL threshold to automatically transfer */
    /* 0.01 SOL refill when Stream Wallet runs low     */
    let stream = await SOLPay.streamLamports(
        "RECEIVING ADDRESS HERE",
        2500,
        10 ** 7,
        150000
    ); // true
})();

It is highly recommended that you prompt users to create a backup of their Stream Wallet.

For more details about the code below, see the backupStreamWallet method.

(async() => {
    /* ... */
    
    let backed_up = await SOLPay.backupStreamWallet(); // true
})();

Get Stream Details

At any point in time, you might want to know how much of the streamed lamports have been sent to the receiving wallet, how much is still pending (not yet at the threshold), the list of transaction signatures for stream transactions (which can be verified using transaction.php), whether the balance of the stream is healthy, when the last refill was requested, whether the stream is paused, or whether the stream is closed.

For more details about the code below, see the getStreamDetails method.

(async() => {
    /* ... */
    
    let details = await SOLPay.getStreamDetails(stream);
    /* {                           */
    /*     type: "...",            */
    /*     pending: 0,             */
    /*     sent: 0,                */
    /*     signatures: [...],      */
    /*     healthyBalance: true,   */
    /*     lastRequestedRefill: 0, */
    /*     paused: false           */
    /*     closed: false           */
    /* }                           */
})();

Refill Stream Wallet

The SOL Pay Stream Wallet is a non-custodial wallet held on the SOL Pay side of the application and is not accessible from the application directly. At some point, the Stream Wallet will run low on funds since all of the funds in the wallet have been streamed. Once the Stream Wallet no longer has a healthy balance (the threshold amount plus fees), SOL Pay will automatically start requesting a refill of the specified refill amount from the user every 45 seconds (starting immediately when the balance is no longer healthy).

However, if you want to override this 45 second delay in the case where a user accidentally declines the refill request (this override should be in the form of a manual button), there is a refill method available. The refill method will only request a refill if the balance is no longer healthy.

For more details about the code below, see the refillStream method.

(async() => {
    /* ... */
    
    let refillRequested = await SOLPay.refillStream(stream); // true
})();

Pause and Resume Stream

If you want to pause or resume the stream, you can use the pause and resume stream methods. If a stream is paused, any pending lamports will still be transferred if the amount of pending lamports is greater than the threshold. If the amount of pending lamports is below the threshold, no lamports will be transferred. However, if the balance of the Stream Wallet is not healthy, the user will still be prompted to refill the Stream Wallet. To disable these prompts and forfeit the pending lamports, please see the next section.

For more details about the code below, see the pauseStream and resumeStream methods.

(async() => {
    /* ... */
    
    let paused = await SOLPay.pauseStream(stream); // true
    
    let resumed = await SOLPay.resumeStream(stream); // true
})();

Close Stream

Once you want to close the stream, you can use the close stream method. Closing the stream will cancel all pending transfers, even if the amount of pending lamports is greater than the threshold. If you want to stop the stream but still want to recover any pending lamports in cases where the amount of pending lamports is greater than the threshold, please use the pause stream method instead.

There is no way to immediately recover pending lamports if the pending amount is less than the threshold. Instead, you can optionally retrieve the pending lamports using the getStreamDetails method and send them using one of the SOL Pay transaction methods (you may not always want to retrieve the pending lamports if the fee is too large compared to the pending amount).

The close stream method awaits for any pending transactions related to the current stream (refills or transfers) to complete to ensure that the state of the stream is finalized.

For more details about the code below, see the closeStream and sendSolanaLamports methods.

(async() => {
    /* ... */
    
    /* Close stream */
    let closed = await SOLPay.closeStream(stream); // true
    
    /* Retrieve final details (optional) */
    let finalDetails = await SOLPay.getStreamDetails(stream);
    
    /* Send the unsent pending stream balance manually (optional) */
    let transaction = await sendSolanaLamports(
        "RECEIVING ADDRESS HERE",
        finalDetails.pending
    );
    
    /* Calculate total amount streamed (optional) */
    let totalStreamed = finalDetails.sent + finalDetails.pending;
    console.log(`Streamed ${totalStreamed / (10 ** 9)} SOL in total!`);
})();

Last updated