Use this file to discover all available pages before exploring further.
A vanity contract allows customization of the address of a smart contract being deployed. It does this by making its own StateInit depend on constant data that is randomly generated many times until a desired address is found. It is often used to deploy contracts with a specific prefix or suffix so the address is visible in block explorers.The contract code and data are included in the vanity deploy message. The vanity contract is first deployed with a StateInit that produces the desired address (see Addresses overview), and then immediately sets its actual state from the payload. This is a special case of upgrading contract’s code.
(int) slice_equal(slice s1, slice s2) asm "SDEQ";() recv_internal(cell in_msg_cell, slice in_msg) impure { ;; Parse data var ds = get_data().begin_parse(); ds~skip_bits(5); ;; Padding var owner = ds~load_msg_addr(); ds~skip_bits(256); ds.end_parse(); ;; Parse message var cs = in_msg_cell.begin_parse(); var flags = cs~load_uint(4); ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool slice sender = cs~load_msg_addr(); ;; Allow deployment only to the owner throw_unless(8, slice_equal(sender, owner)); ;; Set code and data var code = in_msg~load_ref(); var data = in_msg~load_ref(); in_msg.end_parse(); set_code(code); set_data(data);}
It checks whether the message comes from the owner specified in the data, then replaces its code and data with the ones provided in the incoming message. The owner field is required, because someone might intercept an external message, find salt in it, and concurrently deploy their own contract with this salt. Because a value of the owner field changes the address in an unpredictable way, an intercepted salt will be useless, unless attacker can send the message from the same owner address.The 256-bit salt is stored in this contract’s StateInit in addition to five padding bits and the owner address. The salt is not used by the contract’s logic (it is skipped with ds~skip_bits(256);); it only influences the resulting address via the StateInit hash.Because a contract address is derived from the StateInit hash, changing the salt changes the address deterministically. The search for a suitable salt happens entirely off-chain: a Python script (with an OpenCL kernel for speed) generates many random salt values, computes the resulting address, and reports matches. The on-chain vanity contract does not brute-force salts; it only verifies the owner and then sets the provided code and data when deployed.
To generate the salt, copy the code from src/generator in the same repository. It includes the run.py script and the vanity.cl OpenCL kernel.Run the command with the desired search parameters, including -w for the workchain and the owner address allowed to perform the deployment. The example below searches on the basechain for the specified suffix.
<SUFFIX> — desired address suffix; case sensitive when --case-sensitive is set.
<OWNER_ADDR> — address allowed to deploy via the vanity contract.
After running, the script prints logs and starts the search, printing every found salt. It also writes found salts to the found.txt file. The search continues until it is stopped or exits after the first match when --only-one is set. Example output:
The more specific the search, the rarer the matches, and the more compute is required to find one. A 4-character match typically appears in a few seconds on a laptop. TON user-friendly addresses are Base64, so each character encodes 6 bits; four characters correspond to 24 bits, i.e., about 1 in 224 trials on average. Once a salt is found, it can be used to deploy an arbitrary smart contract at that address.
import { toNano, Address } from '@ton/core';import { ExampleContract } from '../wrappers/ExampleContract';import { VanityContract } from '../wrappers/VanityContract';import { compile, NetworkProvider } from '@ton/blueprint';export async function run(provider: NetworkProvider) { const vanityContract = provider.open( VanityContract.createFromConfig({ owner: Address.parse('<OWNER_ADDR>'), salt: Buffer.from('<SALT_HEX>', 'hex'), }), ); const exampleContract = provider.open( ExampleContract.createFromConfig( {}, await compile('ExampleContract'), ), ); const init = exampleContract.init!; await vanityContract.sendDeploy( provider.sender(), toNano('0.01'), // attach value for deployment fees init.code, init.data, ); await provider.waitForDeploy(vanityContract.address);}
Where:
<OWNER_ADDR> — address allowed to deploy via the vanity contract.
<SALT_HEX> — 32-byte salt in hex found by the generator.
Run the script via npx blueprint run. The deployment succeeds when <OWNER_ADDR> matches the address of the wallet used for actual deployment. ExampleContract can be replaced with any contract; the vanity contract does not depend on the specifics of the code or data.