ar.io Logoar.io Documentation

TurboAuthenticatedClient

getBalance()

Issues a signed request to get the credit balance of a wallet measured in AR (measured in Winston Credits, or winc).

const { winc: balance } = await turbo.getBalance();

getFreeStatus()

Returns the wallet's remaining free-tier upload allowance in bytes as { bytesRemaining }, so you can tell up front whether an upload will be free. bytesRemaining is null for a wallet with an unlimited allowance (an exempt/partner wallet), and 0 when the free tier is disabled on the target Turbo deployment. It is advisory — the authoritative free/charge decision is made at upload time — and is a wallet-side figure (a per-network cap may also apply). Deployment-wide free-tier limits are on the service's /info endpoint.

const { bytesRemaining } = await turbo.getFreeStatus();

It is also available on the TurboUnauthenticatedClient for any wallet by address:

const { bytesRemaining } = await turbo.getFreeStatus('a-native-address');

getPaymentHistory()

Issues a signed request for the signing wallet's own completed top-up (payment) history — both cryptocurrency and fiat top-ups — merged newest-first and keyset-paginated. This is self-scoped: it returns only the signing wallet's rows (the service reads the address from the signature, never a query parameter), so it is available on the TurboAuthenticatedClient only. limit is the page size (1-100, default 50). To page, pass the previous response's cursor while hasMore is true.

Each item is discriminated by type: a 'crypto' item includes wincCredited, tokenType, tokenQuantity, usdEquivalent, senderAddress, transactionId, and blockHeight; a 'fiat' item includes wincCredited, paymentAmount, currencyType, paymentProvider, receiptId, and giftMessage. Every item has an ISO-8601 UTC date.

const { payments, hasMore, cursor } = await turbo.getPaymentHistory({
  limit: 25,
});

// Fetch the next page while more results remain
if (hasMore) {
  const next = await turbo.getPaymentHistory({ limit: 25, cursor });
}

signer.getNativeAddress()

Returns the [native address][docs/native-address] of the connected signer.

const address = await turbo.signer.getNativeAddress();

getWincForFiat()

Returns the current amount of Winston Credits including all adjustments for the provided fiat currency, amount, and optional promo codes.

const { winc, paymentAmount, quotedPaymentAmount, adjustments } =
  await turbo.getWincForFiat({
    amount: USD(100),
    promoCodes: ['MY_PROMO_CODE'], // promo codes require an authenticated client
  });

createCheckoutSession()

Creates a Stripe checkout session for a Turbo Top Up with the provided amount, currency, owner, and optional promo codes. The returned URL can be opened in the browser, all payments are processed by Stripe. Promo codes require an authenticated client.

const { url, winc, paymentAmount, quotedPaymentAmount, adjustments } =
  await turbo.createCheckoutSession({
    amount: USD(10.0), // $10.00 USD
    owner: publicArweaveAddress,
    promoCodes: ['MY_PROMO_CODE'], // promo codes require an authenticated client
  });

// open checkout session in a browser
window.open(url, '_blank');

upload()

The easiest way to upload data to Turbo. The signal is an optional [AbortSignal] that can be used to cancel the upload or timeout the request. dataItemOpts is an optional object that can be used to configure tags, target, and anchor for the data item upload.

const uploadResult = await turbo.upload({
  data: 'The contents of my file!',
  signal: AbortSignal.timeout(10_000), // cancel the upload after 10 seconds
  dataItemOpts: {
    // optional
  },
  events: {
    // optional
  },
});

uploadFile()

Signs and uploads a raw file. There are two ways to provide the file to the SDK:

  1. Using a file parameter
  2. Using a fileStreamFactory and fileSizeFactory
Using file`

In Web with a file input:

const selectedFile = e.target.files[0];
const uploadResult = await turbo.uploadFile({
  file: selectedFile,
  dataItemOpts: {
    tags: [{ name: 'Content-Type', value: 'text/plain' }],
  },
  events: {
    onUploadProgress: ({ totalBytes, processedBytes }) => {
      console.log('Upload progress:', { totalBytes, processedBytes });
    },
    onUploadError: (error) => {
      console.log('Upload error:', { error });
    },
    onUploadSuccess: () => {
      console.log('Upload success!');
    },
  },
});

In NodeJS with a file path:

const filePath = path.join(__dirname, './my-unsigned-file.txt');
const fileSize = fs.stateSync(filePath).size;
const uploadResult = await turbo.uploadFile({
  file: filePath,
  dataItemOpts: {
    tags: [{ name: 'Content-Type', value: 'text/plain' }],
  },
});
Using fileStreamFactoryandfileSizeFactory`

