Direct Deposits
Submit an escrow_vault deposit 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).
Credit is the vault ERC-20 share balance on ValueChain, not Spot or Perps. A successful requestDeposit does not mint shares in the same transaction. Claim only if settlement did not auto-deliver — 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. getMinDepositAmount() is raw underlying units; chainConfig.assetDecimals is the decimal count for RAW_AMOUNT.
The underlying must already be on ValueChain. If it is not, move it with Mirror Protocol first.
2. Submit requestDeposit
Install viem and tsx. Set PRIVATE_KEY, VAULT_ADDRESS, RECEIVER, RAW_AMOUNT (underlying base units), and REFERRAL (the bytes32 from Referrals, or omit it for bytes32(0)). This broadcasts an approval when needed and a deposit request.
Save as direct-deposit.mts and run npx tsx direct-deposit.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 amount = BigInt(process.env.RAW_AMOUNT!);
const referral = (process.env.REFERRAL as Hex | undefined) ?? zeroHash;
const vaultAbi = parseAbi([
"function getAsset() view returns (address)",
"function getMinDepositAmount() view returns (uint256)",
"function requestDeposit(uint256 assets, address receiver, bytes32 referral)",
]);
const erc20Abi = parseAbi([
"function approve(address spender, uint256 amount) returns (bool)",
"function allowance(address owner, address spender) view returns (uint256)",
]);
const [asset, minDeposit] = await Promise.all([
publicClient.readContract({ address: vault, abi: vaultAbi, functionName: "getAsset" }),
publicClient.readContract({ address: vault, abi: vaultAbi, functionName: "getMinDepositAmount" }),
]);
if (amount < minDeposit) throw new Error(`Amount below min deposit: ${minDeposit}`);
const allowance = await publicClient.readContract({
address: asset, abi: erc20Abi, functionName: "allowance", args: [account.address, vault],
});
if (allowance < amount) {
const approveHash = await walletClient.writeContract({
address: asset, abi: erc20Abi, functionName: "approve", args: [vault, amount],
});
const approveReceipt = await publicClient.waitForTransactionReceipt({ hash: approveHash });
if (approveReceipt.status !== "success") throw new Error("Approval reverted");
}
const hash = await walletClient.writeContract({
address: vault, abi: vaultAbi, functionName: "requestDeposit",
args: [amount, receiver, referral],
});
console.log({ requestTxHash: hash });
const receipt = await publicClient.waitForTransactionReceipt({ hash });
if (receipt.status !== "success") throw new Error("requestDeposit reverted");Save requestTxHash. Do not use getNextDepositRequestId as the claim ID.
3. Track settlement
Query Settlement and Claims with that hash and KIND=deposit. Empty or processing records do not confirm shares. Do not send a second deposit to retry a status query.
To submit with a user signature instead of this wallet paying gas, use Signed Deposits and the Transaction Relayer.
Last updated