License.sol
Overview
License.sol defines the LicenseContract smart contract, which manages licensing functionality within a system involving blockkeeper wallets and elections. This contract handles license ownership, wallet association, reputation, license lifecycle (creation, update, and destruction), and token balance operations. It interacts closely with AckiNackiBlockKeeperNodeWallet wallets and a root election address, ensuring controlled access and state consistency via guarded functions and balance checks.
Contract: LicenseContract
Purpose
The LicenseContract manages an individual license's lifecycle and state, including ownership transfer, wallet linkage, reputation tracking, and token management. It provides mechanisms for adding/removing blockkeeper wallets, accepting or rejecting licenses, as well as withdrawing and adding token balances.
State Variables
Variable | Type | Description |
|---|---|---|
|
| Contract version identifier |
|
| Unique license identifier (immutable). |
|
| Root address reference (immutable). |
|
| Public key of the license owner (optional). |
|
| Address of the license owner (optional). |
|
| Address of the root election contract. |
|
| Address of the associated BlockKeeper wallet (optional). |
|
| Reputation timestamp or counter for the license. |
|
| Flag indicating if the license is privileged. |
|
| Mapping for storing code cells indexed by code type. |
|
| Timestamp for the license start. |
|
| Flag indicating readiness state of the license. |
|
| Last interaction block sequence number. |
|
| Last license-specific interaction block sequence number. |
Constructor
constructor (
uint256 pubkey,
TvmCell walletCode,
address rootElection,
bool isPrivileged
) senderIs(_root) accept
Parameters:
pubkey: Owner's public key to initialize the owner.walletCode: The code for the blockkeeper wallet contract.rootElection: Address of the root election contract.isPrivileged: Initial privilege status for the license.
Functionality:
Initializes the owner public key.
Stores the wallet contract code under a predefined key.
Sets the root election address.
Initializes license touch tracking and privilege status.
Requires that the caller is the root address (
senderIs(_root)).
Methods
setOwnerAddress
function setOwnerAddress(address owner) public onlyOwnerWalletOpt(_owner_address, _owner_pubkey) accept
Parameters:
owner: New owner address.
Returns: None.
Description:
Transfers ownership to the specified address.
Resets the owner public key to null.
Ensures sufficient balance via
ensureBalance().Enforces license cooldown via block sequence number checks (
LICENSE_TOUCH).
Usage Example:
licenseContract.setOwnerAddress(newOwner);
setOwnerPubkey
function setOwnerPubkey(uint256 pubkey) public onlyOwnerWalletOpt(_owner_address, _owner_pubkey) accept
Parameters:
pubkey: New owner public key.
Returns: None.
Description:
Transfers ownership to the specified public key.
Resets the owner address to null.
Enforces cooldown and ensures balance similarly to
setOwnerAddress.
setLockToStake
function setLockToStake(bool lock) public onlyOwnerWalletOpt(_owner_address, _owner_pubkey) accept
Parameters:
lock: Boolean to lock or unlock stake.
Returns: None.
Description:
Requires association with a blockkeeper wallet.
Calls the linked wallet's
setLockToStakemethod with the license number and lock flag.Uses 0.1 vmshell of value for the internal call.
Enforces cooldown and balance check.
removeBKWallet
function removeBKWallet() public onlyOwnerWalletOpt(_owner_address, _owner_pubkey) accept
Parameters: None.
Returns: None.
Description:
Removes the blockkeeper wallet association.
Calls the wallet's
removeLicensemethod.Enforces cooldown and balance check.
deleteWallet
function deleteWallet(uint128 reputationTime, bool isPrivileged, uint64 last_touch) public
Parameters:
reputationTime: Updated reputation time.isPrivileged: Updated privilege flag.last_touch: Last interaction timestamp.
Returns: None.
Description:
Called by the linked blockkeeper wallet to delete itself.
Updates local reputation, privilege, and last touch state.
Nullifies the blockkeeper wallet reference.
Accepts the message and ensures balance.
destroyLicense
function destroyLicense() public
Parameters: None.
Returns: None.
Description:
Called by the linked blockkeeper wallet.
Destroys the license contract, sending remaining balance to the root election address.
Requires wallet existence and correct sender.
Accepts the message and ensures balance.
addBKWallet
function addBKWallet(uint256 pubkey) public onlyOwnerWalletOpt(_owner_address, _owner_pubkey) accept
Parameters:
pubkey: Public key of the blockkeeper wallet to add.
Returns: None.
Description:
Adds a new blockkeeper wallet for the license.
Checks that no wallet exists currently.
Computes wallet address using
BlockKeeperLib.calculateBlockKeeperWalletAddress.Calls the wallet's
addLicensemethod, passing license number, reputation time, and privilege status.Uses different timestamps if license is ready or not.
Enforces cooldown and balance checks.
notAcceptLicense
function notAcceptLicense(uint256 pubkey) public view senderIs(calculatedWalletAddress) accept
Parameters:
pubkey: Public key of the wallet.
Returns: None.
Description:
Confirms non-acceptance of license by the wallet.
Ensures balance.
Requires caller to be the calculated wallet address.
acceptLicense
function acceptLicense(uint256 pubkey, uint64 last_touch) public senderIs(calculatedWalletAddress) accept
Parameters:
pubkey: Public key of the wallet.last_touch: Timestamp of acceptance.
Returns: None.
Description:
Marks license as ready if not already.
Updates license start timestamp.
Stores wallet address.
Adds balance to the wallet if any tokens exist.
Checks caller identity against computed wallet address.
toWithdrawToken
function toWithdrawToken(uint128 value) public onlyOwnerWalletOpt(_owner_address, _owner_pubkey) accept
Parameters:
value: Amount of tokens to withdraw.
Returns: None.
Description:
Requests token withdrawal from the linked blockkeeper wallet.
Requires wallet existence.
Enforces cooldown and balance checks.
withdrawToken
function withdrawToken(address to, uint128 value) public onlyOwnerWalletOpt(_owner_address, _owner_pubkey) accept
Parameters:
to: Recipient address.value: Amount of tokens.
Returns: None.
Description:
Direct withdrawal of tokens to an address if no blockkeeper wallet exists.
Checks for sufficient balance and cooldown.
Resets privilege flag to false.
Transfers tokens with 0.1 vmshell.
toAddBalance
function toAddBalance(uint128 value) public onlyOwnerWalletOpt(_owner_address, _owner_pubkey) accept
Parameters:
value: Token amount to add.
Returns: None.
Description:
Adds token balance to the linked blockkeeper wallet.
Requires wallet existence and sufficient balance.
Enforces cooldown and balance checks.
receive()
Description:
Fallback/receive function to accept incoming transfers.
Getters
getDetails
function getDetails() external view returns (
uint256 license_number,
optional(address) bkwallet,
optional(uint256) owner_pubkey,
optional(address) owner_address,
uint128 reputationTime,
uint64 license_start
)
Returns:
License number, blockkeeper wallet address, owner public key, owner address, reputation time, and license start timestamp.
getBK
function getBK() external view returns (optional(address) bkwallet)
Returns: Blockkeeper wallet address (optional).
getOwner
function getOwner() external view returns (optional(uint256) owner_pubkey, optional(address) owner_address)
Returns: Owner public key and owner address (optional).
getVersion
function getVersion() external pure returns(string, string)
Returns: Version string and contract name
"LicenseBlockKeeper".
Important Implementation Details
Access Control: Uses modifiers such as
onlyOwnerWalletOptandsenderIsto restrict function calls based on ownership or caller address.Balance Assurance: The internal
ensureBalance()method mints a fixed amount of currency (FEE_DEPLOY_LICENSE) if the contract balance is insufficient, ensuring sufficient funds for contract operations.Cooldown Enforcement: Many state-changing functions enforce a cooldown period (
LICENSE_TOUCH) to prevent rapid repeated calls, using the block sequence number (block.seqno) as a time reference.Wallet Address Calculation: Uses
BlockKeeperLib.calculateBlockKeeperWalletAddressto derive the expected address of a blockkeeper wallet based on the wallet code, root election address, and public key.Currency Handling: Token operations use the
currenciesmapping of the contract's own address to track balances and transfer tokens.License Lifecycle: Tracks readiness and start timestamps, linking license state transitions with wallet acceptance and interaction timestamps.
Use of Optional Types: Owner keys and addresses, as well as wallet addresses, are stored as optional values to represent uninitialized or cleared states.
Interactions with Other Contracts
AckiNackiBlockKeeperNodeWallet:
The license contract interacts extensively with this wallet contract, calling methods such as
addLicense,removeLicense,setLockToStake,withdrawToken, andaddBalance.Wallet address is dynamically calculated using
BlockKeeperLiband stored optionally.Wallets can call back
deleteWalletanddestroyLicenseon the license contract.
BlockKeeperLib:
Provides utility functions for calculating wallet addresses.
Used to verify sender identity and enforce permissions.
Root Election Contract:
Receives funds on license destruction.
The root election address is stored and used as a fallback owner/state controller.
Modifiers:
Custom modifiers imported from
modifiers.solenforce security and validation rules.
Visual Diagram
classDiagram
class LicenseContract {
-string version
-uint256 _license_number
-address _root
-optional(uint256) _owner_pubkey
-optional(address) _owner_address
-address _rootElection
-optional(address) _bkwallet
-uint128 _reputationTime
-bool _isPrivileged
-mapping(uint8 => TvmCell) _code
-uint64 _license_start
-bool is_ready
-uint64 _last_touch
-uint64 _licenseLastTouch
+constructor(pubkey, walletCode, rootElection, isPrivileged)
+setOwnerAddress(owner)
+setOwnerPubkey(pubkey)
+setLockToStake(lock)
+removeBKWallet()
+deleteWallet(reputationTime, isPrivileged, last_touch)
+destroyLicense()
+addBKWallet(pubkey)
+notAcceptLicense(pubkey)
+acceptLicense(pubkey, last_touch)
+toWithdrawToken(value)
+withdrawToken(to, value)
+toAddBalance(value)
+getDetails()
+getBK()
+getOwner()
+getVersion()
}
LicenseContract --> "1" AckiNackiBlockKeeperNodeWallet : interacts with
LicenseContract --> "1" BlockKeeperLib : uses for address calculation
LicenseContract --> "1" Modifiers : applies access controls
This diagram shows the LicenseContract class, its attributes, and methods, as well as its relationships with AckiNackiBlockKeeperNodeWallet, BlockKeeperLib, and Modifiers. The arrows indicate dependencies and interactions.
Notes on Usage
Owners can transfer ownership between public keys and addresses but only one can be set at a time.
Blockkeeper wallets must be added explicitly before accepting licenses.
License state updates are guarded to prevent rapid changes.
Token management functions require an associated blockkeeper wallet for deposits and withdrawals, unless withdrawing directly without a wallet.
The contract's balance is critical for operation and is replenished automatically when low.
For more about smart contract access control and token handling, see Modifiers and Token Management. For wallet address calculations, refer to BlockKeeperLib.