Note: The provided fileStreamFactory should produce a NEW file data stream each time it is invoked. The fileSizeFactory is a function that returns the size of the file. The signal is an optional [AbortSignal] that can be used to cancel the upload or timeout the request. dataItemOpts is an optional object that can be used to configure tags, target, and anchor for the data item upload.

const filePath = path.join(__dirname, './my-unsigned-file.txt');
const fileSize = fs.stateSync(filePath).size;
const uploadResult = await turbo.uploadFile({
  fileStreamFactory: () => fs.createReadStream(filePath),
  fileSizeFactory: () => fileSize,
});
Customize Multi-Part Upload Behavior

By default, the Turbo upload methods will split files that are larger than 10 MiB into chunks and send them to the upload service multi-part endpoints. This behavior can be customized with the following inputs:

  • chunkByteCount: The maximum size in bytes for each chunk. Must be between 5 MiB and 500 MiB. Defaults to 5 MiB.
  • maxChunkConcurrency: The maximum number of chunks to upload concurrently. Defaults to 5. Reducing concurrency will slow down uploads, but reduce memory utilization and serialize network calls. Increasing it will upload faster, but can strain available resources.
  • chunkingMode: The chunking mode to use. Can be 'auto', 'force', or 'disabled'. Defaults to 'auto'. Auto behavior means chunking is enabled if the file would be split into at least three chunks.
  • maxFinalizeMs: The maximum time in milliseconds to wait for the finalization of all chunks after the last chunk is uploaded. Defaults to 1 minute per GiB of the total file size.
// Customize chunking behavior
await turbo.upload({
  ...params,
  chunkByteCount: 1024 * 1024 * 500, // Max chunk size
  maxChunkConcurrency: 1, // Minimize concurrency
});
// Disable chunking behavior
await turbo.upload({
  ...params,
  chunkingMode: 'disabled',
});
// Force chunking behavior
await turbo.upload({
  ...params,
  chunkingMode: 'force',
});

On Demand Uploads

With the upload methods, you can choose to Top Up with selected crypto token on demand if the connected wallet does not have enough credits to complete the upload.

This is done by providing the OnDemandFunding class to the fundingMode parameter on upload methods. The maxTokenAmount (optional) is the maximum amount of tokens in the token type's smallest unit value (e.g: Winston for arweave token type) to fund the wallet with. The topUpBufferMultiplier (optional) is the multiplier to apply to the estimated top-up amount to avoid underpayment during on-demand top-ups due to price fluctuations on longer uploads. Defaults to 1.1, meaning a 10% buffer.

Note: On demand API currently only available for ARIO(ario),ARIO (`ario`), SOL (solana), ETHonBaseNetwork(baseeth)andETH on Base Network (`base-eth`) and USDC on Base Network (base-usdc) token types.

const turbo = TurboFactory.authenticated({
  signer: arweaveSignerWithARIO,
  token: 'ario',
});
await turbo.upload({
  ...params,
  fundingMode: new OnDemandFunding({
    maxTokenAmount: ARIOToTokenAmount(500), // Max 500 $ARIO
    topUpBufferMultiplier: 1.1, // 10% buffer to avoid underpayment
  }),
});

x402 Uploads

Another method of uploading files is via the x402 protocol. This method is optimized for agent workflows and allows for direct uploads to Arweave gateways that support the x402 protocol using an EVM wallet and base-usdc token type.

const turbo = TurboFactory.authenticated({
  signer: ethereumSignerWithBaseUSDC,
  token: 'base-usdc',
});
await turbo.uploadFile({
  ...params,
  fundingMode: new X402Funding({ maxMUSDCAmount: 1_000_000 }), // Max 1 USDC. Opt out if too expensive
});

Raw x402 Data Uploads

Using the x402 protocol, you can also upload raw data to Turbo without signing a data item. This method is ideal for quick agent workflows where the ownership of the data is not required to be tied to a specific wallet. The eventual data item on chain will be signed by Turbo's x402 EVM signer.

