ve(3,3): lock, vote, earn
The ve(3,3) system aligns liquidity incentives with token holders. The cycle is:
- Lock BARK into a
veNFTto get voting power. - Vote each epoch for the pools you want emissions directed to.
- Earn the trading fees and bribes from the pools you voted for, plus a rebase.
- Liquidity providers stake their position NFTs into gauges to receive the BARK emissions.
Epochs are weekly (Thursday 00:00 UTC boundaries, THENA-style).
1. Lock BARK → veNFT
import { Contract, MaxUint256, parseUnits } from 'ethers';
const BARK = '0x776347AF16E01BE5CdC028b556bE029C156024a2';
const VOTING_ESCROW = '0x19cDA4B6EEb4AB71033Ef926c9ee096Af25E8bdd';
const ERC20_ABI = ['function approve(address,uint256) returns (bool)'];
const VE_ABI = [
'function create_lock(uint256 _value, uint256 _lock_duration) returns (uint256 tokenId)',
'function increase_amount(uint256 _tokenId, uint256 _value)',
'function increase_unlock_time(uint256 _tokenId, uint256 _lock_duration)',
'function withdraw(uint256 _tokenId)',
];
await (await new Contract(BARK, ERC20_ABI, signer).approve(VOTING_ESCROW, MaxUint256)).wait();
const ve = new Contract(VOTING_ESCROW, VE_ABI, signer);
const amount = parseUnits('1000', 18);
const twoYears = 2 * 365 * 24 * 60 * 60; // max lock
const tx = await ve.create_lock(amount, twoYears);
await tx.wait();
// The veNFT tokenId is emitted in the Deposit event; read it from the receipt logs.
Longer locks give more voting power. Extend with increase_unlock_time, add BARK with
increase_amount, and withdraw once the lock has fully expired.
2. Vote for pools
Each epoch, allocate your veNFT's voting power across pools. Weights are relative — they're normalized to your total power.
const VOTER = '0x32d5633feB481A9a0A5C483C728CA75c3b29d1d8';
const VOTER_ABI = [
'function vote(uint256 _tokenId, address[] _poolVote, uint256[] _weights)',
'function reset(uint256 _tokenId)',
'function poke(uint256 _tokenId)',
];
const voter = new Contract(VOTER, VOTER_ABI, signer);
const tx = await voter.vote(
veTokenId,
['0xPoolA', '0xPoolB'],
[70, 30], // 70% / 30% of voting power
);
await tx.wait();
A veNFT can vote once per epoch. Use reset to clear votes, or poke to re-apply your last
weights with refreshed voting power.
3. Claim rewards
After voting you accrue fees and bribes from the pools you backed, plus a rebase from
the RewardsDistributor.
const VOTER_ABI = [
'function claimRewards(address[] _gauges)',
'function claimBribes(address[] _bribes, address[][] _tokens, uint256 _tokenId)',
'function claimFees(address[] _fees, address[][] _tokens, uint256 _tokenId)',
];
const REWARDS_DISTRIBUTOR = '0xA5c526a74b2262503200Bd4359212014cfE31f95';
const RD_ABI = ['function claim(uint256 _tokenId) returns (uint256)'];
const voter = new Contract(VOTER, VOTER_ABI, signer);
await (await voter.claimBribes(bribeAddrs, bribeTokens, veTokenId)).wait();
await (await voter.claimFees(feeAddrs, feeTokens, veTokenId)).wait();
// Claim the weekly rebase into your veNFT.
await (await new Contract(REWARDS_DISTRIBUTOR, RD_ABI, signer).claim(veTokenId)).wait();
Resolve a pool's bribe/fee contracts from its gauge — see the VoterV4 reference.
Stake a position for emissions
Liquidity providers earn BARK emissions by staking their position NFT into the pool's
GaugeV2_NFT. The gauge takes custody of the NFT while staked.
const GAUGE_ABI = [
'function deposit(uint256 tokenId)',
'function withdraw(uint256 tokenId)',
'function getReward(address account)',
];
const NPM_ABI = ['function approve(address to, uint256 tokenId)'];
// 1. Resolve the gauge for the pool.
const gaugeAddr = await voter.gauges(poolAddress); // VoterV4.gauges(pool)
// 2. Approve the gauge to take the position NFT, then deposit.
await (await new Contract(NPM, NPM_ABI, signer).approve(gaugeAddr, positionTokenId)).wait();
const gauge = new Contract(gaugeAddr, GAUGE_ABI, signer);
await (await gauge.deposit(positionTokenId)).wait();
// 3. Claim accrued BARK emissions any time.
await (await gauge.getReward(await signer.getAddress())).wait();
// 4. Unstake — returns the NFT to you.
await (await gauge.withdraw(positionTokenId)).wait();
Gotchas
- Approve the right spender. Locking approves BARK to
VotingEscrow; staking approves the position NFT to the specific gauge. - One vote per epoch. Re-voting in the same epoch reverts (
onlyNewEpoch). Usepoke. - Custody. While staked, the gauge holds your position NFT —
withdrawto get it back. - Claim explicitly. Emissions, fees, bribes, and the rebase are all pull-based; nothing is auto-sent to your wallet.