V2 Locker
V2 Locker는 설정된 BDEX V2 Factory가 생성한 ERC20 LP 토큰을 보관합니다. ETERNAL_LOCK은 type(uint256).max입니다. 영구 락은 출금하거나 기간을 단축할 수 없지만 수량 추가, 분할, 이전은 가능합니다.
쓰기 함수
lockLPToken
function lockLPToken(
address _lpToken,
uint256 _amount,
uint256 _unlock_date,
address payable _referral,
bool _fee_in_eth,
address payable _withdrawer,
uint16 _countryCode
) external payable
호출자로부터 LP를 전송하고 현재 수수료를 차감한 뒤 락을 생성합니다.
| 이름 | 타입 | 설명 |
|---|---|---|
_lpToken | address | BDEX V2 페어 토큰. |
_amount | uint256 | 수수료 차감 전 전송되는 LP 수량. |
_unlock_date | uint256 | 초 단위 Unix 타임스탬프 또는 ETERNAL_LOCK. |
_referral | address payable | 자격을 갖춘 추천인 또는 0 주소. |
_fee_in_eth | bool | true면 네이티브 토큰, false면 보조 토큰으로 고정 수수료를 지급합니다. |
_withdrawer | address payable | 초기 락 Owner. |
_countryCode | uint16 | COUNTRY_LIST가 허용하는 코드. |
접근 / payable: 모든 호출자; payable; nonReentrant.
_amount는 0보다 커야 합니다. ETERNAL_LOCK을 제외한 잠금 해제 시각은 미래이며 10_000_000_000보다 작아야 합니다. 국가/지역과 Factory 페어도 유효해야 합니다. 호출자는 LP allowance를 제공하고, 보조 토큰으로 지급할 때는 해당 토큰 allowance도 제공해야 합니다. 허용 목록에 없는 네이티브 수수료 지급자는 계산된 금액과 정확히 같은 수수료를 전송해야 합니다. 컨트랙트는 0 주소 _withdrawer를 허용하므로 클라이언트에서 거부해야 합니다. amount와 initialAmount에는 LP 수수료 차감 후 수량이 저장됩니다. 이어서 NONCE가 증가하고 onNewLock이 발생합니다.
relock
function relock(uint256 _lockID, uint256 _unlock_date) external
락 기간을 연장하거나 영구 락으로 전환합니다.
| 이름 | 타입 | 설명 |
|---|---|---|
_lockID | uint256 | 연장할 락. |
_unlock_date | uint256 | 초 단위 새 시각 또는 ETERNAL_LOCK. |
접근 / payable: 락 Owner만; nonpayable; nonReentrant.
새 값은 현재 unlockDate보다 크고 초 단위 형식 검사를 통과해야 합니다. 컨트랙트는 block.timestamp보다 큰지 별도로 확인하지 않으므로 클라이언트는 _unlock_date > max(current unlockDate, current block time)을 요구해야 합니다. 전체 잔여 수량에서 현재 LP 수수료를 차감하고 onRelock을 발생시킵니다. 최소 수령량 매개변수는 없습니다.
withdraw
function withdraw(uint256 _lockID, uint256 _amount) external
만료된 기간제 락에서 일부 또는 전부를 출금합니다.
| 이름 | 타입 | 설명 |
|---|---|---|
_lockID | uint256 | 원본 락. |
_amount | uint256 | 출금 수량. type(uint256).max는 남은 LP 전부를 뜻합니다. |
접근 / payable: 락 Owner만; nonpayable; nonReentrant.
수량은 0보다 커야 하고 영구 락이 아니어야 하며 unlockDate < block.timestamp를 만족해야 합니다. 전액 출금하면 Owner의 활성 인덱스에서 ID가 제거되지만 amount가 0인 과거 LOCKS 레코드는 유지됩니다. onWithdraw을 발생시킵니다.
incrementLock
function incrementLock(uint256 _lockID, uint256 _amount) external
기존 락에 LP를 추가합니다.
| 이름 | 타입 | 설명 |
|---|---|---|
_lockID | uint256 | 추가 수량을 받을 락. |
_amount | uint256 | 수수료 차감 전 LP 수량. |
접근 / payable: 모든 호출자; nonpayable; nonReentrant.
이 함수는 의도적으로 Owner를 확인하지 않습니다. 추가된 LP는 기존 락 Owner의 소유가 됩니다. 수량은 0보다 크고 승인되어야 합니다. 클라이언트는 LOCKS(_lockID).lpToken != address(0)을 확인해야 합니다. 현재 LP 수수료를 차감한 순수량은 amount에 더해지며 initialAmount에는 더해지지 않습니다. onIncrementLock을 발생시킵니다.
splitLock
function splitLock(uint256 _lockID, uint256 _amount) external payable
락 일부를 같은 Owner와 조건을 가진 새 락으로 옮깁니다.
| 이름 | 타입 | 설명 |
|---|---|---|
_lockID | uint256 | 원본 락. |
_amount | uint256 | 하위 락에 배정할 수량. |
접근 / payable: 락 Owner만; payable; nonReentrant.
수량은 0보다 크고 원본 잔액을 초과할 수 없습니다. 허용 목록 계정도 msg.value가 gFees.ethFee와 같아야 합니다. 하위 락은 lpToken, lockDate, unlockDate, Owner, 국가/지역 코드를 상속하며 amount와 initialAmount는 모두 _amount입니다. onSplitLock과 onNewLock을 발생시킵니다.
transferLockOwnership
function transferLockOwnership(
uint256 _lockID,
address payable _newOwner
) external
락과 활성 인덱스를 즉시 이전합니다.
| 이름 | 타입 | 설명 |
|---|---|---|
_lockID | uint256 | 이전할 락. |
_newOwner | address payable | 새 Owner. |
접근 / payable: 락 Owner만; nonpayable.
새 Owner는 호출자와 달라야 합니다. 수락 호출이 없는 1단계 이전입니다. 컨트랙트가 0 주소를 허용하므로 클라이언트에서 거부해야 합니다. onTransferLockOwnership을 발생시킵니다.
읽기 함수
LOCKS
function LOCKS(uint256 _lockID) external view returns (
address lpToken,
uint256 lockDate,
uint256 amount,
uint256 initialAmount,
uint256 unlockDate,
uint256 lockID,
address owner,
uint16 countryCode
)
락의 public mapping Getter입니다. amount는 남은 LP 수량이고 initialAmount는 생성 시 순수량입니다. 알 수 없는 ID는 0 값을 반환합니다.
TOKEN_LOCKS
function TOKEN_LOCKS(address lpToken, uint256 index)
external view returns (uint256 lockID)
LP 토큰의 index 위치에 있는 과거 락 ID를 반환합니다.
토큰 열거
function getNumLocksForToken(address _lpToken)
external view returns (uint256);
function getNumLockedTokens() external view returns (uint256);
function getLockedTokenAtIndex(uint256 _index)
external view returns (address);
_lpToken은 과거 락 개수를 조회할 LP 토큰입니다. _index는 0부터 시작하는 전역 인덱스이며 범위를 벗어나면 revert합니다. 전역 토큰 집합은 정리되지 않으며 TOKEN_LOCKS는 과거 ID를 포함합니다.
사용자 열거
function getUserNumLockedTokens(address _user)
external view returns (uint256);
function getUserLockedTokenAtIndex(address _user, uint256 _index)
external view returns (address);
function getUserNumLocksForToken(address _user, address _lpToken)
external view returns (uint256);
function getUserLockForTokenAtIndex(
address _user,
address _lpToken,
uint256 _index
) external view returns (TokenLock memory);
각 함수는 활성 토큰 집합 수, 인덱스의 토큰, 특정 토큰의 활성 락 수, 전체 락을 반환합니다. 전액 출금한 락은 제거됩니다. 인덱스는 0부터 시작하며 범위를 벗어나면 revert합니다.
수수료 허용 목록 조회
function getWhitelistedUsersLength() external view returns (uint256);
function getWhitelistedUserAtIndex(uint256 _index)
external view returns (address);
function getUserWhitelistStatus(address _user)
external view returns (bool);
허용 목록 길이, 인덱스의 주소, 포함 상태를 반환합니다. 잘못된 인덱스는 revert합니다.
공개 설정 Getter
function NONCE() external view returns (uint256);
function ETERNAL_LOCK() external view returns (uint256);
function uniswapFactory() external view returns (address);
function COUNTRY_LIST() external view returns (address);
function owner() external view returns (address);
function gFees() external view returns (
uint256 ethFee,
address secondaryFeeToken,
uint256 secondaryTokenFee,
uint256 secondaryTokenDiscount,
uint256 liquidityFee,
uint256 referralPercent,
address referralToken,
uint256 referralHold,
uint256 referralDiscount
);
NONCE는 다음 락 ID이며 활성 락 수가 아닙니다. 비율 필드는 1000을 분모로 사용합니다(10 = 1%). 수수료는 즉시 변경될 수 있으므로 쓰기 트랜잭션 제출 직전에 다시 읽고 시뮬레이션해야 합니다.
이벤트
onNewLock
event onNewLock(uint256 lockID, address lpToken, address owner, uint256 amount, uint256 lockDate, uint256 unlockDate, uint16 countryCode);
lockLPToken과 splitLock이 하위 락을 생성할 때 발생합니다.
| 매개변수 | 설명 |
|---|---|
lockID | 새 락 ID. |
lpToken | 락된 페어 토큰. |
owner | 락 Owner. |
amount | 저장된 순수량. |
lockDate | 생성 타임스탬프. |
unlockDate | 해제 타임스탬프 또는 ETERNAL_LOCK. |
countryCode | 검증된 국가/지역 코드. |
onRelock
event onRelock(uint256 lockID, address lpToken, address owner, uint256 amountRemainingInLock, uint256 liquidityFee, uint256 unlockDate);
락 기간 연장과 수수료 차감 후 발생합니다.
| 매개변수 | 설명 |
|---|---|
lockID | 연장된 락. |
lpToken | 페어 토큰. |
owner | 락 Owner. |
amountRemainingInLock | 순잔액. |
liquidityFee | 차감된 LP 수수료. |
unlockDate | 새 해제 시각. |
onWithdraw
event onWithdraw(uint256 lockID, address lpToken, address owner, uint256 amountRemainingInLock, uint256 amountRemoved);
일부 또는 전액 출금 후 발생합니다.
| 매개변수 | 설명 |
|---|---|
lockID | 출금된 락. |
lpToken | 페어 토큰. |
owner | Owner 겸 수령인. |
amountRemainingInLock | 남은 LP 수량. |
amountRemoved | 전송된 LP 수량. |
onIncrementLock
event onIncrementLock(uint256 lockID, address lpToken, address owner, address payer, uint256 amountRemainingInLock, uint256 amountAdded, uint256 liquidityFee);
락에 LP를 추가할 때 발생합니다.
| 매개변수 | 설명 |
|---|---|
lockID | 수량이 증가한 락. |
lpToken | 페어 토큰. |
owner | 수익자 Owner. |
payer | LP 제공자. |
amountRemainingInLock | 새 총 잔액. |
amountAdded | 추가된 순 LP 수량. |
liquidityFee | 차감된 LP 수수료. |
onSplitLock
event onSplitLock(uint256 lockID, address lpToken, address owner, uint256 amountRemainingInLock, uint256 amountRemoved);
하위 락 생성 시 원본 락에 대해 발생합니다.
| 매개변수 | 설명 |
|---|---|
lockID | 원본 락. |
lpToken | 페어 토큰. |
owner | 두 락의 Owner. |
amountRemainingInLock | 분할 후 원본 락 수량. |
amountRemoved | 하위 락 수량. |
onTransferLockOwnership
event onTransferLockOwnership(uint256 lockID, address lpToken, address oldOwner, address newOwner);
1단계 소유권 이전이 완료될 때 발생합니다.
| 매개변수 | 설명 |
|---|---|
lockID | 이전된 락. |
lpToken | 페어 토큰. |
oldOwner | 이전 Owner. |
newOwner | 새 Owner. |
오류
다음은 V2 Locker 사용자 흐름의 주요 revert입니다. 문자열을 정확히 비교해야 하며 컨트랙트는 ZERO WITHDRAWL 철자를 사용합니다.
| Error / Revert | 관련 함수 | 조건 |
|---|---|---|
TIMESTAMP INVALID | lockLPToken, relock | 일반 해제 시각이 10_000_000_000 이상이며 보통 밀리초 입력입니다. |
DATE PASSED | lockLPToken | 일반 해제 시각이 현재 블록 시각보다 늦지 않습니다. |
INSUFFICIENT | lockLPToken | _amount == 0. |
COUNTRY | lockLPToken | _countryCode가 COUNTRY_LIST 검증을 통과하지 못합니다. |
NOT UNIV2 | lockLPToken | _lpToken이 설정된 BDEX V2 Factory 페어가 아닙니다. |
INADEQUATE BALANCE | lockLPToken | 추천인이 referralHold 요건을 충족하지 못합니다. |
FEE NOT MET | lockLPToken, splitLock | msg.value가 필요한 네이티브 수수료와 정확히 같지 않습니다. |
NOT OWNER | relock, withdraw, splitLock, transferLockOwnership | 호출자가 락 Owner가 아닙니다. |
UNLOCK BEFORE | relock | 새 시각이 현재 unlockDate보다 엄격히 크지 않습니다. |
ZERO WITHDRAWL | withdraw | _amount == 0 또는 계산된 출금량이 0입니다. |
ETERNAL_LOCK | withdraw | 영구 락 출금을 시도합니다. |
NOT YET | withdraw | 기간제 락이 아직 만료되지 않았습니다. |
ZERO AMOUNT | incrementLock, splitLock | 추가 또는 분할 수량이 0입니다. |
OWNER | transferLockOwnership | _newOwner가 호출자와 같습니다. |
TransferHelper: APPROVE_FAILED | 토큰 승인 | approve가 실패하거나 false를 반환합니다. |
TransferHelper: TRANSFER_FAILED | 토큰 전송 | transfer가 실패하거나 false를 반환합니다. |
TransferHelper: TRANSFER_FROM_FAILED | lockLPToken, incrementLock | 잔액/allowance 부족 또는 transferFrom 실패. |
Panic(0x11) | withdraw, splitLock 등 수량 연산 | 요청량이 잔액을 초과하거나 수수료 계산에서 underflow/overflow가 발생합니다. |
관리 함수와 재진입 방지는 상속된 다음 오류도 반환할 수 있습니다.
| Error / Revert | 조건 |
|---|---|
Ownable: caller is not the owner | Owner가 아닌 계정이 관리 함수를 호출합니다. |
ReentrancyGuard: reentrant call | nonReentrant 함수에 재진입합니다. |
기반 Factory, LP 토큰, 추천 토큰, 수수료 토큰의 revert는 변경 없이 전달됩니다. 프런트엔드는 원본 revert data를 유지해야 합니다.