Universal Lockup Wallet
Universal Lockup Wallet implements time-based fund locking with allowlist functionality. All funds unlock simultaneously when the time restrictions expire. Source code:universal/uni-lockup-wallet.fc
Use cases
Escrow services. Lock funds until conditions are met, with allowlist of valid recipients.Persistent memory layout
seqno: 32-bit sequence number for replay protection.subwallet_id: 32-bit wallet identifier.public_key: 256-bit Ed25519 public key for signing external messages (wallet operations).config_public_key: 256-bit Ed25519 public key for signing internal messages that add locked funds. This separation allows a third party to initialize and fund the lockup wallet without having access to spend the funds.allowed_destinations: Prefix dictionary of allowlisted destination addresses (usespfxdict_get?for prefix matching).total_locked_value: Total amount of locked funds (unrestricted destinations).locked: Dictionary mapping unlock timestamps to locked amounts.total_restricted_value: Total amount of restricted funds (allowlist-only).restricted: Dictionary mapping unlock timestamps to restricted amounts.
Message layout
External message body layout
signature: 512-bit Ed25519 signature.subwallet_id: 32-bit subwallet identifier.valid_until: 32-bit Unix timestamp.msg_seqno: 32-bit sequence number.- Message list: References to messages to send.
raw_reserve(effectively_locked, 2), and sends messages. Each message is sent with its specified mode, but if mode is not 2, it’s forced to mode 3 (pay fees separately, ignore errors).
Internal message body layout
Internal messages withop = 0x82eaf9c4 (rwallet_op) allow adding locked funds:
- Must carry ≥1 TON value.
- Contain valid signature from
config_public_key. cmdmust be0x373aa9f4(restricted_transfer).only_restrict: Flag determining lock type:1for restricted funds,0for locked funds.timestamp: Unix timestamp for unlock.
Internal messages with other opcodes from allowlisted addresses are silently ignored.
Get methods
int seqno()returns current sequence number.int wallet_id()returns current subwallet ID.int get_public_key()returns stored public key.(int, int, int) get_balances_at(int time)returns balance, restricted value, and locked value at specified time.(int, int, int) get_balances()returns current balance, restricted value, and locked value.int check_destination(slice destination)returns whether destination address is allowlisted.
There is no get-method for
config_public_key. This is by design — the configuration key is only used internally for adding locked funds.Exit codes
| Exit code | Description |
|---|---|
| 31 | Signature verification failed (wrong_signature) |
| 32 | Config signature verification failed |
| 33 | Message value too small (< 1 TON) |
| 34 | Sequence number mismatch (wrong_seqno) |
| 35 | Subwallet ID mismatch (wrong_subwallet_id) |
| 36 | Message expired (replay_protection) |
| 40 | Unknown operation code (unknown_op) |
| 41 | Unknown command (unknown_cmd) |
Vesting Wallet
Vesting Wallet implements gradual fund unlocking over time with an optional cliff period. The funds unlock linearly according to a vesting schedule. Available through web interface. Source code.Use cases
Employee token vesting. Lock employee tokens with vesting schedule (e.g., 4 years with 1-year cliff).Persistent memory layout
stored_seqno: 32-bit sequence number (replay protection).stored_subwallet: 32-bit wallet identifier.public_key: 256-bit Ed25519 public key for signing external messages.start_time: 64-bit Unix timestamp when vesting begins.total_duration: 32-bit total vesting duration in seconds.unlock_period: 32-bit period between unlocks in seconds.cliff_duration: 32-bit cliff period before first unlock.total_amount: Total amount subject to vesting.allow_elector: Boolean flag that bypasses vesting restrictions for transfers to Elector and Config contracts.
Message layout
External message body layout
signature: 512-bit Ed25519 signature.subwallet_id: 32-bit subwallet identifier.valid_until: 32-bit Unix timestamp.msg_seqno: 32-bit sequence number.- Optional: One message reference. If present, mode MUST be 3 (pay fees separately, ignore errors).
- Before
start_time + cliff_duration: All funds locked. - During vesting: Linear unlock based on
unlock_period. - After
start_time + total_duration: All funds unlocked.
allow_elector is enabled, vesting restrictions are bypassed for transfers to system contracts (see allow_elector field description above).
Internal message body layout
Internal messages are ignored (no operations performed).Get methods
int seqno()returns current sequence number.int get_public_key()returns stored public key.int get_locked_amount(int now_time)returns locked amount at specified time.(int, int, int, int, int, int) get_lockup_data()returns(start_time, total_duration, unlock_period, cliff_duration, total_amount, allow_elector).
Exit codes
| Exit code | Description |
|---|---|
| 33 | Sequence number mismatch |
| 34 | Subwallet ID mismatch |
| 35 | Signature verification failed |
| 36 | Message expired (valid_until check failed) |
| 37 | Invalid number of message references |
| 38 | Invalid send mode (must be 3 if message present) |