const turbo = TurboFactory.authenticated({
  signer: ethereumSignerWithBaseUSDC,
  token: 'base-usdc',
});
await turbo.uploadRawX402Data({
  data: myRawData,
  maxMUSDCAmount: 1_000_000, // Max 1 USDC. Opt out if too expensive
});

NOTE: For free uploads under 100 KiB, this method of upload currently does not require a signature and can be used with an unauthenticated client.

// Unsigned free upload of raw data under 100 KiB
const turbo = TurboFactory.unauthenticated({ token: 'base-usdc' });
await turbo.uploadRawX402Data({
  data: myRawData,
});

uploadFolder()

Signs and uploads a folder of files. For NodeJS, the folderPath of the folder to upload is required. For the browser, an array of files is required. The dataItemOpts is an optional object that can be used to configure tags, target, and anchor for the data item upload. The signal is an optional [AbortSignal] that can be used to cancel the upload or timeout the request. The maxConcurrentUploads is an optional number that can be used to limit the number of concurrent uploads. The throwOnFailure is an optional boolean that can be used to throw an error if any upload fails. The manifestOptions is an optional object that can be used to configure the manifest file, including a custom index file, fallback file, or whether to disable manifests altogether. Manifests are enabled by default. The folderIndex is an optional folder index that skips files already on Arweave. The manifestDataItemOptsis an optional object that configures the manifest data item only, and defaults todataItemOpts`.

NodeJS Upload Folder
const folderPath = path.join(__dirname, './my-folder');
const { manifest, fileResponses, manifestResponse } = await turbo.uploadFolder({
  folderPath,
  dataItemOpts: {
    // optional
    tags: [
      {
        // User defined content type will overwrite file content type
        name: 'Content-Type',
        value: 'text/plain',
      },
      {
        name: 'My-Custom-Tag',
        value: 'my-custom-value',
      },
    ],
    // no timeout or AbortSignal provided
  },
  manifestOptions: {
    // optional
    indexFile: 'custom-index.html',
    fallbackFile: 'custom-fallback.html',
    disableManifests: false,
  },
});
Browser Upload Folder
<input type="file" id="folder" name="folder" webkitdirectory />
<script type="module">
  const folderInput = document.getElementById('folder');

  folderInput.addEventListener('change', async (event) => {
    const selectedFiles = folderInput.files;
    console.log('Folder selected:', selectedFiles);

    const { manifest, fileResponses, manifestResponse } =
      await turbo.uploadFolder({
        files: Array.from(selectedFiles).map((file) => file),
      });

    console.log(manifest, fileResponses, manifestResponse);
  });
</script>
Upload Folder with Progress Events

The uploadFolder method supports folder-level and per-file events for tracking upload progress. This is useful for building progress bars or providing feedback to users during folder uploads.

const folderPath = path.join(__dirname, './my-folder');
const { manifest, fileResponses, manifestResponse } = await turbo.uploadFolder({
  folderPath,
  events: {
    // Per-file events
    onFileStart: ({ fileName, fileSize, fileIndex, totalFiles }) => {
      console.log(
        `Starting file ${
          fileIndex + 1
        }/${totalFiles}: ${fileName} (${fileSize} bytes)`,
      );
    },
    onFileProgress: ({
      fileName,
      fileIndex,
      totalFiles,
      fileProcessedBytes,
      fileTotalBytes,
      step,
    }) => {
      const percentComplete = (fileProcessedBytes / fileTotalBytes) * 100;
      console.log(
        `File ${
          fileIndex + 1
        }/${totalFiles} (${fileName}) ${step}: ${percentComplete.toFixed(2)}%`,
      );
    },
    onFileComplete: ({ fileName, fileIndex, totalFiles, id }) => {
      console.log(
        `Completed file ${fileIndex + 1}/${totalFiles}: ${fileName} (${id})`,
      );
    },
    onFileError: ({ fileName, fileIndex, totalFiles, error }) => {
      console.error(
        `Error uploading file ${fileIndex + 1}/${totalFiles}: ${fileName}`,
        error,
      );
    },
    // Folder-level aggregate events
    onFolderProgress: ({
      processedFiles,
      totalFiles,
      processedBytes,
      totalBytes,
      currentPhase,
    }) => {
      const percentComplete = (processedBytes / totalBytes) * 100;
      console.log(
        `Folder progress (${currentPhase}): ${processedFiles}/${totalFiles} files, ${percentComplete.toFixed(
          2,
        )}%`,
      );
    },
    onFolderError: (error) => {
      console.error('Folder upload error:', error);
    },
    onFolderSuccess: () => {
      console.log('Folder upload complete!');
    },
  },
});
Incremental Folder Uploads

An Arweave upload is permanent, so paying twice for byte identical files buys nothing. Pass a folderIndex and uploadFolder hashes every file, asks the index which of those files already have a data item on Arweave, and signs, uploads and pays for only the rest. The manifest is assembled from the ids that were already known plus the ids of whatever this run uploaded.

import {
  composeFolderIndex,
  createChainFolderIndex,
  createFileFolderIndex,
} from '@ardrive/turbo-sdk/node';

const folderIndex = composeFolderIndex([
  // Fast local cache, kept outside the folder being uploaded.
  createFileFolderIndex({ filePath: '.turbo/folder-index.jsonl' }),
  // Fallback for a machine that has never deployed before, e.g. a CI runner.
  // getPublicKey() is the one form every signer type can produce.
  createChainFolderIndex({ owner: await turbo.signer.getPublicKey() }),
]);

const { manifest, manifestResponse, folderIndexSummary } =
  await turbo.uploadFolder({
    folderPath: path.join(__dirname, './dist'),
    folderIndex,
    // Deploy varying tags belong on the manifest, which is rewritten every time.
    manifestDataItemOpts: {
      tags: [{ name: 'Git-Commit', value: process.env.GITHUB_SHA }],
    },
  });

console.log(folderIndexSummary);
// { totalFiles: 143, uploadedFiles: 2, reusedFiles: 141, ... }
What a reused file is matched on

An index key is \<sha-256 of the bytes\>.\<sha-256 of the tags\>, and both halves matter. Keying on the bytes alone would reuse a data item whose tags are not the ones you asked for: an empty a.css and an empty b.js hash identically, and sharing one item between them would serve JavaScript as text/css, which a browser refuses to execute. Covering the tags means a reused data item is always exactly the data item this call would otherwise have created — same bytes, same Content-Type, same dataItemOpts tags.

Files uploaded with an index carry one extra tag, File-SHA256, holding the sha-256 of their own bytes. That tag is what createChainFolderIndex filters on.

The trade-off this buys, and how you find out

The corollary is a real cost cliff, so it is worth being blunt about. A per file tag whose value changes between deploys changes every key, and re-uploads the whole folder at full price. A commit sha, a build number or a timestamp in dataItemOpts means you never reuse anything, and the deploy still succeeds, so nothing about the run looks wrong except the bill.

That is deliberate. The alternative — keying on bytes alone — reuses an item tagged with a previous deploy's commit sha, so the tags on chain quietly stop describing what is on chain. A wrong bill is recoverable; a data item that lies about itself is permanent. So the index errs towards paying again.

To keep the cliff from being silent, uploadFolder logs a warning when a file it is about to upload has bytes the index already holds under a different set of tags, which is what a deploy-varying per file tag looks like:

3 of the 3 file(s) this run is about to upload are already on Arweave byte for
byte, under a different set of tags. Their content has not changed but their
tags have, so they are being paid for again. A folder index key covers the tags
on a file as well as its bytes. That is usually a tag in dataItemOpts whose
value changes between deploys -- a commit sha, a build number, a timestamp -- in
which case move it to manifestDataItemOpts rather than paying for these files
again. It can also be a file that kept its content but changed its Content-Type,
through a rename or a new extension, which is expected and costs one upload.

Very little else produces that signal: a folder the index has never seen has unknown bytes, and a layer that could not be reached reports nothing known, so neither triggers it. A file that kept its content but changed its Content-Type through a rename does trigger it, and the message says so. It also fires for one drifted file among a hundred reused ones, not only when everything misses. A layer that does not implement the optional knownContentHashes cannot answer the question and stays quiet. The fix, whenever it is a varying tag, is always the same: move it to manifestDataItemOpts, since the manifest is rewritten on every deploy anyway.

Index layers
LayerWhere it livesSurvives a fresh checkout
createMemoryFolderIndex(seed?)memoryno
createFileFolderIndex({ filePath }) (NodeJS)a JSON lines logonly if the file is kept
createChainFolderIndex({ owner, appName?, ... })gateway GraphQLyes
composeFolderIndex([...])layers the above--

Reads fall through a composed index in order and writes go to every layer that is not readOnly, so an id recovered from the gateway is cached locally for the next run. A layer that throws is skipped, not propagated — a full disk under the file layer must not stop the memory layer from holding ids the run has already paid for, and an unreachable gateway must not stop the local cache from answering. Pass a logger as the second argument to composeFolderIndex to see which layer was skipped and why.

createFileFolderIndex writes an append-only log, one JSON record per line, compacted when it is next loaded. It appends after every single upload rather than rewriting at the end of the run, so a deploy killed part way through never loses a file it has paid for — and appending is constant work per file, where rewriting the whole file per upload is quadratic and costs minutes and gigabytes of writes on a first deploy of a few thousand files. It is also the more crash safe shape: a process killed mid write can only damage the last line, which is dropped on load, where a torn rewrite loses every id in the file.

An index is a cache. A get or resolve that throws is treated as a miss and logged — an unreachable gateway costs you a re-upload, it does not fail your deploy. Anything with get and set is a valid index, so implement TurboFolderUploadIndex to back one with a database, an object store, or a CI cache. Treat the keys as opaque.

Telling a gateway whose uploads to sweep

createChainFolderIndex needs the owner a gateway indexes uploads under, which is the base64url sha-256 of the signer's public key. Pass await turbo.signer.getPublicKey() and the SDK derives it, which works for every signer type.

A bare string is deliberately rejected, because it cannot be disambiguated: a raw 32 byte ed25519 public key base64urls to exactly 43 characters, the same shape as an owner address, and guessing wrong means the sweep matches nothing and the whole folder is re-uploaded with no error at all. Say which one you have — { publicKey } or { address } — if you are not passing the bytes.

An 0x... Ethereum address or a base58 Solana address is not accepted, because owners: on a gateway does not match those. (Verified against arweave.net: owners matches the 43 character address and returns nothing for the raw public key, so the conversion has to happen client side.)

Trust model

The sweep is scoped to owners: [your own address], so it can only ever find items you signed. Within that scope, File-SHA256 is self asserted — it is a tag your own past uploads wrote, not something a gateway verifies against the bytes — and the index trusts it. That is safe for uploads this SDK made, since it only ever writes a hash it computed from the file in front of it.

uploadFolder writes whichever tag the index it is given declares, so setting hashTagName moves both the tag that is written and the tag the sweep filters on, and the two cannot drift apart. Every layer in a composeFolderIndex stack that declares one has to declare the same one, or the call throws: one tag is written per file, so a stack that disagrees would leave whichever layer lost matching nothing, for ever, without an error.

It stops being safe if you point hashTagName at a tag you were already using for something else. Any of your own past items carrying 64 hex characters under that name would be treated as a candidate, and one whose tag set happens to match would be reused — putting a manifest path in front of unrelated bytes. Use a name nothing else of yours writes.

When the sweep runs out of pages

A sweep can examine at most pageSize * maxPages items, 2,000 by default. A folder with more files than that, or a long enough deployment history, can therefore reach the page limit with files still unresolved — and those files are uploaded and paid for again while the summary reports them as ordinary new files. Pass a logger to createChainFolderIndex and it says so when this happens, naming how many files were left. Raise maxPages or pageSize, or put a createFileFolderIndex in front, and the sweep has less to find.

In the browser

createMemoryFolderIndex, createChainFolderIndex and composeFolderIndex all work in the browser. createFileFolderIndex is NodeJS only, since there is no filesystem to write to; persist the map yourself and seed createMemoryFolderIndex with it, or rely on the chain index.

Note that hashing differs by platform. NodeJS streams each file through a node:crypto digest, so file size is not a concern. The browser has no streaming WebCrypto digest, so each File is buffered whole before it is hashed — a very large File can exhaust the tab.

Known limitation

A gateway indexes an upload minutes after it lands, so two machines deploying the same brand new file at the same moment can each pay for it once. Only the bill is affected, and only for genuinely new bytes -- the manifest is correct either way.

topUpWithTokens()

Tops up the connected wallet with Credits by submitting a payment transaction for the token amount to the Turbo wallet and then submitting that transaction id to Turbo Payment Service for top up processing.

  • The tokenAmount is the amount of tokens in the token type's smallest unit value (e.g: Winston for arweave token type) to fund the wallet with.
  • The feeMultiplier (optional) is the multiplier to apply to the reward for the transaction to modify its chances of being mined. Credits will be added to the wallet balance after the transaction is confirmed on the given blockchain. Defaults to 1.0, meaning no multiplier.
  • The turboCreditDestinationAddress (optional) is the native address to credit the funds to. If not provided, the connected wallet's native address will be used. Note: Not available for KYVE token type.
Arweave (AR) Crypto Top Up
const turbo = TurboFactory.authenticated({ signer, token: 'arweave' });

const { winc, status, id, ...fundResult } = await turbo.topUpWithTokens({
  tokenAmount: WinstonToTokenAmount(100_000_000), // 0.0001 AR
  feeMultiplier: 1.1, // 10% increase in reward for improved mining chances
  turboCreditDestinationAddress: '0xabc...123', // Any custom EVM / SOL / AR / KYVE native destination address
});
AR.IO Network (ARIO) Crypto Top Up
const turbo = TurboFactory.authenticated({ signer, token: 'ario' });

const { winc, status, id, ...fundResult } = await turbo.topUpWithTokens({
  tokenAmount: ARIOToTokenAmount(100), // 100 $ARIO
});
USDC Crypto Top Up

// USDC on Ethereum Mainnet
const { winc, status, id, ...fundResult } = await TurboFactory.authenticated({
  signer,
  token: 'usdc',
}).topUpWithTokens({
  tokenAmount: USDCToTokenAmount(1), // 1 USDC
});

// USDC on Base Network
const { winc, status, id, ...fundResult } = await TurboFactory.authenticated({
  signer,
  token: 'base-usdc',
}).topUpWithTokens({
  tokenAmount: USDCToTokenAmount(1), // 1 USDC
});


// USDC on Polygon Network
const { winc, status, id, ...fundResult } = await TurboFactory.authenticated({
  signer,
  token: 'polygon-usdc',
}).topUpWithTokens({
  tokenAmount: USDCToTokenAmount(1), // 1 USDC
});
Ethereum (ETH) Crypto Top Up
const turbo = TurboFactory.authenticated({ signer, token: 'ethereum' });

const { winc, status, id, ...fundResult } = await turbo.topUpWithTokens({
  tokenAmount: ETHToTokenAmount(0.00001), // 0.00001 ETH
});
Polygon (POL / MATIC) Crypto Top Up
const turbo = TurboFactory.authenticated({ signer, token: 'pol' });

const { winc, status, id, ...fundResult } = await turbo.topUpWithTokens({
  tokenAmount: POLToTokenAmount(0.00001), // 0.00001 POL
});
Eth on Base Network Crypto Top Up
const turbo = TurboFactory.authenticated({ signer, token: 'base-eth' });

const { winc, status, id, ...fundResult } = await turbo.topUpWithTokens({
  tokenAmount: ETHToTokenAmount(0.00001), // 0.00001 ETH bridged on Base Network
});
Solana (SOL) Crypto Top Up
const turbo = TurboFactory.authenticated({ signer, token: 'solana' });

const { winc, status, id, ...fundResult } = await turbo.topUpWithTokens({
  tokenAmount: SOLToTokenAmount(0.00001), // 0.00001 SOL
});
KYVE Crypto Top Up
const turbo = TurboFactory.authenticated({ signer, token: 'kyve' });

const { winc, status, id, ...fundResult } = await turbo.topUpWithTokens({
  tokenAmount: KYVEToTokenAmount(0.00001), // 0.00001 KYVE
});

shareCredits()

Shares credits from the connected wallet to the provided native address and approved winc amount. This action will create a signed data item for the approval

const { approvalDataItemId, approvedWincAmount } = await turbo.shareCredits({
  approvedAddress: '2cor...VUa',
  approvedWincAmount: 800_000_000_000, // 0.8 Credits
  expiresBySeconds: 3600, // Credits will expire back to original wallet in 1 hour
});

revokeCredits()

Revokes all credits shared from the connected wallet to the provided native address.

const revokedApprovals = await turbo.revokeCredits({
  revokedAddress: '2cor...VUa',
});

getCreditShareApprovals()

Returns all given or received credit share approvals for the connected wallet or the provided native address.

const { givenApprovals, receivedApprovals } =
  await turbo.getCreditShareApprovals({
    userAddress: '2cor...VUa',
  });

How is this guide?