VaultRegistrar Integration Guide
AI assistant skill pack for integrating DS Tokens into a DeFi protocol using Securitize's VaultRegistrar on the DS Protocol testnet. Use this context for all questions, code generation, and debugging in your project.
What VaultRegistrar does
VaultRegistrar is an on-chain registry that authorises DeFi operator contracts to manage DS Token vaults on behalf of investors. DS Token is a permissioned ERC-20 — transfers only succeed if both sender and receiver are registered in the DS Protocol. VaultRegistrar bridges that permission model with DeFi.
The 7-step integration lifecycle
- Get DS Tokens — Use the testnet faucet at https://labs.dev.securitize.io/faucet.
- Register as Operator — Call
addOperator(yourContract)on VaultRegistrar. Your protocol contract (the one that callsregisterVault()) must holdOPERATOR_ROLE. Do this once at https://labs.dev.securitize.io/register-as-operator. - Deploy a vault — Deploy an ERC-4626-compatible vault that accepts DS Token.
- Collect investor signature — Investor signs EIP-712 typed data (see below).
- Call
registerVault()— Your contract submits the signature on-chain. - Transfer tokens — DS Tokens move into the vault.
- Protocol interaction — Your protocol logic executes with registered tokens.
The operator concept
The operator field in the EIP-712 message must match the exact msg.sender of registerVault() on-chain. This is your protocol contract — not the deployer EOA, not a backend wallet. The contract calls registerVault(), so the contract address is the one that needs OPERATOR_ROLE.
IVaultRegistrar interface
interface IVaultRegistrar {
function registerVault(
address vault,
address investor,
uint256 deadline,
bytes calldata signature
) external;
function addOperator(address operator) external;
function removeOperator(address operator) external;
function isOperator(address operator) external view returns (bool);
function invalidateNonce() external;
function operatorNonce(address investor, address operator)
external view returns (uint256);
}
EIP-712 typed data
Investors sign this structure. Your contract must verify the same structure when calling registerVault().
Domain:
name:"VaultRegistrar"version:"1"chainId: the target chain IDverifyingContract: the VaultRegistrar proxy address
Type VaultPermission:
investoraddress— the investor's walletoperatoraddress— your protocol contract (must holdOPERATOR_ROLE)tokenaddress— DS Token contract addressnonceuint256— read fromoperatorNonce(investor, operator)before signingdeadlineuint256— Unix timestamp, e.g.block.timestamp + 1 hour
Collecting the signature (wagmi / viem)
import { useSignTypedData } from 'wagmi'
const { signTypedData } = useSignTypedData()
signTypedData({
domain: {
name: 'VaultRegistrar',
version: '1',
chainId,
verifyingContract: VAULT_REGISTRAR_ADDRESS,
},
types: {
VaultPermission: [
{ name: 'investor', type: 'address' },
{ name: 'operator', type: 'address' },
{ name: 'token', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
},
primaryType: 'VaultPermission',
message: {
investor: investorAddress,
operator: YOUR_PROTOCOL_CONTRACT,
token: DS_TOKEN_ADDRESS,
nonce: await publicClient.readContract({
address: VAULT_REGISTRAR_ADDRESS,
abi: vaultRegistrarAbi,
functionName: 'operatorNonce',
args: [investorAddress, YOUR_PROTOCOL_CONTRACT],
}),
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
},
})
Calling registerVault() from your contract
function deposit(
address investor,
address vault,
uint256 amount,
uint256 deadline,
bytes calldata signature
) external {
// 1. Register the vault using the investor's EIP-712 signature
IVaultRegistrar(VAULT_REGISTRAR).registerVault(
vault,
investor,
deadline,
signature
);
// 2. Transfer DS Tokens into the vault
IERC20(DS_TOKEN).transferFrom(investor, vault, amount);
// 3. Your protocol logic
}
msg.sender of this function must equal the operator in the signature and must hold OPERATOR_ROLE on the VaultRegistrar.
Common errors
| Error | Cause |
|---|---|
InvalidSignature | operator in signature ≠ msg.sender, or wrong nonce / deadline |
SignatureExpired | block.timestamp > deadline — use a future deadline |
InvalidNonce | Investor called invalidateNonce() — fetch a fresh nonce |
OperatorNotRegistered | msg.sender does not hold OPERATOR_ROLE |
VaultAlreadyRegistered | Vault already registered for this investor + operator pair |
Sandbox tools
Use the live sandbox at https://labs.dev.securitize.io to test your integration:
- Faucet
/faucet— Get testnet DS Tokens - Register as Operator
/register-as-operator— Add your contract to VaultRegistrar - Mock Protocol Example
/mock-protocol— Run a full sign → approve → deposit flow in the browser - Protocol Tester
/protocol-tester— Upload your ABI and call any write function with EIP-712 signing support - Docs
/docs— Full integration documentation
See also
- Operator Registration — the underlying flow the skill encodes.
- API Reference — contract functions, events, errors.
- Integration Guide — the step-by-step walkthrough this skill trains the assistant on.