Build a Native project
Use a reviewed template or integrate a custom contract with BondrailEarner.
factory.deployNative need no individual review.
Both paths still require valid terms and sufficient history.Create the account
BondrailFactory.createAccount(asset) creates the issuer's account in the token used for fees, funding
and repayment. History starts at the first nonzero booked revenue, before any bond exists.
import { bondrailClient } from '@bondrail/sdk/client';
const bondrail = bondrailClient({ publicClient, walletClient, factory });
const account = await bondrail.createAccount(asset);Option 1: deploy a reviewed template
The disclosed reviewer approves the hash of creation code with setNativeTemplate(hash, true).
An issuer then calls deployNative(account, creationCode, args, salt). args must be ABI-encoded
constructor arguments beginning with the account. The factory deploys that code with CREATE2, records
templateOf(project), and binds it through bindProjectFromFactory in the same transaction.
import { bondrailFactoryAbi } from '@bondrail/sdk/abis';
import { encodeAbiParameters } from 'viem';
// Example for a reviewed template whose only constructor parameter is the account.
const args = encodeAbiParameters([{ type: 'address' }], [account]);
const { request } = await publicClient.simulateContract({
address: factory, abi: bondrailFactoryAbi, functionName: 'deployNative',
args: [account, reviewedCreationCode, args, salt], account: walletClient.account!,
});
const hash = await walletClient.writeContract(request);
const receipt = await publicClient.waitForTransactionReceipt({ hash });
if (receipt.status !== 'success') throw new Error('Template deployment failed');Use the actual reviewed template's full constructor layout and exact bytecode. No separate per-project
approval is needed for this path. Revocation through setNativeTemplate removes template-based approval;
an independent nativeApproved(project) approval can still authorize that project.
Option 2: inherit the package in a custom contract
npm i @bondrail/contractsSee the package README for
tarballs before publication, forge install, and npm/Git remappings. Both use this import:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {BondrailEarner} from "@bondrail/contracts/src/BondrailEarner.sol";
contract MyProject is BondrailEarner {
constructor(address account) BondrailEarner(account) {}
function pay(uint256 gross) external returns (uint256 net) {
return _collect(msg.sender, gross, gross / 100);
}
}The issuer deploys the contract and calls BondrailAccount.bindProject(project) once. The reviewer
must then call setNativeApproval(project, true) before createBond can accept it. Inheriting
BondrailEarner alone does not prove all fee paths use it. Review must examine alternate fee routes,
upgrade/admin powers and caller authentication. The account reference in the base is immutable.
Route each fee and authenticate the payer
_collect(payer, gross, fee) calls account.collect: it pulls from the payer, books the fee and sends
the net to the project. Payers approve the account. Use msg.sender or independently authenticated
intent; never expose an arbitrary-payer pull to untrusted callers. _collectWithPermit supports an
EIP-2612 token; signAccountPermit in @bondrail/sdk/permit signs for the account as spender.
_settleOut(payer, gross, fee) approves and pulls funds from the project, then sends the net to the
payer; the recipient approves nothing. Both routes use the account's asset. Tiny percentage fees can
round to zero, so choose payment bounds and rounding deliberately.
function _collect(address payer, uint256 gross, uint256 fee) internal returns (uint256 net) {
return _bondrailAccount.collect(payer, gross, fee);
}function _settleOut(address payer, uint256 gross, uint256 fee) internal returns (uint256 net) {
IERC20(_bondrailAccount.asset()).forceApprove(address(_bondrailAccount), gross);
return _bondrailAccount.settleOut(payer, gross, fee);
}During an Active bond, BondrailAccount._checkPayment enforces fee * 10000 >= gross * minFeeBps().
The factory checks review/binding at issuance, deposits, activation and second release. These checks
do not prove future demand or stop a business moving users elsewhere. See the trust model
and the external Foundry example.