For the complete documentation index, see llms.txt. This page is also available as Markdown.

Direct Redemptions

Submit an escrow_vault redemption from the user's wallet. The wallet pays ValueChain gas. This is not a signed OnBehalf call and not a SoDEX RWA (clob) trade. See Vault Lifecycle for settlement. Encode referral first (Referrals).

The request spends vault shares the user already holds. No underlying-asset approval is required. Credit is the underlying asset on ValueChain, not Spot or Perps. A successful requestRedeem does not return assets in the same transaction. Immediate settlement is not delayed settlement. Claim only if a leg was not auto-delivered — that step is on Settlement and Claims.

1. Select the vault

Load contracts.vault from Fund Information for an escrow_vault fundId. Check fundStatus and chainConfig.paused. getMinRedeemShares() is raw vault-share units; RAW_AMOUNT uses that same unit.

2. Submit requestRedeem

Install viem and tsx. Set PRIVATE_KEY, VAULT_ADDRESS, RECEIVER, RAW_AMOUNT (share base units), and REFERRAL (the bytes32 from Referrals, or omit it for bytes32(0)). This broadcasts a redemption request.

Save as direct-redeem.mts and run npx tsx direct-redeem.mts.

import {
  createPublicClient, createWalletClient, defineChain, http, parseAbi, zeroHash,
  type Address, type Hex,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";

const valuechain = defineChain({
  id: 286623, name: "ValueChain",
  nativeCurrency: { name: "SOSO", symbol: "SOSO", decimals: 18 },
  rpcUrls: { default: { http: ["https://mainnet.valuechain.xyz"] } },
});
const account = privateKeyToAccount(process.env.PRIVATE_KEY as Hex);
const publicClient = createPublicClient({ chain: valuechain, transport: http() });
const walletClient = createWalletClient({ account, chain: valuechain, transport: http() });
const vault = process.env.VAULT_ADDRESS as Address;
const receiver = process.env.RECEIVER as Address;
const shares = BigInt(process.env.RAW_AMOUNT!);
const referral = (process.env.REFERRAL as Hex | undefined) ?? zeroHash;
const vaultAbi = parseAbi([
  "function getMinRedeemShares() view returns (uint256)",
  "function balanceOf(address account) view returns (uint256)",
  "function requestRedeem(uint256 shares, address receiver, bytes32 referral)",
]);

const [minShares, balance] = await Promise.all([
  publicClient.readContract({ address: vault, abi: vaultAbi, functionName: "getMinRedeemShares" }),
  publicClient.readContract({ address: vault, abi: vaultAbi, functionName: "balanceOf", args: [account.address] }),
]);
if (shares < minShares) throw new Error(`Shares below min redeem: ${minShares}`);
if (balance < shares) throw new Error(`Insufficient vault shares: have ${balance}`);

const hash = await walletClient.writeContract({
  address: vault, abi: vaultAbi, functionName: "requestRedeem",
  args: [shares, receiver, referral],
});
console.log({ requestTxHash: hash });
const receipt = await publicClient.waitForTransactionReceipt({ hash });
if (receipt.status !== "success") throw new Error("requestRedeem reverted");

Save requestTxHash. Do not use getNextRedeemRequestId as the claim ID.

3. Track settlement

Query Settlement and Claims with that hash and KIND=redeem. Empty or processing records do not confirm assets. Keep tracking a delayed leg even if the immediate leg is done. Do not send a second redemption to retry a status query.

To submit with a user signature instead of this wallet paying gas, use Signed Redemptions and the Transaction Relayer.

Last updated