> For the complete documentation index, see [llms.txt](https://docs.ape.bond/apebond/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ape.bond/apebond/where-dev/permalock-positions-technical-specification.md).

# Permalock Positions Technical Specification

ApeBond locking positions are managed through the veABOND contract. Users receive NFT-based lock positions that can be regular, rolling, or permanent (Permalock). Rewards are distributed separately through the Reward Distributor contract.

### Contracts

veABOND\
`0xDF1dD618f3B564765e3ffc9F229637942ef601B2`

Reward Distributor\
`0x49135331B7A7dde8601Deea11dA4939Afac033c5`

### Retrieving User Lock Positions

To fetch all lock positions of a user:

1. On the veABOND contract, call `getUserTokenIds` passing the user’s address.\
   This returns all NFT token IDs owned by that user.
2. For each returned token ID, call `lockDetails` on the veABOND contract.

The `lockDetails` response contains all relevant information about the position, including `lockType`, `amount`, timestamps and rolling duration.

### Lock Types

The `lockType` field inside `lockDetails` determines the type of position:

If `lockType === 0`\
This is a regular position. It has a fixed unlock timestamp.

If `lockType === 1`\
This is a rolling position. It has a fixed lock duration, but this duration is renewed every week. There is no fixed unlock timestamp until the user stops rolling the position and converts it into a regular lock.

If `lockType === 2`\
This is a Permalock position. Tokens are locked permanently and will never unlock.

### Locked ABOND Amount Calculation

The `amount` value returned by `lockDetails` must be interpreted depending on the lock type.

For non-permalock positions (`lockType === 0` or `lockType === 1`), the locked ABOND amount is:

`lockDetails.amount`

For Permalock positions (`lockType === 2`), the effective locked ABOND amount is:

`lockDetails.amount / 2`

This division by two is required due to the internal accounting logic of the Permalock mechanism. Indexers and frontends must apply this adjustment to correctly reflect the user’s locked balance.

### Unlock Date Calculation

For regular positions (`lockType === 0`), the unlock timestamp is:

`lockDetails.endTime`\
This value is expressed in seconds.

For rolling positions (`lockType === 1`), there is no fixed unlock timestamp.\
To determine the locked duration, use:

`lockDetails.rollingDuration`

This represents the amount of locked time in seconds. The duration does not decrease while the position is rolling. When the user stops rolling, the position becomes a regular lock and receives a fixed `endTime`.

For Permalock positions (`lockType === 2`), the position never unlocks.\
There is no unlock timestamp. Frontends should display it as a permanent lock, for example with a “Permalock” label.

### Reward Calculation

Rewards are distributed through the Reward Distributor contract and are linked to the user’s address, not to individual NFT positions.

To calculate unclaimed rewards:

On the Reward Distributor contract, call:

`earned(userAddress, rewardTokenAddress)`

For USDT rewards, use:

`0x55d398326f99059fF775485246999027B3197955`

The `earned` method returns the amount of USDT currently unclaimed by the user.

Since rewards are address-based and not NFT-based, indexers should aggregate rewards per user address rather than per position.
