Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The primary wallet responsibility is taking care of Bitcoins deposited by tBTC users. Whenever a wallet needs to move some Bitcoins due to a protocol action (e.g. deposit sweep or redemption), it must assemble an appropriate Bitcoin transaction and sign each transaction's input using the tECDSA signing algorithm. During the tECDSA signing, randomly selected 51-of-100 wallet signers must collaborate to produce a proper signature.
A single tECDSA signing attempt consists of several steps. Each step has a maximum duration expressed in the specific number of host chain (e.g. Ethereum) blocks:
Signers readiness announcement phase which takes exactly 6 blocks
Signature production & advertisement phase which takes up to 30 blocks
Cooldown period that takes exactly 5 blocks
That means a single signing attempt can take up to 41 blocks (~8 minutes on Ethereum, assuming 12 seconds as the average block time). If the signature is not produced during that time, wallet signers give up the signing attempt and retry.
A wallet that is asked to sign the given message (e.g. Bitcoin transaction input) does not limit itself to a single tECDSA signing attempt. Due to the distributed nature of the signing algorithm, a single signing attempt may fail due to, for example, some unexpected network problems affecting inter-signer communication. If the first signing attempt fails, another set of randomly selected 51 wallet signers retry signing during the next attempt. Subsequent signing attempts are scheduled on fixed intervals, based on the block the first attempt started at, and the known maximum duration of a single attempt (41 blocks). For example, if the first attempt started at the block B, subsequent attempts will be scheduled as follows:
Attempt 2 -> B + 41
Attempt 3 -> B + 82
Attempt N -> B + (N-1) * 41
The wallet always executes 5 signing attempts at maximum. Such a count of maximum attempts is an acceptable trade-off between a reasonable signing timeout and a sufficient tolerance for misbehaving wallet signers. Executing 5 signing attempts allows trying 5 different 51-signer subsets. This is enough to produce a signature even for an unlikely scenario of 2 misbehaving wallet signers. In that case, 51 signers must be selected out of the honest 98 signers. That means the probability of selecting a successful subset is:
which means 5 selections are required in the worst case.
Combining the 5 signing attempts at maximum with up to 41 blocks per single attempt means the wallet will try to sign the given message for 5*41 = 205 blocks (~40 minutes on Ethereum, assuming 12 seconds as the average block time). If the signature is not produced during that time, wallet signers give up ultimately.
Wallets have the ability to sign multiple messages (e.g. multiple inputs of a single Bitcoin transaction) in a serial manner, one message after another. In such a case, the whole signing process is successful only if all messages in the batch obtained their signatures.
As mentioned in the previous section, the maximum allowed time for signing a single message is 205 blocks (~40 minutes on Ethereum). That means the maximum time to sign a batch of N messages is N*205 blocks. During that time, the wallet cannot perform any other work as signing is computationally heavy. This factor must be taken into account while building wallet actions that leverage signing.
The tBTC protocol defines a finite set of wallet actions:
Heartbeat
Deposit sweep
Redemption
Moving funds
Moved funds sweep
Each action involves wallet signing under the hood. The time necessary to complete the given action depends on how many signatures must be produced during execution. Knowing the worst-case time necessary to produce a single signature (205 blocks) and the number of signatures that may be required by the given action, we can set the right time boundaries for specific actions. This information is crucial for proper wallet coordination.
Let's use the Deposit sweep action to show how signing affects wallet actions. This action is initiated by a coordinator that submits a deposit sweep proposal through the WalletCoordinator
chain contract. An expected outcome of that action is a Bitcoin transaction with multiple inputs (swept deposits) and one output, submitted to the Bitcoin chain. That means the action's execution time strongly depends on the number of deposits suggested as part of the given sweep proposal. The WalletCoordinator
contract has some governable parameters that impact the Deposit sweep action:
depositSweepMaxSize
that sets the maximum number of deposits within a single sweep proposal
depositSweepProposalValidity
which determines the proposal's validity time. This is an exclusive time the wallet obtains to execute the given sweep and no other actions can be taken meanwhile
In other words, the wallet can sweep up to depositSweepMaxSize
deposits and has depositSweepProposalValidity
time to do so.
Signing is the most important and complex step of the Deposit sweep action and the reference client implementation sets the signing timeout to be depositSweepProposalValidity - 1 hour
for all inputs of the sweep transaction. Producing a signature for a single deposit input may take up to 205 blocks (5 attempts underneath). This is ~40 minutes assuming Ethereum's average block time of 12 seconds. Having that in mind, the aforementioned WalletCoordinator
governable parameters must be chosen with care as they have a strong impact on signing execution:
If depositSweepMaxSize = 5
and depositSweepProposalValidity = 4 hours
, the wallet will try to sign 5 inputs in 3 hours which gives ~36 minutes per input. As 5 signing attempts take ~40 minutes, this configuration will allow for 4 attempts per input
If depositSweepMaxSize = 10
and depositSweepProposalValidity = 4 hours
, the wallet will try to sign 10 inputs in 3 hours which gives ~18 minutes per input. As 5 signing attempts take ~40 minutes, this configuration will allow for 2 attempts per input
If depositSweepMaxSize = 20
and depositSweepProposalValidity = 4 hours
, the wallet will try to sign 20 inputs in 3 hours which gives ~9 minutes per input. As 5 signing attempts take ~40 minutes, this configuration will allow for 1 attempt per input
A Decentralized, Permissionless Bitcoin Bridge to DeFi
Existing solutions that bridge Bitcoin to Ethereum require users to send their Bitcoin to an intermediary, in exchange for an ERC-20 token that represents the original asset. This centralized model requires you to trust a third party and is susceptible to censorship, threatening the premise of Bitcoin as sovereign, secure, permissionless digital asset.
The second generation of tBTC is a truly decentralized (and scalable) bridge between Bitcoin and Ethereum. It provides Bitcoin holders secure and open access to the broader DeFi ecosystem. tBTC v2 allows you to unlock your Bitcoin’s value to borrow and lend, mint stablecoins, provide liquidity, and much more.
Instead of centralized intermediaries, tBTC uses a randomly selected group of operators running nodes on the Threshold Network to secure deposited Bitcoin through threshold cryptography. That means tBTC requires a threshold majority agreement before operators perform any action with your Bitcoin. By rotating the selection of operators weekly, tBTC protects against any individual or group of operators colluding to fraudulently seize the underlying deposits. By relying on an honest-majority-assumption, we can calculate the likelihood any wallet comprised of a quorum of dishonest operators (for a deeper discussion of the probability calculations, see here).
Unlike other solutions on the market, users of tBTC trust math, not hardware or people.
A Bitcoin-backed Stablecoin
Threshold USD (thUSD) is a stablecoin soft-pegged against USD and backed by ETH and tBTC as collateral, with a minimum collateral ratio of 110%.
With either BTC or ETH as your collateral, you'll be able to borrow thUSD at very low cost.
Threshold USD is a modified fork of Liquity Protocol built to be self-sustained through a PCV ("Protocol Controlled Value"). There is no equivalent of LQTY token in Threshold USD. Instead all profits accrue into the PCV. Since there is no token, Bootstrapping is completed through an Initial Protocol Loan.
The result of protocol owning its own liquidity ("PCV") is a more predictable trajectory and sustainability long-term. The stability pool is funded by the PCV instead of user deposits. Thanks to this, no funds are wasted on rewards to passive LQTY stakers (rented liquidity) and those funds can instead by re-injected into the stability pool. As the protocol grows and accrue fees, the stability pool will be consistently topped up.
Liquity is limited to ETH as the only type of collateral. Threshold USD expand to support BTC as collateral for loans through the decentralized BTC wrapper tBTC. In the future other types of collateral may be considered for on-boarding if they are sufficiently decentralized.
Each collateral will be deployed with its own contracts and each new collateral will require a DAO vote with a lengthy time delay before deployment. By having each collateral be its own contract any collateral can easily be deprecated by disallowing minting on that specific contract.
All contracts related to thUSD can be found here.
Follow along with this guide and leverage your Bitcoin by minting tBTC.
Here are some things you will need before you start the minting process:
If you don't already have one, you'll need to set up a Bitcoin wallet. A solid option to use is Green Wallet. You can download it here:
After you've created your wallet, select Bitcoin
as your network.
If you have questions about terminology, you can toggle over to the How it Works page in the dapp to learn more. You can also dive into documentation on wallet generation and bridge permissionlessness in the docs.
Connect your preferred Ethereum wallet to the tBTC dapp by selecting Connect Wallet.
Navigate to the tBTC Bridge page. This is represented in the lefthand navigation by the tBTC icon.
Enter a Bitcoin wallet address as the BTC Recovery Address. Click Generate Deposit Address to create your unique deposit address.
Make sure to download the JSON file by clicking Download. The JSON file contains a wallet public key, a refund public key, and a refund lock time. You need to keep this JSON file until you receive your tBTC tokens.
In your Bitcoin wallet, take a picture of the QR code of the generated Deposit Address in the tBTC dapp. It will look something like this:
Send your BTC deposit to this Deposit Address from your Bitcoin wallet. The minimum deposit is 0.01 BTC.
Return to the tBTC dapp. After your funds are sent, the screen will automatically advance to Step 3.
To initiate minting, click on Confirm deposit & mint.
Sign the transaction in your Ethereum wallet.
Your mint is now in progress! You don't need to remain in the dapp to wait for your tBTC tokens to mint. You can see the status of your mint in the dapp. The first stage requires 1 confirmation on the Bitcoin Network before advancing to the next step.
Now you will see the following while waiting for a Minter to assess the minting initialization:
Next, you will see the following while waiting for a Guardian to examine the minting request:
Success! You can see all transaction links on this screen.
Make sure to add the tBTC token address to your Ethereum wallet by clicking token address.
Wallets are created periodically based on governance. updateWalletParameters
changes the time between wallets and walletParameters
reads it. The time between new wallets is held in walletCreationPeriod
in number of seconds, so the current value of 1209600
represents 14 days.
In order for the wallet to move funds, it produces signatures using a Threshold Elliptic Curve Digital Signature Algorithm, requiring 51-of-100 Signers to cooperate.
The 100 signers on each wallet are chosen with our Sortition Pool, and the randomness is provided by the Random Beacon.
The probability that a Staker is chosen to be a Signer is equal to their percentage of the total TBTC Stake. Each Signer is chosen independently. The same Staker can be a signer on the same wallet multiple times. The same Staker can be a Signer on multiple wallets simultaneously.
For simplicity, say there are only three Stakers: Alice, Bob, and Carol. Alice has 250M T, Bob has 400M T, and Carol has 350M T staked, so they own 25%, 40% and 35% of the stake respectively. That means, Alice has a 25% chance to be a Signer, Bob has a 40% chance, and Carol has a 35% chance. Each Signer is selected independently.
The Sortition Pool is more complex (because of heavy gas optimization), but reasoning about it could look like this:
For each Signer, we're going to generate a random number between 1 and 100. Alice is the Signer if the number is in [1, 25]. Bob is the Signer if the number is in [26, 65]. Carol is the Signer if the number is in [66, 100]. For example, if our first random number is 33, our first Signer would be Bob. We can generate 100 random numbers: (75, 51, 13, 48, 36, 62, 46, 65, 97, 67...)
, and then use that to determine Signers: (Carol, Bob, Alice, Bob, Bob, Bob, Bob, Bob, Carol, Carol...)
.
This example illustrates a few properties mentioned earlier:
Each Signer is selected independently. Whether or not Carol is the first signer has no influence on Carol being the second Signer.
The chance that you become a particular Signer is equal to your share of the Stake.
If Carol has a 35% chance of being a particular Signer, what are chances that Carol has at least 51 of the 100 seats (and could control the wallet by herself)?
The number of Signers that Carol controls on a wallet is modeled by the Binomial Distribution. From wikipedia:
A Binomial distribution with parameters
n
andp
is the discrete probability distribution of the number of successes in a sequence ofn
independent experiments, each asking a yes–no question, and each with its own Boolean-valued outcome: success (with probabilityp
) or failure (with probability1−p
).
This is exactly our situation! From Carol's perspective, there will be n=100
independent experiments, each asking a yes-no question (does this Signer belong to Carol), each with a 35% probability.
It's the last figure: "Cumulative probability: P(X>51)" that's relevant. That says there is a ~0.074% chance that Carol would have a controlling Share of any particular wallet.
The next important question is "The probability that Carol controls a Wallet is low, but it only needs to happen once for things to be bad. What is the probability that she controls any wallet in the next 2 years?"
A wallet is generated every 14 days, so over the next 2 years, the system would generate ~52 wallets. Each wallet has a 1 - 0.00074 = .99926
or 99.926% chance of not being controlled by Carol. That means we can exponentiate:
Carol would have a ~3.8% chance of getting control of a wallet in 2 years. That's with her owning 35% of the total Stake! Alice has a much lower chance. She has a 0.0002131%
chance of controlling a wallet, which means that over the course of 52 wallets, she has a 0.02131%
chance of controlling any wallet in 2 years.
As of writing, the *largest* Staker controls ~8.83% of the Stake.
The only thing that a Staker accomplishes by splitting up their Stake into multiple identities is making the system appear to be more diverse.
For example, say that Alice split up her Stake equally into 5 accounts: Alice1, Alice2, Alice3, Alice4, and Alice5. Now, rather than Alice having a 25% chance to be a Signer, each account has a 5% chance which collectively add up to 25%.
To use the example from earlier: Alice has 250M T, Bob has 400M T, and Carol has 350M T staked. Alice has her T split into 50M for each identity. Alice1 would own 50M/1000M = 5%.
Keeping with the simplification of assigning numbers from 1 to 100 to identities, Alice1 would get [1, 5], Alice2 gets [6, 10], Alice3 gets [11, 15], Alice4 gets [16, 20], Alice5 gets [21, 25], Bob gets [26, 65], Carol gets [66, 100]. If we use the same random numbers as before, (75, 51, 13, 48, 36, 62, 46, 65, 97, 67...)
, then we make the assignments as (Carol, Bob, Alice3, Bob, Bob, Bob, Bob, Bob, Carol, Carol...)
. Nothing has effectively changed!
In order to effectively ship the product, we launched with a permissioned set of Signers, as well as permissioned sets of Guardians and Minters. This document will explain the ideas behind those changes and what we're doing about it going forward.
The permissioned honest-majority signer set will remain in place until custody is upgraded to a 1-of-N trust assumption using BitVM2 (or an equivalent design).
To select the 100 signers for a wallet, tBTC selects from the permissioned list of Beta Stakers. This decision was made for several reasons:
The point about GG18 is crucial. Without being able to identify misbehaving signers, a small, sophisticated, malicious minority can make it difficult to sign Bitcoin transactions in a timely manner. If we were able to identify the misbehaving signers, we could exclude them directly from the signing process.
Although alternative algorithms exist for identifying misbehaving signers, they are not yet viable for production use for one or more of the following reasons:
They are not open source.
They exist only as whitepapers.
Recent advances in Bitcoin bridge design, specifically BitVM2, suggest the possibility of improving custody from an honest-majority assumption to a 1-of-N trust assumption. Threshold Network is closely monitoring the development of this design and various implementations, with the medium-term intent of upgrading tBTC's underlying custody mechanics once the technology is sufficiently mature.
Guardians and Minters are a permissioned set of high-trust public operators with their reputations on the line.
Guardians are responsible for validating mint and redemption requests, and have the ability to veto malicious or fraudulent requests. If we were to make these lists permissionless, a malicious Minter could flood the system with fake minting requests for the Guardians to deal with, or a malicious Guardian could veto every proposed mint to halt growth.
Minters serve a convenience function by enabling "fast minting." Importantly, they do not have the ability to gatekeep mint requests; any deposit that all Minters refuse to approve or that a Guardian refuses to accept can still be minted every eight hours by the signers. This ensures that the system remains resilient and able to handle situations in which a malicious actor attempts to disrupt the minting process.
Threshold Network powers tBTC, the Bitcoin standard for DeFi—a trust-minimized way to bring BTC liquidity into the crypto ecosystem while always maintaining a direct settlement path back to native Bitcoin.
Unlike other BTC derivatives or wrapped tokens, tBTC is designed to be as close to Bitcoin as possible while enabling seamless participation in DeFi. No complex staking mechanics, no dependency on a single entity—just pure BTC liquidity that always settles back to Bitcoin.
Learn the fundamentals of the Threshold Network to get a deeper understanding of our main features:
A backstop for assets secured by the tBTC protocol
Over time, it became clear that this backstop model was sub-optimal given the relationship between tBTC and T - in the case of a BTC collateral loss event, T's value would also decline, greatly reducing its effectiveness as an insurance backstop. Consequently, the explicit Threshold Coverage Pool has been sunset with the approval of TIP-064.
Under the newly implemented "implicit coverage pool" model, tBTC is backed by the full faith and credit of Threshold DAO - by its treasury assets, which currently include T, ETH, wBTC, tBTC, stablecoins, CVX, veCRV, and associated LP tokens, etc.
Sweeping is an accounting optimization for tracking bitcoin deposits in tBTC contracts. It involves periodically consolidating recent bitcoin deposits into a single Unspent Transaction Output (UTXO) for a more optimal commitment cadence to Ethereum. This process simplifies tracking associated public keys and refund time locks while also helping prevent supply peg disruption. Typically, Sweeping runs every 8 hours depending on the volume and size of deposits.
If we wanted to be able to redeem bitcoin deposits, we would need to track which deposits are associated to which public keys the same way that wallet software does; this is a headache especially from a bitcoin mining fee perspective.
As a result of this, we give ourselves the same time limit for collecting the deposit. If we don't move the funds by that time, a user could deposit 5 BTC, receive 5 TBTC, and then 9 months later reclaim their original 5 BTC without redeeming the 5 BTC. This would break the TBTC supply peg.
The result is that all of the scattered deposits are "swept" into a single "pile" represented by one UTXO that we can commit to on ethereum.
That transaction created a UTXO worth 1.51614471 BTC. The next transaction
Used the old UTXO (the first input) as well as all of the recent deposits to create a new UTXO (the output on the right) worth 15.42475511 BTC. The final transaction
Follows the same pattern. It uses the old UTXO (the first input) as well as the recent deposits to create a new UTXO worth 59.52818486 BTC.
Background of Threshold USD, Main Parameters and Key Characteristics
An immediate question that comes up is providing utility for the bridged tBTC for DeFi applications. Threshold USD provides an alternative utility to tBTC by allowing to mint thUSD, which then can be used for multiple purposes in a wider ecosystem.
Threshold USD is a decentralized borrowing protocol that allows you to draw loans using tBTC and ETH as collateral. Loans are paid out in thUSD (a USD pegged stablecoin) and need to maintain a minimum collateral ratio of 110%.
Liquity is totally governance free and immutable; although that is a tremendous strength for a DeFi Protocol as it makes it completely censorship resistant, it also exposes the protocol to existential oracle risk and limits its ability to scale and respond to market dynamics.
With that in mind some flexibilitiy is embeded into Threshold USD. It has a few parameters that can be changed through governance:
Collateral Type: in addition to tBTC other collateral types may be added (ETH will be an additional collateral to tBTC, as it is the most decentralized and abundant asset in Ethereum) and also removed by revoking mint and burn capabilities.
Price Feed Contract: Oracles are critical for the health of the protocol (defining liquidations) and may need to be updated due to poor performance of existing oracles
PCV Contract: Withdraw from BAMM to PCV, pay the debt and withdraw funds from PCV after repaying all the debt.
BAMM Contract: Dao has veto capability for change submission to the "A" parameter and B.Protocol fees.
Stable-value assets are an essential building block for Ethereum applications and have grown to represent tens of billions of dollars in value.
However, the vast majority of this value is in the form of fiat-collateralized stablecoins like USDT and USDC. Decentralized stablecoins like DAI and sUSD make up only a small portion of the total stablecoin supply, meaning the vast majority of stablecoins are centralized.
Threshold USD addresses this by creating a more capital efficient and user-friendly way to borrow stablecoins.
Threshold USD’s key benefits include:
Low cost for tBTC loan (0.5% issuance fee and no interest rate at launch).
Minimum collateral ratio of 110% — more efficient usage of deposited tBTC
Governance Minimized— most operations are algorithmic and fully automated, and most protocol parameters are set at time of contract deployment.
Note: See section above for parameters that can be changed through governance
Directly redeemable — thUSD can be redeemed at face value for the underlying collateral at any time
Yes. The Threshold USD token contracts mint function will be able to add additional contracts; this is how we keep the option to upgrade while leaving all the contracts immutable with the exception of the price feed contract.
You can use thUSD via a web interface (aka frontend) or directly via the smart contracts.
Borrow thUSD against tBTC by opening a Vault and use directly in DeFi applications or exchange for other coins
Secure Threshold USD by providing thUSD to the Stability Pool in exchange for Liquidation rewards
Redeem 1 thUSD for 1 USD worth of tBTC when the thUSD peg falls below $1 (i.e. arbitrage the system)
thUSD is the USD-pegged stablecoin used to pay out loans on the Threshold USD protocol. At any time it can be redeemed against the underlying collateral at face value.
To become a Stability Pool depositor you need to have thUSD, which can be borrowed by opening a Vault. You can also use Curve or another (decentralized) exchange to buy the tokens on the open market.
These are the fees for using Threshold USD Protocol:
A one-time fee whenever thUSD is borrowed, as a percentage of the drawn amount (in thUSD)
A fee when thUSD is redeemed (see Section “Redemptions and thUSD Price Stability” for details on the Redemption Mechanism)
For redeemers, there is a redemption fee on the amount paid to users by the system (in tBTC) when exchanging thUSD for tBTC. Note that redemption is separate from repaying your loan as a borrower, which is free of charge
Both fees depend on the redemption volumes, i.e. they increase upon every redemption in function of the redeemed amount, and decay over time as long as no redemptions take place. The intent is to throttle large redemptions with higher fees, and to throttle borrowing directly after large redemption volumes. The fee decay over time ensures that the fee for both borrowers and redeemers will “cool down”, while redemptions volumes are low.
The fees cannot become smaller than 0.5% (except in Recovery Mode), which protects the redemption facility from being misused by arbitrageurs front-running the price feed. The borrowing fee is capped at 5%, keeping the system (somewhat) attractive for borrowers even in phases where the monetary is contracting due to redemptions. Other than that, the two fees are identical.
Interest rate: at launch no ongoing interest rate is charged when using ETH and tBTC as collateral, only the initial borrowing fee.
The decision to incorporate an ongoing interest rate that will accrue on the loan amount in thUSD, which is calculated based on a predetermined interest rate and the amount of time that has elapsed, will be made by the DAO in the near future for these and any other future collaterals.
There are two main ways to generate revenue using Threshold USD:
Deposit thUSD to the Stability Pool and earn liquidation gains (in tBTC).
Other opportunities may arise in time in the DeFi Ecosystem to use thUSD and earn rewards or yield.
As a non-custodial system, all the tokens sent to the protocol will be held and managed algorithmically without the interference of any person or legal entity. That means your funds will only be subject to the rules set forth in the smart contract code.
You may lose all or part of your funds in a Liquidation scenario:
You are a borrower (Vault owner) and your collateral in tBTC is liquidated. You will still keep your borrowed thUSD, but your Vault will be closed and your collateral will be used to compensate Stability Pool depositors.
If the liquidation happens under Normal Mode (i.e. your Vault is at 110% Collateral Ratio), all your Collateral will be used the Liquidation and fees
If the liquidation happens under Recovery Mode (i.e. Total Protocol Collateral Ratio is less than 150%), you may recover a part of the Collateral if your Vault is between the 110% and 150% Collateral Ratio)
In addition, the following Scenarios may happen that may lead to loss of funds:
Bugs/Hacks: Please note that although the system is diligently audited, a hack or a bug that results in losses for the users can never be fully excluded. This includes potential bugs/hacks on tBTC as it is the collateral for thUSD.
Price Oracle Risk: Liquidations are triggered by the Collateral Ratio, which is a function of the Collateral Price. There is a risk of malfunction of manipulation with the Price Feed. We are minimizing the exposure to those risks, but they cannot be completely ruled out
If the Threshold USD is not accepted and all users want to leave, the last fraction of collateral cannot be recovered as there won’t be enough thUSD available (due to Loan fees accrued). This would only affect a very minor fraction of capital
For redemptions, in case of an acceleration of redemptions, the redemption fee increases and can lead to losses. If the Total Collateral Ratio is less than 110%, redemptions are blocked
Bitcoin (BTC)
Ethereum (ETH) for Ethereum transaction gas costs
Bitcoin compatible wallet
Ethereum compatible wallet
You're ready to mint! Go to the tBTC dapp here: https://dashboard.threshold.network/tBTC/mint
You've successfully minted tBTC!
That means we can use a Binomial Probability Calculator to answer our question:
The system was designed from the outset to be fully permissionless - anyone with the minimum amount of T stake, could run a node and have a of being a custodian.
tBTC currently uses a permissioned set of signers (aka ) operating under an honest-majority assumption.
During the early days of the system; the testnet and phases, it is important to ensure that signers are available to help test changes and quickly respond to critical bugs. Having direct access to individuals known to the development team is critical in this context.
The underlying signature algorithm, , cannot identify misbehaving signers.
They are not yet codebases.
To address this issue, we have been developing a proof-of-concept for and exploring .
If a Guardian or Minter misbehaves, the can vote to remove them.
Threshold Network's powers tBTC and is the value accrual asset used to distribute profits from bridge fee via token buybacks.
Threshold Coverage Pool has been sunset via the DAO ratified proposal.
The Threshold Coverage Pool served as a backstop for assets secured by the tBTC protocol. In the event that secured Bitcoin were lost from the protocol, assets from the coverage pool were to be withdrawn by the risk manager, converted to BTC, and put back into the protocol to achieve the supply peg as closely as possible. The risk manager for the coverage pool was the multisig.
Join the discussion and ask questions about the coverage pool in the in the .
When a user makes a deposit, they're locking up the funds using our specific . This creates an Unspent Transaction Output ().
Typically, the job of a bitcoin "wallet" (wallets don't exist in the same way that they do on ethereum) is to scan the blockchain for particular locking script patterns that it thinks it can unlock (like a associated to your public key) and sum up the relevant funds. When you want to send someone else bitcoin, the wallet software figures out which UTXOs to unlock to send to them so that you don't have to.
Further, our includes this idea of a time-locked refund. If the funds are not touched by a certain amount of time (9 months at the time of writing; <locktime>
in the script), we allow the depositor to reclaim their deposit. We do this as an effective escape hatch for if something goes wrong with the protocol or deposit.
Sweeping aims to solve both of these problems simultaneously as well as serves as a performance optimization. Every 8 hours, we take all of the recent deposits, unlock them, and then send the funds using a normal back to the wallet itself, consolidating the UTXOs into a single UTXO.
Here's a deposit for . That deposit is swept in transaction (along with many other deposits). That was one of three sweeps performed by that wallet (as of writing).
launched in 2023 the second generation of , a decentralized and scalable bridge between Bitcoin and Ethereum. It provides Bitcoin holders secure and open access to the broader DeFi ecosystem.
In addition to the collateral, the loans are secured by a Stability Pool containing thUSD and by fellow borrowers collectively acting as guarantors of last resort. Learn more about these mechanisms under .
Threshold USD as a protocol is based on a fork of Liquity (), which has established itself as a successful protocol since its launch on May 2021, going through several severe stress tests successfully.
This documentation is based on the Liquity documents () with the appropriate changes that are relevant to Threshold USD.
Providing liquidity to the thUSD Pool in Curve () to earn swapping fees and maybe incentive fees (these may be time dependent and could be turned on or off at will)
To borrow thUSD, all you need is a wallet (e.g. MetaMask or ) and sufficient tBTC or ETH to open a Vault and pay the gas fees.
Providing liquidity to the thUSD Pool in Curve () to earn swapping fees and maybe incentive fees (these may be time dependent and could be turned on or off at will)
Key aspects and parameters of borrowing thUSD
Threshold USD protocol offers low interest loans and is more capital efficient than other borrowing systems (i.e. less collateral is needed for the same loan). Instead of selling tBTC to have liquid funds, you can use the protocol to lock up your tBTC, borrow against the collateral to withdraw thUSD, and then repay your loan at a future date.
For example: Borrowers speculating on future tBTC price increases can use the protocol to leverage their tBTC positions up to 11 times, increasing their exposure to price changes. This is possible because thUSD can be borrowed against tBTC, sold on the open market to purchase more tBTC — rinse and repeat.*
*Note: This is NOT a recommendation for how to use Threshold USD. Leverage can be very risky as you can lose all your funds and should be used only by those with experience and for speculative amounts.
Collateral is any asset which a borrower must provide to take out a loan, acting as a security for the debt.
Currently, Threshold USD supports tBTC and ETH as collateral but additional collaterals could be added as voted by governance, as the code allows for it. The reasoning behind having these two collaterals is that they represent the two most decentralized assets in the Ethereum Ecosystem.
To borrow you must open a Vault and deposit a certain amount of collateral (tBTC) to it. Then you can draw thUSD up to a collateral ratio of 110%. A minimum debt of 2,000 thUSD is required. This minimum debt threshold prevents an attacker from creating a large number of Vaults that are then unprofitable to liquidate.
A Vault is where you take out and maintain your loan. Each Vault is linked to an Ethereum address and each address can have just one Vault. If you are familiar with Troves or CDPs from other platforms, Vault are similar in concept.
Vaults maintain two balances: one is an asset (tBTC) acting as collateral and the other is a debt denominated in thUSD. You can change the amount of each by adding collateral or repaying debt. As you make these balance changes, your Vault’s collateral ratio changes accordingly.
You can close your Vault at any time by fully paying off your debt.
For the base situation, see the section “Does Threshold USD charge any fees?”
Every time you draw thUSD from your Vault, a one-off borrowing fee is charged on the drawn amount and added to your debt. Please note that the borrowing fee is variable (and determined algorithmically) and has a minimum value of 0.5% under normal operation. The fee is 0% during Recovery Mode.
A 200 thUSD Liquidation Reserve charge will be applied as well, but returned to you upon repayment of debt.
When a Loan is opened, the borrowing fee is added to the debt of the Vault and is given by a baseRate . The fee rate is confined to a range between 0.5% and 5% and is multiplied by the amount of liquidity drawn by the borrower.
For example: The borrowing fee stands at 0.5% and the borrower wants to receive 4,000 thUSD to their wallet. Being charged a borrowing fee of 20.00 thUSD, the borrower will incur a debt of 4,220 thUSD after the Liquidation Reserve and issuance fee are added.
Loans issued by the protocol do not have a repayment schedule. You can leave your Vault open and repay your debt any time, as long as you maintain a collateral ratio of at least 110%.
This is the ratio between the Dollar value of the collateral in your Vault and its debt in thUSD. The collateral ratio of your Vault will fluctuate over time as the price of tBTC changes. You can influence the ratio by adjusting your Vault’s collateral and/or debt — i.e. adding more tBTC collateral or paying off some of your debt.
For example: Let’s say the current price of tBTC is $30,000 and you decide to deposit 1 tBTC. If you borrow 10,000 thUSD, then the collateral ratio for your Vault would be 200%.
(1tBTC * $30,000/10,000 thUSD)*100 = 300%
If you instead took out 15,000 thUSD that would put your ratio at 200%.
The minimum collateral ratio (or MCR for short) is the lowest ratio of debt to collateral that will not trigger a liquidation under normal operations (aka Normal Mode). This is a protocol parameter that is set to 110%. So if your Vault has a debt of 10,000 thUSD, you would need at least $11,000 worth of tBTC posted as collateral to avoid being liquidated.
To avoid liquidation during Recovery Mode, it is recommended to keep the ratio comfortably above 150% (e.g. 200% or better 250%).
You lose your collateral as your debt is paid off through liquidation, i.e. you will no longer be able to retrieve your collateral by repaying your debt. A liquidation thus results in a net loss of 9.09% (= 100% * 10 / 110) of your collateral’s Dollar value.
When you open a Vault and draw a loan, 200 thUSD is set aside as a way to compensate gas costs for the transaction sender in the event your Vault gets liquidated. The Liquidation Reserve is fully refundable if your Vault is not liquidated, and is given back to you when you close your Vault by repaying your debt. The Liquidation Reserve counts as debt and is taken into account for the calculation of a Vault's collateral ratio, slightly increasing the actual collateral requirements.
When thUSD is redeemed, the tBTC provided to the redeemer is allocated from the Vault(s) with the lowest collateral ratio (even if it is above 110%). If at the time of redemption you have the Vault with the lowest ratio, you will give up some of your collateral, but your debt will be reduced accordingly.
The USD value by which your tBTC collateral is reduced corresponds to the nominal thUSD amount by which your Vault’s debt is decreased. You can think of redemptions as if somebody else is repaying your debt and retrieving an equivalent amount of your collateral. As a positive side effect, redemptions improve the collateral ratio of the affected Vaults, making them less risky.
Redemptions that do not reduce your debt to 0 are called partial redemptions, while redemptions that fully pay off a Vault’s debt are called full redemptions. In such a case, your Vault is closed, and you can claim your collateral surplus and the Liquidation Reserve at any time.
Let’s say you own a Vault with 2 tBTC collateralized and a debt of 32,000 thUSD. The current price of tBTC is $20,000. This puts your collateral ratio (CR) at 125% (= 100% * (2 * 20,000) / 32,000). Let’s imagine this is the lowest CR in the Threshold USD system and look at two examples of a partial redemption and a full redemption:
Somebody redeems 12,000 thUSD for 0.6 tBTC and thus repays 12,000 thUSD of your debt, reducing it from 32,000 thUSD to 20,000 thUSD. In return, 0.6 tBTC, worth $12,000, is transferred from your Vault to the redeemer. Your collateral goes down from 2 to 1.4 tBTC, while your collateral ratio goes up from 125% to 140% (= 100% * (1.4 * 20,000) / 20,000).
Somebody redeems 60,000 thUSD for 3 tBTC. Given that the redeemed amount is larger than your debt minus 200 thUSD (set aside as a Liquidation Reserve), your debt of 32,000 thUSD is entirely cleared and your collateral gets reduced by $30,000 of tBTC, leaving you with a collateral of 0.5 tBTC (= 2 - 30,000 / 20,000).
By making liquidation instantaneous and more efficient, Threshold USD needs less collateral to provide the same security level as similar protocols that rely on lengthy auction mechanisms to sell off collateral in liquidations.
You can sell the borrowed thUSD on the market for tBTC and use the latter to top up the collateral of your Vault. That allows you to draw and sell more thUSD, and by repeating the process you can reach the desired leverage ratio.
Note: This is NOT a recommendation for how to use Threshold USD. Leverage can be very risky and should be used only by those with experience and still will most probably end up with a Liquidation, so this should be avoided.
If Vaults are liquidated and the Stability Pool is empty (or gets emptied due to the liquidation), every borrower will receive a portion of the liquidated collateral and debt as part of a redistribution process.
This is a mechanism to reduce systemic risk to thUSD by ensuring a total collateral ratio across all Vaults remain above 150%
Recovery Mode kicks in when the Total Collateral Ratio (TCR) of the system falls below 150%.
During Recovery Mode, Vaults with a collateral ratio below 150% can be liquidated.
Moreover, the system blocks borrower transactions that would further decrease the TCR. New thUSD may only be issued by adjusting existing Vaults in a way that improves their collateral ratio, or by opening a new Vault with a collateral ratio>=150%. In general, if an existing Vault's adjustment reduces its collateral ratio, the transaction is only executed if the resulting TCR is above 150%.
The Total Collateral Ratio or TCR is the ratio of the Dollar value of the entire system collateral at the current ETH:USD price, to the entire system debt. In other words, it's the sum of the collateral of all Vaults expressed in USD, divided by the debt of all Vaults expressed in thUSD.
The goal of Recovery Mode is to incentivize borrowers to behave in ways that promptly raise the TCR back above 150%, and to incentivize thUSD holders to replenish the Stability Pool.
Economically, Recovery Mode is designed to encourage collateral top-ups and debt repayments, and also itself acts as a self-negating deterrent: the possibility of it occurring actually guides the system away from ever reaching it. Recovery Mode is not a desirable state for the system.
While Recovery Mode has no impact on the redemption fee, the borrowing fee is set to 0% to maximally encourage borrowing (within the limits described above).
By increasing your collateral ratio to 150% or greater, your Vault will be protected from liquidation. This can be done by adding collateral, repaying debt, or both.
Yes, you can be liquidated below 150% if your Vault's collateral ratio is smaller than 150%. In order to avoid liquidation in Normal Mode and Recovery Mode, a user should keep their collateral ratio above 150%.
In Recovery Mode, liquidation loss is capped at 110% of a Vault's collateral. Any remainder, i.e. the collateral above 110% (and below the TCR), can be reclaimed by the liquidated borrower using the standard web interface.
This means that a borrower will face the same liquidation “penalty” (10%) in Recovery Mode as in Normal Mode if their Vault gets liquidated.
A Bitcoin-backed Stablecoin
A certain network effect is required for a stablecoin to function well. Bootstrapping is the process of ensuring the protocol has gained enough traction to become self-sufficient.
In the past this was usually accomplished by being an early adopter of coins, such as buying Bitcoin early and benefiting from the lower price. DeFi revolutionized the bootstrapping concept by enabling the bootstrapping of capital through yield-farming (aka rented liquidity).
Liquity Protocol (creators of the LUSD stablecoin) bootstrapped by issuing LQTY tokens to depositors in the stability pool. This incentivized people to take out loans and deposit to the stability pool.
For normal, healthy operations of the protocol, it's vital that there is sufficient funds in the stability pool to cover all liquidations. However the LQTY incentive resulted in far more deposits than required, essentially creating wasted capital. Furthermore there are concerns on how sustainable Liquity will be after the initial 100 million LQTY has been issued and the pool is only sustained through liquidations rewards.
In Threshold USD we take a different approach. A newer concept in DeFi known as Protocol Controlled Value (PCV) is the idea that the protocol itself can own liquidity and use that to improve the protocol. This is a new alternative to renting it elsewhere (aka yield-farming) and has the benefit of long-term sustainability.
But the PCV has to come from somewhere. In thUSD we resolve this by issuing an Initial Protocol Loan to the PCV which then deposit these funds directly to the stability pool. Read more about this here:
That lets us bootstrap the stability pool at zero cost to the protocol.
But not only that, by eliminating the LQTY token, all profits (from interest, redemption fee, etc) will go directly into the PCV. Compared to Liquity, where profits are distributed among LQTY holders, we have eliminated a massive drain on the system, at no cost.
Having the stability pool funded on its own is enough for the protocol to function, and we can expect some users that want to borrow against their tBTC to take part, but it's not going to create major adoption, and for thUSD to function well it needs to be stable at ~$1, that requires people to put up liquidity at decentralized exchanges.
In order to draw in more users and create liquidity for thUSD, we will issue rewards to pools on other platforms (such as a thUSD stablecoin pool on Curve). This will incentivize users to take debt and deposit into Curve, with the added benefit of improved liquidity and resiliency.
How fast we want to grow can be almost entirely adjusted by how much reward is sent to the pool.
This part is indeed rented liquidity with all its drawbacks, but remember that Threshold USD profits are sent to the PCV instead of LQTY holders: as the protocol grows in popularity, profits from the protocol itself can be used to fund these rewards, thus creating a self-sustaining feedback loop.
On top of that, Threshold DAO will store some of its reserves in stablecoins, so the Threshold DAO can initiate a PCV with deposits on Curve. That will result in more stability for thUSD which is important for adoption.
Redemptions are a mechanism to return thUSD to a value of 1USD if it falls below it
The ability to redeem thUSD for tBTC at face value (i.e. 1 thUSD for $1 of tBTC) and the minimum collateral ratio of 110% create a price floor and price ceiling (respectively) through arbitrage opportunities. We call these "hard peg mechanisms" since they are based on direct processes.
thUSD also benefits from less direct mechanisms for USD parity — called "soft peg mechanisms". One of these mechanisms is parity as a Schelling point. Since Threshold USD treats thUSD as being equal to USD, parity between the two is an implied equilibrium state of the protocol. Another of these mechanisms is the borrowing fee on new debts. As redemptions increase (implying thUSD is below $1), so too does the baseRate — making borrowing less attractive which keeps new thUSD from hitting the market and driving the price below $1.
Liquity (on which thUSD Protocol is based on) did a thorough analysis on the price stability of LUSD here (https://www.liquity.org/blog/on-price-stability-of-liquity). This analysis is equally relevant for thUSD.
A redemption is the process of exchanging thUSD for tBTC at face value, as if 1 thUSD is exactly worth $1. That is, for x thUSD you get x Dollars worth of tBTC in return.
Users can redeem their thUSD for tBTC at any time without limitations. However, a redemption fee might be charged on the redeemed amount.
For example, if the current redemption fee is 1%, the price of tBTC is $50,000 and you redeem 10,000 thUSD, you would get 0.198 tBTC (0.2 tBTC minus a redemption fee of 0.002 tBTC).
Note that the redeemed amount is taken into account for calculating the base rate and might have an impact on the redemption fee, especially if the amount is large.
To illustrate how Redemptions work, below you can see the mechanism in action for LUSD, when its value went below 1 USD. The Borrowing rate (red line) immediately spiked from 0.5% up to around 1.8% and redemptions (blue bars) started to happen, i.e. users would buy LUSD at less than 1 USD and redeem for ETH in Vaults as if it was valued at 1 USD, arbitraging the difference, reducing the supply of LUSD and increasing its price.
No, redemptions are a completely separate mechanism. All one has to do to pay back their debt is adjust their Vault's debt and collateral.
Under normal operation, the redemption fee is given by the formula (baseRate + 0.5%) * tBTCdrawn
Redemption fees are based on the baseRate state variable in Threshold USD, which is dynamically updated. The baseRate increases with each redemption, and decays according to time passed since the last fee event - i.e. the last redemption or issuance of thUSD.
Upon each redemption:
baseRate is decayed based on time passed since the last fee event
baseRate is incremented by an amount proportional to the fraction of the total thUSD supply that was redeemed
The redemption fee is given by (baseRate + 0.5%) * tBTCdrawn
If your Vault is redeemed against, you do not incur a net loss. However, you will lose some of your tBTC exposure. Your Vault's collateral ratio will also improve after a redemption.
The best way to avoid being redeemed against is by maintaining a high collateral ratio relative to the rest of the Vault's in the system. Remember: The riskiest Vault (i.e. lowest collateralized Vaults) are first in line when a redemption takes place.
B. Protocol is a third-party decentralized backstop liquidity protocol aiming to make lending platforms more stable.
In Liquity Protocol there's a concept called "Stability Pool". The purpose of the stability pool is to purchase liquidated collateral (tBTC) at a discount by using Threshold USD (thUSD) as payment.
Users deposits thUSD into the stability pool and their funds are pooled with other depositors. If a pool consist of 900,000 thUSD and a user deposits 100,000 thUSD, that user is entitled to 10% of the collateral seized.
The issue with stability pool is that as liquidations occurs, thUSD is traded to tBTC, but never back to thUSD. If left untouched, the pool will eventually only consist of tBTC and no further liquidations can take place against the pool. Furthermore, by acquiring tBTC collateral, the value for depositors in the pool becomes subject to the price of BTC.
Users are therefore incentivized to quickly sell of the tBTC for thUSD to avoid taking on price risk, but in Liquity, this process is manual. Users have to manually open the UI and withdraw tBTC, sell it for thUSD and then re-deposit the thUSD. This is both a time consuming and gas costly operation, best suited for whales and users with their own bots.
Even worse, a DAO cannot realistically operate in the current stability pool model because voting to move and sell funds becomes impractical, costly and slow.
In order to establish a non-human, algorithmic, fully automated solution to compound profits we look to B.Protocol.
Instead of depositing directly into the stability pool, we can use B.Protocol's wrapping smart contract interface, which deposits the thUSD to the stability pool on behalf of all users (and the PCV).
Once liquidation happens, the discounted tBTC is automatically offered for sale by B.Protocol’s Backstop AMM (B.AMM). This is done according to a deterministic formula, which takes into account the current tBTC and thUSD inventory, and the current BTC-USD market price (which is taken from Chainlink). Whenever the sale occurs, the smart contract deposits the returned thUSD back to the stability pool.
If there are no takers for the offer on the B.AMM, Gelato Keepers will arbitrage through popular DEX pairs to fulfill the order.
This way the PCV becomes self-sufficient and able to operate indefinitely without outside interference.
B.Protocol Team will deploy a non-upgradeable pool that is Threshold USD compatible.
The pool will be using Chainlink BTC/USD oracle (same as Threshold USD).
The pool will not deploy idle funds in any yield farming applications.
Threshold USD PCV will whitelist the smart contract for the B.Protocol pool and the Threshold Network DAO (T DAO) will vote to initiate a deposit of thUSD to the B.Protocol pool. The deposit is moved from the PCV smart contract to B.Protocol and can be moved back to the PCV at any time, without limitation, as long as the T DAO votes to do so. If there is tBTC in the pool at the time of withdraw, the tBTC may also be transferred back to the PCV.
The B.AMM contract's "A" parameter ("A" is amplification factor, higher value means less slippage) is operated through a co-ownership between T DAO and B.Protocol, where B.Protocol propose "A" value and T DAO can approve or reject.
The discount rate is set to 4% on deployment, but the max rate should be configurable up to 10% in a joint governance mechanism between T DAO & B.Protocol.
All profits from liquidations will auto-compound within the B. Protocol pool.
Keeper
As a backup mechanism, B. Protocol will deploy Gelato keepers that can route.
Example:
tBTC -> WBTC -> USDC -> thUSD
In this example funds could be routed through Curve Finance pools (both stablecoin and wrapped bitcoin pools).
In addition, funds could be routed through uniswap (v2 or v3) WBTC or USDC paired pools.
Other routes could be:
tBTC -> WBTC -> DAI -> thUSD
tBTC -> WBTC -> USDT -> thUSD
The keeper is funded by the DAO and any profit it makes is distributed back to the PCV.
Ensure your wallet has sufficient ETH for transaction fees. You can fund your wallet on BOB by transferring tBTC or ETH from the Ethereum Mainnet.
Note: The minimum amount to mint thUSD on BOB is $2,000 ($1,800 minimum debt + $200 liquidation reserve) worth of tBTC or ETH + transaction fees.
Set up Wallet:
Ensure you have a wallet connected to the Ethereum Mainnet with sufficient tBTC or ETH for bridging.
Access Bridge Interface:
Connect Wallet:
Connect your wallet on the Ethereum Mainnet network to the bridge interface.
Select tBTC or ETH:
Choose tBTC or ETH as the asset you want to bridge.
Enter Amount:
Specify the amount of tBTC or ETH you want to bridge.
Confirm Transaction:
Review the transaction details, including fees, and confirm the transaction.
Authorize Transaction:
Approve the transaction in your wallet.
Wait for Confirmation:
Wait for the transaction to be confirmed on the Ethereum blockchain.
Verify Receipt:
Once confirmed, check your wallet on the BOB Network to verify the receipt of the bridged tBTC or ETH.
Note: When bridging assets back from the BOB Network, please know that the process can take up to 7 days.
Access Wallet Setup
Connect Your Wallet
Choose your preferred wallet (e.g., MetaMask) and follow the prompts to connect it to the BOB Network.
Switch to BOB Network
Click on the option "Switch to BOB." This will automatically add the BOB Network to your wallet and connect your wallet to the BOB Network.
Manual Setup
Alternatively, you can manually set up your wallet with the following settings:
Chain ID: 60808
Gas Token: ETH
Threshold is community-driven and governed by an eponymous DAO that includes the constituencies of both the NuCypher and Keep networks. The Threshold DAO has two primary bodies: the Tokenholder DAO and the Elected Council. The goal of this two-pronged structure is to enhance representation while ensuring accountability. Each of these governance bodies holds the other accountable, similar to the system of checks and balances found in most constitutional governments. They also hold separate responsibilities that are embedded in the governance structure.
From an implementation perspective, the Tokenholder DAO is based on the Governor Bravo governance model (in particular, using OpenZeppelin Governance). The Tokenholder DAO is on Ethereum Mainnet at 0xd101f2B25bCBF992BdF55dB67c104FE7646F5447
. The Elected Council is implemented as a Gnosis Safe contract, with a 6-of-9 configuration, also deployed on Ethereum Mainnet, at 0x9F6e831c8F8939DC0C830C6e492e7cEf4f9C2F5f
.
A technical architecture diagram is show below.
Navigate to the BOB bridge interface at .
Navigate to .
RPC URL:
WS URL:
Explorer:
The Initial Protocol Loan (IPL) is a debt issued against the protocol itself in order to fund the stability pool. Even though it's technically debt, it does not in itself make the protocol a fractional reserve because all funds are accounted for.
thUSD is minted by the PCV and deposited into the stability pool. A freeze on withdraw is initiated until debt is fully repaid. At any time, the Threshold DAO can initiate a withdraw, which will destruct the debt and withdraw exceeds. If the PCV for some reason has less than the debt available, withdraw is denied.
Profits from usage of the protocol (loan interest, redemption fee, etc) accrues into the PCV, so in an event where there are less funds than debt the protocol first has to earn back the missing funds.
Benefits of the hybrid PCV + IPL model:
Bootstrap stability pool for free
No need for a Protocol token = all profits accrue directly to the PCV
Immediate surplus on first loan drawn / liquidation
Predictability and (once debt is repaid) high resilience against Black Swans
No idle capital (it doesn't "really" exist)
Disadvantages
Higher risk of under-collateralization during the initial stages
Poor management of PCV could result in not enough funds in the stability pool
Each liquidation that occurs will draw against the stability pool and result in ~10% profit to the stability pool. This also means that the price can drop up to 10% after a liquidation before the stability pool is at risk of losing money on the liquidation. Our integration with B.Protocol ensures that liquidated tBTC is automatically converted back to thUSD and re-deposited into the stability pool. Under normal circumstances and without other factors, it is expected that the balance of thUSD in the pool will grow over time.
But there can be Black Swan events, large drops in the price of BTC in a short period of time or liquidity issues that results in a loss, even at ~10% profit. This is a risk of the protocol becoming undercollateralized, but the same issue would apply even without debt (stability pool not being profitable). The protocol is created to be sustainable, so these types of rare events will be averaged out. In addition, all income streams from Threshold USD also ends up in the PCV which further decrease the risk of undercollaterization.
The undercollaterialization is mostly a concern during the initial bootstrapping phase. As interest accrue and repay the initial debt, the funds in the stability pool will be replaced by fully owned PVC, thus eliminating this disadvantage.
Threshold USD (thUSD) is a stablecoin soft-pegged against USD, backed by ETH and tBTC as collateral. For more details, refer to the THUSD overview.
With thUSD, you can now:
Open collateral vaults seamlessly on BOB Network using bridged tBTC or ETH
Mint thUSD and utilize it across the BOB Network ecosystem
Start by connecting your preferred wallet (e.g., MetaMask) at app.gobob.xyz/wallet and bridging your tBTC at app.gobob.xyz/bridge.
Access the thUSD App Interface:
Navigate to app.thresholdusd.org and connect your preferred wallet on BOB Network.
Open a New Vault:
Go to the “Borrow” menu, choose tBTC or ETH as your collateral, and select "Open a Vault".
Deposit tBTC or ETH:
Specify the amount of tBTC or ETH you wish to deposit as collateral. Ensure the deposited amount meets the minimum collateral requirement of $2,000 ($1,800 minimum debt + $200 liquidation reserve) + transaction fees.
Set the collateral amount:
Set your desired collateral amount. Ensure it meets the minimum required ratio of 110% of your debt.
Mint thUSD:
Enter the amount of thUSD you wish to mint based on your collateral and collateralization ratio.
Review the details of your vault, including the collateral amount, collateralization ratio, and minted thUSD.
In case of tBTC as collateral, approve tBTC expenditure.
Confirm, and authorize the transaction to mint thUSD.
Manage Your Vault:
Monitor your vault on app.thresholdusd.org to ensure it remains adequately collateralized. You can adjust collateral and debt position to adjust the collateralization ratio or repay thUSD as needed.
Additionally to the DAO governance bodies, there are three community-led guilds with different focus areas: the Marketing Guild, the Integrations Guild, and the Treasury Guild. Each guild is managed by an elected committee and holds regular, rotating elections.
Join a guild (via Discord's #dao-contribute
channel) and work together with other Threshold DAO members based on your interests and expertise!
The Threshold Treasury Guild is responsible for effectively managing the Threshold DAO treasury. This includes growing Protocol Owned Liquidity (POL), researching / implementing best practice treasury management strategies, executing ecosystem liquidity incentives, diversifying the treasury, etc.
The core mission of the Threshold Integrations Guild is to build successful, synergistic and long-lasting relationships with other protocols, DAOs and external organizations.
The Threshold Marketing Guild is responsible for general Threshold marketing, growing our network of contributors, onboarding new members to the Threshold DAO, educating people about the Threshold’s value, services and use cases, and more.
To participate in DAO governance, token holders must set a governance delegate address. Vote delegation is the process of granting a delegate the power to vote on your behalf, using your voting weight, on DAO governance issues. The delegate can be yourself (self-delegation) or a third party. A configured delegate can be changed or revoked at any time.
Delegation never involves the transfer of custody of assets but rather just the vote weight those assets represent in the Threshold DAO.
Third-party delegates are volunteers who actively participate in Threshold governance and wish to grow their influence over critical DAO decisions. Delegates provide ETH addresses to which other Threshold token holders and Threshold stakers can delegate their vote weight. Third-party delegates are subsequently responsible for voting on Threshold governance proposals with this vote weight that others have assigned to them.
Community members who are unsure or uninterested in governance and do not want to actively participate in proposals, discussions, and voting, can instead delegate to active DAO members who have demonstrated a commitment to Threshold. Delegating their vote allows token holders and stakers to have an indirect say in the DAO without being involved in day-to-day governance activities.
Community members interested in serving as delegates can self-nominate here.
There is no compensation for third-party delegate contribution to governance.
The process for delegating liquid tokens is explained in the following subsection. It's not currently possible to delegate tokens deposited as LP in AMM pools (e.g. Curve), although this is an area for future improvement.
Update procedure for the tBTC v2 client depends on installation method
The following instructions assume your docker install followed these installation instructions.
To update a tBTC node:
Pull the new image
Restart the tBTC service
To free system resources, run
Examine logs to ensure the node started correctly. Find Docker instance identification; it'll be a random combination of words, e.g. stinky_brownie
:
Use specific identification and substitute accordingly; specify a path and file name for the log file:
Display the log file
Look for the following and take note of the version:
Alternatively, verify your client updated by visiting your status page:
Compare the displayed version number to the version number you are expecting, i.e.:
This install method requires downloading the latest version of the binary. Follow the installation steps provided here.
A tBTC v2 node can be set up using either a docker or binary installation.
Forum discussion: A Threshold community member posts a potential proposal on the Threshold governance forums. Community members who post the initial proposal are encouraged to get active in Meta governance discussions within the community on forums and in Discord to earn support for the proposal. There is no minimum token threshold required to create a new proposal on the forums. Community mods reserve the right to moderate spam proposals during this stage by deleting the proposal from the forums.
Temperature Check: Once a potential proposal has enough traction and discussion within the community, it can proceed for a temperature check via an off-chain snapshot. If a proposal receives majority support during the temperature check, it is eligible to move onto the next step.
Proposal Creation: A community member holding enough vote weight (at least 0.25% of T total supply) submits the proposal on-chain. The proposal enters a 2-day delay period before voting officially begins.
Vote Period: Proposal voting remains open for 10 days. If the proposal passes with enough quorum (at least 1.5% of T total supply), it moves onto the next step; if the proposal fails, it is canceled. Creators and supporters of the proposal may bring a modified proposal forward again but it must be sufficiently different and pass requirements outlined in previous steps.
Timelock Period: Once a proposal is approved, the Governor Bravo smart contracts include an additional timelock delay of 2 days. Anyone can interact with the Governor Bravo smart contracts to queue an approved proposal into the Timelock contract.
Execution: After the timelock delay, anyone can execute an approved proposal.
Council vetos: During the on-chain phase, the Elected Council can veto any proposal. This is intended to be an extra security mechanism in the event that a dangerous proposal passes.
Late quorum prevention: The 10-days voting period is automatically extended when quorum is reached late, to prevent governance attacks that try to reach quorum at the last minute; in case a proposal reaches quorum less than 2 days before the deadline, the proposal deadline is extended for 2 more days from the moment the quorum was reached.
Off-chain proposals: Some proposals do not imply any on-chain action (e.g. Council and Guild elections). In these cases, there is a Snapshot vote that takes 5 days for regular proposals and 7 days for elections, with no associated on-chain proposal.
Compilation of current multisigs for the Threshold Council and Guilds
Ethereum
0x9F6e831c8F8939DC0C830C6e492e7cEf4f9C2F5f
Eth: Foundation
0xf642Bd6A9F76294d86E99c2071cFE2Aa3B61fBDa
Arbitrum
0x9F6e831c8F8939DC0C830C6e492e7cEf4f9C2F5f
Optimism
0x7fB50BBabeDEE52b8760Ba15c0c199aF33Fc2EfA
Polygon
0x9F6e831c8F8939DC0C830C6e492e7cEf4f9C2F5f
Base
0x518385dd31289F1000fE6382b0C65df4d1Cd3bfC
Solana
814TqVmhQGKB3srSLRuMcH6m8qWFHRSbNpRxC5Xnador
The Threshold Council multisigs have a signature policy threshold set to 6 of 9.
Ethereum
0x71E47a4429d35827e0312AA13162197C23287546
Arbitrum
0x6c2bd894bD166DCF053045a4883Db49EAE3FC01C
Optimism
0x126940ea97b328E57E9e2285D546a677b2f38300
Polygon
0xc3Bf49eBA094AF346830dF4dbB42a07dE378EeB6
Base
0x3b8f79458b6d303B47D56734B00CC6941443bd95
Solana
4bZiv1J33tJHiWSHPU96wABAZbPnbJ9M2zCmH9Hs12SW
The Treasury Guild multisigs have a signature policy threshold set to 5 of 9.
Ethereum
eth:0x2ff7aB212cD6FEaE21bAc5300465E149FB6b85a9
Polygon
matic:0x5bD70E385414C8dCC25305AeB7E542d8FC70e667
The Integrations Guild multisigs have a signature policy threshold set to 4 of 7.
Ethereum
eth:0xd55c4261145EA1752662faA0485AfBC8C431b0CA
Polygon
0xe663AD6295d47ce33F9b65950761Ecba6654E5E8
The Marketing Guild multisigs have a signature policy threshold set to 5 of 8.
The following demonstrates how to authorize applications for tBTC v2 and how to register your operator address via the Threshold Dashboard.
One important step to get your node operating on the Threshold Network is proper application authorization as well as operator account registration. Applications need only be authorized once.
It is CRITICALLY important that both the tBTC application as well as the Random Beacon applications are authorized. A node cannot be deployed without both applications being properly authorized.
Please note: by authorizing these applications, an unbonding period of 45 days will go into effect on the T you stake for these applications. This cool-down period begins the day you submit an unstake request.
To get started, visit the Threshold Dashboard and connect your wallet.
Click on "Configure Apps"
Select BOTH tBTC and Random Beacon applications and enter your desired amount of T to stake per application. Note that the minimum is 40,000T.
The operator account is the Ethereum account created on your node. In order for the network to associate your T stake with your node, you must register your Operator Address.
An Operator for the Provider registration can be submitted just once. The Operator address assignment cannot be updated.
After both applications have been authorized, click on "Start Mapping" to begin the Operator Registration process.
Enter your Operator Address in the field provided and click on "Map Address."
Once the steps above have been successfully completed, you are ready to move on to the next step in the node deployment process.
Don't forget: a tBTC v2 node will not be able to be deployed without successfully authorizing both the tBTC and Random Beacon applications, and registering the node's operator address FIRST.
How to delegate liquid T tokens
Liquid T holders can delegate their token weights to themselves or a third party for voting on governance proposals.
Delegation is accomplished via an on-chain transaction which costs ETH gas.
1. Go to https://boardroom.io/threshold.
2. Connect your wallet.
3. Click "Set Up Delegation".
4. Select your "Delegation Type" - either to yourself or a third party.
5. Enter "Delegate Address" and click on "Delegate Votes".
6. Sign the transaction.
This document explains the basic installation and configuration for the tBTC v2 staking client.
This document is intended for members of the community who would like to run their own tBTC v2 node.
Please be aware that running a node is not an easy task and requires technical skill and commitment to maintaining node uptime and availability.
Please review this document in its entirety prior to beginning setup of your node to familiarize yourself with the general setup process.
The Threshold Network expects certain capabilities for each node running on the network. To help attain these capabilities consider the following criteria:
It is paramount that tBTC v2 nodes remain available to the Network. We strongly encourage a stable and redundant internet connection.
Equally important is machine uptime and reliability. A VPS is strongly recommended.
A connection to a production grade self-hosted or third party Ethereum node deployment.
Persistent and redundant storage that will survive a VM or container rotation, and a disk failure.
Each node running on the network requires a unique Ethereum Operator Account. The account has to maintain a positive Ether balance at all times.
Each node running on the network requires a unique IP address or a unique application port running under the same IP.
While it is possible to run the client on a local machine, this is not recommended.
Your operating environment will ultimately dictate what machine type to go with. This is particularly relevant if you’re running a containerized solution where multiple applications are sharing VM resources. The below types are sufficient for running one instance of the tBTC v2 Node.
The preferred OS is Ubuntu.
Starting from version v2.0.0-m3
, the Keep Node interacts with the Bitcoin network through an Electrum protocol server. You can use one of the publicly available servers or run your own. The URL of the chosen server should be passed under the bitcoin.electrum
section of the configuration. If no Electrum server is set explicitly in the bitcoin.electrum
configuration section, the Keep Node will randomly pick one server from its embedded server list, appropriate for the Bitcoin network the Keep Node is currently running against.
Setup persistent data directories for the client.
The client requires two persistent directories. These directories will store configuration files and data generated and used by the client. It is highly recommended to create frequent backups of these directories. Loss of these data may be catastrophic and may lead to slashing.
It is crucial to ensure the data directory is persisted and backed up on a regular basis.
The tBTC v2 client will create two subdirectories within the storage directory: keystore
and work
. You do not need to create these.
The keystore
subdirectory contains sensitive key material data generated by the client. Loosing the keystore
data is a serious protocol offense and leads to slashing and potentially losing funds.
It is the operator’s responsibility to ensure the keystore data are not lost under any circumstances.
The work
directory contains data generated by the client that should persist the client restarts or relocations. If the work
data are lost the client will be able to recreate them, but it is inconvenient due to the time needed for the operation to complete and may lead to losing rewards.
Contained within the operator-key
directory is the account key file (operator key file), its name will be similar to the following:
UTC--2018-11-01T06-23-57.810787758Z--fa3da235947aab49d439f3bcb46effd1a7237e32
copy (not move!) this account key file to the config
directory created above
Required network configuration for the tBTC v2 staking client.
The node has to be accessible publicly to establish and maintain connections with bootstrap nodes and discovered peers. The node exposes metrics and diagnostics services for network health monitoring purposes. Update firewall rules as necessary, including application level firewalls for the following ports
The network port must be exposed publicly for peers to connect to your node.
The status port must be exposed publicly for rewards allocation.
An Announced Address is a layered addressing information (multiaddress
/multiaddr
) announced to the Threshold Network that is used by peers to connect with your node, e.g.: /dns4/bootstrap-0.test.keep.network/tcp/3919
or /ip4/104.154.61.116/tcp/3919
.
If the machine you’re running your node is not exposing a public IP (e.g. it is behind NAT) you should set the network.AnnouncedAddresses
(flag: --network.announcedAddresses
) configuration property to addresses (ip4
or dns4
) under which your node is reachable for the public.
This page will guide you through Binary setup steps.
Choose either Docker installation OR Binary installation.
Under Assets, copy the path to the compressed binary and use the command below to download the file. Make relevant adjustments to version as necessary:
After the download completes, use the command below to display the contents of the folder:
Extract the compressed file:
You can save some time and prevent misspelling a file name by typing the first few letter of the file name and pressing the Tab key. This will autocomplete the file name. Be sure to verify the file name prior to pressing the enter key.
To launch the tBTC v2 client, several configuration flags and environmental values need to be set. For simplicity, a bash script can be used rather than typing or pasting all the flags into the console.
The following flags must be set at minimum:
To launch the client, execute the following:
If everything is configured correctly, the client will request the password for the Operator Account. Supply the password and press Enter.
You should see the following shortly:
Congratulations, your node is up and running.
A Keep Node requires a connection to a WebSocket Ethereum API. You should obtain a WS API URL from a service provider (e.g. , , ) or run your own Ethereum node (e.g. ).
The client expects configuration options to be passed as CLI flags or specified in a . If you specify an option by using a parameter on the command line, it will override the value read from the configuration file.
Assuming for the root user with the command provided in the step, the operator-key file should be located in the /.operator-key
directory.
To read more about multiaddress
see the .
See GitHub for the latest release:
For a complete list of client commands and flags, see .
AWS
c5.large
Azure
F2s v2
Google Cloud
n2-highcpu-2
Self-hosted
2 vCPU / 2 GB RAM / 1 GiB Persistent Storage
Network
network.port
TCP
3919
Status
clientInfo.port
TCP
9601
Alternative application authorization methods to using the Threshold Dashboard.
An operator-registering transaction can be submitted with the Keep Client if the staking provider address key file is available.
An operator-registering transactions can be submitted with Etherscan.
For each of the RandomBeacon
and WalletRegistry
contracts perform the following steps:
Find the address of the contract and open it on Etherscan (see below).
Go to Contract
→ Write Contract
tab.
Connect your wallet with Connect to Web3
button.
Submit the registerOperator
function with your Operator address as an argument.
Prepare your machine to install the tBTC v2 staking client
The client requires an Ethereum Key File of an Operator Account to connect to the Ethereum chain. This account is created in a subsequent step using Geth (GoEthereum).
The Ethereum Key File is expected to be encrypted with a password. The password has to be provided in a prompt after the client starts or configured as a KEEP_ETHEREUM_PASSWORD
environment variable.
The Operator Account has to maintain a positive Ether balance at all times. We strongly advise you monitor the account and top-up when its balance gets below 0.5 Ether.
Please do NOT reuse an operator account that is being used for TACo or other applications.
To create a new Ethereum account, install Geth (GoEthereum) and create a new account using the command below. This account will subsequently be referred to as the Operator Account.
When prompted, provide a password to protect the operator key file.
Use a password manager to generate a strong password and store it safely. It will be needed again during setup.
Avoid passwords that contain the following characters: ', ", `, $ These characters may be interpreted as part of the configuration which can lead to undesirable outcomes that may be extremely time intensive to correct.
Once the process completes, your public key will be displayed. Take note of your Operator Account public key.
DO NOT LOSE THE PASSWORD TO THE OPERATOR ACCOUNT.
Your Operator Account will need to maintain a positive ETH balance at all times to ensure proper operation and availability of your tBTC v2 node.
This page will guide you through Docker setup steps.
Install or update Docker to the latest version. Visit the Official Docker website for detailed instructions. Use the command below to find your installed version if needed:
General best practices recommend against running the tBTC v2 client as the root
user as a security precaution. One security-minded approach is to Run the Docker daemon as a non-root user (Rootless mode).
Next, choose ONE of the following options: Docker Compose makes managing the container simple, but requires an additional step to ensure the container starts after a reboot. The tBTC v2 Service option configures the client to run as a service in order to ensure that the client is restarted automatically, should your machine reboot. The Docker Launch Script is faster to setup, but won't start the client if your machine reboots.
Navigate to cd /home/$USER/keep/
Create a file named docker-compose.yaml
Copy the the template below into the file and replace the <Placeholders> with respective details.
Save and close the file when finished.
To start the tBTC client sudo docker compose up
tBTC will start up with the console output on screen. Verify that the client is running correctly, then press CTRL
+ c
to stop the client.
Restart the client with the 'detach' flag: sudo docker compose up -d
To stop the container at a later time, use sudo docker compose down
To ensure the tBTC container starts after a server reboot, use the template below to create a service in /etc/systemd/system/
called docker-compose-app.service
Adjust the WorkingDirectory
to the path of your tBTC folder. Save and close the file when finished.
use sudo systemctl enable docker-compose-app
to enable the service.
Create the tbtcv2.service file:
Paste the following in the tbtcv2.service file:
Replace the placeholders inside the <> brackets, remove the <> brackets but be sure to not edit anything further.
When done, save and close the file.
Next, test to make sure your configuration works:
There will be no console output because it will be running in the background. Use systemctl to get the status of the service:
If the service failed, go back and double check your configuration.
Another option is to see if the Docker container is running:
If everything is running as intended, enable the service:
Now, with the service running, you should make sure that your configuration will tolerate a reboot and start up again automatically.
Log back in to your machine and check that the service is running. If it is, you're done. If not, go back and review your work.
To launch the tBTC v2 client, several configuration flags and environmental values need to be set. For simplicity, a bash script can be used rather than typing or pasting all the flags into the console.
Create the launch script:
And paste the following:
Save and close the file, and make it executable:
To launch the tBTC v2 client, execute:
The --detach
property will prevent the status messages from the client to be printed to the console. Review the Docker logs for detailed status information.
The path shown in the example configuration will differ from yours. Make sure it is configured correctly.
Unless the --detach
flag was removed from the startup script, there will be no console output. In order to check your node, retrieve the Docker logs.
First, find your Docker instance identification, it'll be a random combination of words, e.g. stinky_brownie
:
Use your specific identification and substitute:
Scroll down about half a page, and you should see the following:
Congratulations, your node is up and running.
Optional logging configuration for the tBTC v2 staking client.
Logging can be configured with environment variables. Please see sample settings:
LOG_LEVEL option DEBUG will generate extensive output. Consider INFO instead.
If you want to share your LibP2P address with others you can get it from the startup log. When sharing remember to substitute the /ipv4/
address with the public facing IP of your client if you’re running on a private machine, or replace the entire /ipv4/
segment with a DNS entry if you’re using a hostname.
Advanced configuration options and tBTC v2 staking client options
Configuration options for logging
Alternative application authorization methods to using the Threshold Dashboard.
Application configuration can be stored in a file and passed to the application with the --config
flag.
Client information exposed by the tBTC v2 staking client.
Use a config file to store client configuration.
Application configuration can be stored in a file and passed to the application with the --config
flag.
Example:
Configuration files in formats TOML, YAML and JSON are supported.
Sample configuration file:
Client information exposed by the tBTC v2 staking client.
The client exposes metrics and diagnostics on a configurable port (default: 9601
) under /metrics
and /diagnostics
resources.
The data can be consumed by Prometheus to monitor the state of a node.
The client exposes the following metrics:
connected peers count,
connected bootstraps count,
Ethereum client connectivity status (if a simple read-only CALL can be executed).
Metrics are enabled once the client starts. It is possible to customize the port at which metrics endpoint is exposed as well as the frequency with which the metrics are collected.
Exposed metrics contain the value and timestamp at which they were collected.
Example metrics endpoint call result:
The client exposes the following diagnostics:
list of connected peers along with their network id and Ethereum operator address,
information about the client’s network id and Ethereum operator address.
Diagnostics are enabled once the client starts. It is possible to customize the port at which diagnostics endpoint is exposed.
Example diagnostics endpoint call result:
Find answers to some of the most commonly asked questions here.
Certain errors may be reported by your node during the early stages of Chaosnet and the tBTC 2 launch. See a sample below:
This warning is normal and may happen on chaosnet. It will disappear and reappear periodically.
This is expected during this stage of the chaosnet. When the pool is locked, new operators cannot join but sortition (selecting operators from the pool) is possible. When the pool is unlocked, new operators can join but the sortition is not possible. Once the first set of beta operators is registered, the pool will get locked for some time to allow the sortition. After some time, when another set of beta operators are added, the pool will be unlocked again.
To get familiarized with API of contracts related to the DAO, go here.
As part of bootstrapping tBTC utility, Threshold Network allow-lists authorized stakers to participate in tBTC minting and redemptions to ensure system continuity during progressive decentralization. These allow-listed stakers are called Beta Stakers. The goal with the Beta Staker program is to ensure key operations run properly without interruptions during early growth.
Note that this is a form of 'progressive decentralization', but with a clear, simple and already deployed pathway for the decentralization depth to increase – i.e. by adding more independent stakers to the allow list.
As of the latest contract query, there are now 35 Beta Stakers, an increase from 20 as previously reported in November 2023. A few notable professional staking providers can be found requesting DAO approval here.
Visit contract page on Etherscan to see the current number of Beta Stakers.
Beta Staker nodes form a permissioned set that is responsible for creating tBTC wallets that custody BTC. Running a tBTC Beta Staker node is a significant commitment with specific requirements. This document aims to highlight such requirements, technical recommendations, and possible costs of operating a Beta Staker tBTC node.
To stay informed about current node activity and overall network health please visit tbtcscan.com/operators or check status.threshold.network. These resources provide up-to-date statistics on node counts, stake distribution and operational metrics.
Running a Beta Staker node is a long-term commitment. Once the given node is added to the Beta Stakers set, it must remain operational until the end of the Beta Staker Program (~12 months).
Operators of Beta Staker nodes are expected to be extremely responsive, especially regarding upgrades requested by software contributors. Ideally, they should be able to upgrade their nodes within 24 hours of notification.
Operators of Beta Staker nodes must be technically capable. They are responsible for ensuring high availability (more than 96% uptime) and security of the node.
A Beta Staker node performs more computationally expensive operations (DKG, threshold signing, etc) compared to a standard node. To ensure a high level of service, a Beta Staker node requires a machine with:
4 CPUs
4 GB of RAM
1 GB of persistent disk space
80 Mbps of network bandwidth
Linux OS
In addition to the above:
The underlying machine’s operating system and tools must be up to date, especially regarding recent security patches.
Backups of the persistent disk must be performed on an ongoing basis. This is crucial to ensure the safety of mission-critical data (e.g. key material). The usage of an additional encryption layer for backups is highly recommended.
The network layer must provide a unique public IPv4 address allowing the node to be reached from the external network. A proper firewall configuration must be in place and ensure a safe perimeter allowing inbound traffic on two ports (communication and diagnostics). The internet connection must be stable and failover scenarios must be taken into account.
A Beta Staker node requires access to an Ethereum node. It is highly recommended to set up a private Ethereum stack (e.g. Geth + Prysm) and use public providers as failover (e.g. Alchemy, Infura, etc). Such a setup is crucial for network diversity and decentralization as it helps avoid the single-point-of-failure risk associated with public providers. Beta Staker operators should use their own judgement for selecting stack components. Specific technical requirements for a private Ethereum stack depend on the software used. For example, a stack based on Geth + Prysm requires 4 CPU / 16 GB RAM / 2 TB SSD.
A Beta Staker node requires an Electrum protocol server to interact with Bitcoin. It is highly recommended to set up a private stack consisting of an Electrum server (e.g. Fulcrum, ElectrumX, Electrs, etc) paired with a Bitcoin node (e.g. Bitcoin Core) and use public servers as failover. The reasons are exactly the same as for a private Ethereum stack. Beta Staker operators should use their own judgement for selecting stack components. Specific technical requirements for a private Bitcoin stack depend on the software used. For example, a stack based on Fulcrum + Bitcoin Core requires 8 CPU / 16 GB RAM / 2 TB SSD.
It is highly recommended to set up a private monitoring stack to ensure observability and alerting. The monitoring system should supervise the node itself as well as Ethereum and Bitcoin stacks. Beta Staker operators should use their own judgement for selecting stack components. Specific technical requirements for a monitoring stack depend on the software used. For example, a stack based on Grafana + Prometheus requires 2 CPU / 4 GB RAM / 20 GB HDD.
The actual monthly costs of running a Beta Staker node depends on the hosting model (VPS vs self-hosting) and infrastructure configuration. The following estimation aims to provide a ballpark figure. It also assumes that all aforementioned technical requirements and recommendations are taken into account.
Key system assumptions
Beta Staker node requires 4 CPUs / 4 GB RAM / 1 GB HDD
Ethereum stack requires 4 CPUs / 16 GB RAM / 2 TB SSD
Bitcoin stack requires 8 CPUs / 16 GB RAM / 2 TB SSD
Monitoring stack requires 2 CPUs / 4 GB RAM / 20 GB HDD
External storage for backups (node and auxiliary stacks) is 1 TB HDD
Network layer ensures 100 Mbps of bandwidth and includes all necessary equipment (firewall, public IPs, etc)
The above assumptions can be used to divide costs into 4 categories:
Computing costs: This category includes the costs of running 18 CPUs and 40 GB RAM in total. There are a number of possible configurations to provide such computing capacity. Using the VPS-based model as an example, the cost of 3x 8CPU/16GB VMs on leading cloud service providers starts from ~$400/month.
Storage costs: This category includes the costs of using 4 TB SSD and ~1 TB HDD of storage in total. For the VPS-based model, part of this cost is often included in the cost of VMs, but some providers charge for the storage separately with rates like ~$0.08/GB (e.g., Amazon EBS). In that case, it is safe to assume that storage costs start from ~$200/month.
Network costs: This category includes the cost of 100 Mbps of bandwidth and all auxiliary equipment and features like a firewall or public IPs. For the VPS-based model, such bandwidth is often provided out of the box with the VMs, but a firewall and public IPs may be charged separately. Moreover, some providers may apply an additional charge on egress traffic. It is safe to assume that network costs start from ~$50/month.
Other costs: This category includes all maintenance and other costs depending on the hosting model and infrastructure configuration. For the VPS-based model, such costs can be OS licenses, automatic backup, additional management tools, and so on. For the self-hosting model, these can be costs of internet connection, power failover (e.g., UPS), auxiliary network equipment, and similar. This category of costs must be factored into the total monthly cost.
In summary, the cost for running a Beta Staker node using the VPS-based model starts at approximately $650/month. Assuming a safety margin for other costs, a rough cost estimate is $800/month for running a setup in accordance with the technical requirements and recommendations.
Estimating the general cost for the self-hosting model is non-trivial due to the variety of possible configurations. The total monthly cost can be similar to the VPS-based model but may also incur additional hidden costs such as hardware maintenance
Above assumptions and figures should be used cautiously as it is only intended to provide a general sense of the infrastructure costs. Each prospective Beta Staker node operator should conduct their own estimates based on their individual circumstances.
Last but not least, the presented estimate refers only to the infrastructure-related costs of operating a tBTC node. This estimate DOES NOT include human operational costs. Each Beta Staker operator must include this overhead when making their own estimates.
Generic interface for an application. Application is an external smart contract or a set of smart contracts utilizing functionalities offered by Threshold Network. Applications authorized for the given staking provider are eligible to slash the stake delegated to that staking provider.
Event emitted by withdrawRewards
function.
Withdraws application rewards for the given staking provider. Rewards are withdrawn to the staking provider's beneficiary address set in the staking contract.
Emits RewardsWithdrawn
event.
Used by T staking contract to inform the application that the authorized amount for the given staking provider increased. The application may do any necessary housekeeping. The application must revert the transaction in case the authorization is below the minimum required.
Used by T staking contract to inform the application that the authorization decrease for the given staking provider has been requested. The application should mark the authorization as pending decrease and respond to the staking contract with approveAuthorizationDecrease
at its discretion. It may happen right away but it also may happen several months later. If there is already a pending authorization decrease request for the application, and the application does not agree for overwriting it, the function should revert.
Used by T staking contract to inform the application the authorization has been decreased for the given staking provider involuntarily, as a result of slashing. Lets the application to do any housekeeping neccessary. Called with 250k gas limit and does not revert the transaction if involuntaryAuthorizationDecrease
call failed.
Returns the amount of application rewards available for withdrawal for the given staking provider.
The minimum authorization amount required for the staking provider so that they can participate in the application.
Abstract contract to support checkpoints for Compound-like voting and delegation. This implementation supports token supply up to 2^96 - 1. This contract keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting power can be publicly queried through {getVotes} and {getPastVotes}. NOTE: Extracted from OpenZeppelin ERCVotes.sol. This contract is upgrade-safe.
Emitted when an account changes their delegate.
Emitted when a balance or delegate change results in changes to an account's voting power.
Get number of checkpoints for account
.
Get the address account
is currently delegating to.
Gets the current votes balance for account
.
account
address
The address to get votes balance
[0]
uint96
The number of current votes for account
Determine the prior number of votes for an account as of a block number.
Block number must be a finalized block or else this function will revert to prevent misinformation.
account
address
The address of the account to check
blockNumber
uint256
The block number to get the vote balance at
[0]
uint96
The number of votes the account had as of the given block
Retrieve the totalSupply
at the end of blockNumber
. Note, this value is the sum of all balances, but it is NOT the sum of all the delegated votes!
blockNumber
must have been already mined
blockNumber
uint256
The block number to get the total supply at
Change delegation for delegator
to delegatee
.
Moves voting power from one delegate to another
src
address
Address of old delegate
dst
address
Address of new delegate
amount
uint256
Voting power amount to transfer between delegates
Writes a new checkpoint based on operating last stored value with a delta
. Usually, said operation is the add
or subtract
functions from this contract, but more complex functions can be passed as parameters.
ckpts
uint128[]
The checkpoints array to use
op
function (uint256,uint256) view returns (uint256)
The function to apply over the last value and the delta
delta
uint256
Variation with respect to last stored value to be used for new checkpoint
Lookup a value in a list of (sorted) checkpoints.
ckpts
uint128[]
The checkpoints array to use
blockNumber
uint256
Block number when we want to get the checkpoint at
Maximum token supply. Defaults to type(uint96).max
(2^96 - 1)
Encodes a blockNumber
and value
into a single uint128
checkpoint.
blockNumber
is stored in the first 32 bits, while value
in the remaining 96 bits.
Decodes a block number from a uint128
checkpoint
.
Decodes a voting value from a uint128
checkpoint
.
Decodes a block number and voting value from a uint128
checkpoint
.
This is a space to consolidate all the DAO rules, guidelines and all the efforts we are leading to improve our ways of work
DAO rules were created with the inception of the DAO, and are mostly reflected in our forum, we refer as early rules to TIP-002, TIP-007, TIP-013, TIP-020, TIP-026 and TIP-032.
TIP-002, outlined by Matt Luongo, describes the creation of the DAO, the different bodies and the general ways we interact with each other.
TIP-007, outlined by Arj, describes the requirement of a minimum stake size for the Threshold Network stakers, at the moment of the network genesis.
TIP-013, outlined by Will, describes the creation of the DAO Guilds, and its inner workings.
TIP-020, outlined by Arj, describes the incentives for Threshold Network stakers at the interim era.
TIP-026, outlined by Will, outlines our governance processes, and creates a template to be followed when creating TIPs.
TIP-032, outlined by Arj, supersedes TIP-020 and establishes the reward allocation for stakers between the DAO products.
TIP-002
TIP-007
TIP-013
TIP-020
TIP-026
TIP-032
In 2022, the DAO lead an effort to improve our governance processes, leading to the creation and vote of several DAO rules. This endeavour was lead by the Rules Subcommittee, a group of 3 people volunteered from each of the guilds + the DAO PM. The outcome of this workgroup was the creation of TIP-031 and TIP-034.
TIP-031, outlined by the rules committee, establishes the rules for the DAO Guilds elections and management.
TIP-034, outlined by the rules committee, extends TIP-026 by providing a more defined view to the way proposals are created for the DAO, outlining best practices and guidelines.
GP-021, outlined by ZeroInFo, details the expansion of the Integrations Guild Committee, increasing 2 seats.
TIP-049, outlined by John Packel, describes the restructuring of the Marketing Guild Committee.
TIP-031
TIP-034
GP-021
TIP-049
TC-003, outlined by Luna5, outlines the alignment of the Council elections with the Guilds on the month of March, and removes the staggered elections for the Council.
Here you'll find the Sepolia testnet version of the Threshold dapp.
This page will show you how to launch a tBTC v2 node on the testnet.
This is a TESTNET guide document. Following this document will not result in a node enabling you to earn mainnet rewards.
While it is possible to run the client on a local machine, this is not recommended.
Your operating environment will ultimately dictate what machine type to go with. This is particularly relevant if you’re running a containerized solution where multiple applications are sharing VM resources. The below types are sufficient for running one instance of the tBTC v2 Node.
The preferred OS is Ubuntu.
AWS
c5.large
Azure
F2s v2
Google Cloud
n2-highcpu-2
Self-hosted
2 vCPU / 2 GB RAM / 1 GiB Persistent Storage
A Keep Node requires a connection to a WebSocket Ethereum API. You should obtain a WS API URL from a service provider (e.g. Alchemy, Infura, Ankr) or run your own Ethereum node (e.g. Geth).
The client requires an Ethereum Key File of an Operator Account to connect to the Ethereum chain. This account is created in a subsequent step using Geth (GoEthereum).
The Ethereum Key File is expected to be encrypted with a password. The password has to be provided in a prompt after the client starts or configured as a KEEP_ETHEREUM_PASSWORD
environment variable.
The Operator Account has to maintain a positive Ether balance at all times.
Please do NOT reuse an operator account that is being used for PRE or other applications.
To create a new Ethereum account, install Geth (GoEthereum) and create a new account using the command below. This account will subsequently be referred to as the Operator Account.
When prompted, provide a password to protect the operator key file.
Use a password manager to generate a strong password and store it safely. It will be needed again during setup.
Avoid passwords that contain the following characters: ', ", `, $ These characters may be interpreted as part of the configuration which can lead to undesirable outcomes that may be extremely time intensive to correct.
Once the process completes, your public key will be displayed. Take note of your Operator Account public key.
DO NOT LOSE THE PASSWORD TO THE OPERATOR ACCOUNT.
Your Operator Account will need to be funded with sepolia ETH and maintain a positive balance at all times to ensure proper operation and availability of your tBTC v2 node.
The node has to be accessible publicly to establish and maintain connections with bootstrap nodes and discovered peers.
Update firewall rules as necessary, including application level firewalls.
The node exposes metrics and diagnostics services for monitoring. A network port has to be exposed publicly, so the peers can connect to your node. A Diagnostics Port has to be exposed publicly, for the rewards allocation.
Network
network.port
TCP
3919
Status
clientInfo.port
TCP
9601
A Diagnostics Port has to be exposed publicly, for the rewards allocation.
An Announced Address is a layered addressing information (multiaddress
/multiaddr
) announced to the Threshold Network that is used by peers to connect with your node, e.g.: /dns4/bootstrap-0.test.keep.network/tcp/3919
or /ip4/104.154.61.116/tcp/3919
.
If the machine you’re running your node is not exposing a public IP (e.g. it is behind NAT) you should set the network.AnnouncedAddresses
(flag: --network.announcedAddresses
) configuration property to an addresses (ip4
or dns4
) under which your node is reachable for the public.
To read more about multiaddress
see the libp2p docummentation.
One important step to get your node operating on the Threshold Network is proper application authorization as well as operator account registration. Applications need only be authorized once.
It is CRITICALLY important that both the tBTC application as well as the Random Beacon applications are authorized. A node cannot be deployed without both applications being properly authorized.
Please note: by authorizing these applications, an unbonding period of 45 days will go into effect on the T you stake for these applications. This cool-down period begins the day you submit an unstake request.
To get started, visit the Threshold Dashboard and connect your wallet.
Click on "Configure Apps"
Select BOTH tBTC and Random Beacon applications and enter your desired amount of T to stake per application. Note that the minimum is 40,000T.
The operator account is the Ethereum account created on your node. In order for the network to associate your T stake with your node, you must register your Operator Address.
An Operator for the Provider registration can be submitted just once. The Operator address assignment cannot be updated.
After both applications have been authorized, click on "Start Mapping" to begin the Operator Registration process.
Enter your Operator Address in the field provided and click on "Map Address."
Once the steps above have been successfully completed, you are ready to move on to the next step in the node deployment process.
Don't forget: a tBTC v2 node will not be able to be deployed without successfully authorizing both the tBTC and Random Beacon applications, and registering the node's operator address FIRST.
The client requires two persistent directories. These directories will store configuration files and data generated and used by the client. It is highly recommended to create frequent backups of these directories. Loss of these data may be catastrophic and may lead to slashing.
It is crucial to ensure the data directory is persisted and backed up on a regular basis.
The tBTC v2 client will create two subdirectories within the storage directory: keystore
and work
. You do not need to create these.
The keystore
subdirectory contains sensitive key material data generated by the client. Loosing the keystore
data is a serious protocol offense and leads to slashing and potentially losing funds.
It is the operator’s responsibility to ensure the keystore data are not lost under any circumstances.
The work
directory contains data generated by the client that should persist the client restarts or relocations. If the work
data are lost the client will be able to recreate them, but it is inconvenient due to the time needed for the operation to complete and may lead to losing rewards.
Assuming Geth was installed for the root user with the command provided in the Operator Account creation step, the operator-key file should be located in the ~/operator-key
directory.
Contained within the operator-key
directory is the account key file (operator key file), its name will be similar to the following:
UTC--2018-11-01T06-23-57.810787758Z--fa3da235947aab49d439f3bcb46effd1a7237e32
copy (not move!) this account key file to the config
directory created above
Install or update Docker to the latest version. Visit the Official Docker website for detailed instructions. Use the command below to find your installed version if needed:
To launch the tBTC v2 client, several configuration flags and environmental values need to be set. For simplicity, a bash script can be used rather than typing or pasting all the flags into the console.
Create the launch script:
And paste the following:
Save and close the file, and make it executable:
To launch the tBTC v2 client, execute:
The --detach
property will prevent the status messages from the client to be printed to the console. Review the Docker logs for detailed status information.
The path shown in the example configuration will differ from yours. Make sure it is configured correctly.
Unless the --detach
flag was removed from the startup script, there will be no console output. In order to check your node, retrieve the Docker logs.
First, find your Docker instance identification, it'll be a random combination of words, e.g. stinky_brownie
:
Use your specific identification and substitute:
Scroll down about half a page, and you should see the following:
Congratulations, your node is up and running.
Abstract contract to handle governance parameters
Based on GovernorVotesQuorumFraction
, but without being opinionated on what's the source of voting power, and extended to handle proposal thresholds too. See OpenZeppelin's GovernorVotesQuorumFraction, GovernorVotes and GovernorSettings for reference.
Update the voting delay. This operation can only be performed through a governance proposal. Emits a VotingDelaySet
event.
Update the voting period. This operation can only be performed through a governance proposal. Emits a VotingPeriodSet
event.
Compute the required amount of voting power to reach quorum
Compute the required amount of voting power to create a proposal at the last block height
This function is implemented to comply with Governor API but we we will actually use proposalThreshold(uint256 blockNumber)
, as in our DAOs the threshold amount changes according to supply.
Compute the required amount of voting power to create a proposal
module:user-config
Delay, in number of block, between the proposal is created and the vote starts. This can be increassed to leave time for users to buy voting power, of delegate it, before the voting of a proposal starts.
module:user-config
Delay, in number of blocks, between the vote start and vote ends.
NOTE: The {votingDelay} can delay the start of the vote. This must be considered when setting the voting duration compared to the voting delay.
Compute the past total voting power at a particular block
Review available CLI Options below.
The staking contract enables T owners to have their wallets offline and their stake managed by staking providers on their behalf. The staking contract does not define operator role. The operator responsible for running off-chain client software is appointed by the staking provider in the particular application utilizing the staking contract. All off-chain client software should be able to run without exposing operator's or staking provider’s private key and should not require any owner’s keys at all. The stake delegation optimizes the network throughput without compromising the security of the owners’ stake.
Creates a delegation with msg.sender
owner with the given staking provider, beneficiary, and authorizer. Transfers the given amount of T to the staking contract.
The owner of the delegation needs to have the amount approved to transfer to the staking contract.
Copies delegation from the legacy KEEP staking contract to T staking contract. No tokens are transferred. Caches the active stake amount from KEEP staking contract. Can be called by anyone.
The staking provider in T staking contract is the legacy KEEP staking contract operator.
Copies delegation from the legacy NU staking contract to T staking contract, additionally appointing staking provider, beneficiary and authorizer roles. Caches the amount staked in NU staking contract. Can be called only by the original delegation owner.
Allows the Governance to set the minimum required stake amount. This amount is required to protect against griefing the staking contract and individual applications are allowed to require higher minimum stakes if necessary.
Allows the Governance to approve the particular application before individual stake authorizers are able to authorize it.
Increases the authorization of the given staking provider for the given application by the given amount. Can only be called by the authorizer for that staking provider.
Calls authorizationIncreased(address stakingProvider, uint256 amount)
on the given application to notify the application about authorization change. See IApplication
.
Requests decrease of the authorization for the given staking provider on the given application by the provided amount. It may not change the authorized amount immediatelly. When it happens depends on the application. Can only be called by the given staking provider’s authorizer. Overwrites pending authorization decrease for the given staking provider and application if the application agrees for that. If the application does not agree for overwriting, the function reverts.
Calls authorizationDecreaseRequested(address stakingProvider, uint256 amount)
on the given application. See IApplication
.
Requests decrease of all authorizations for the given staking provider on all applications by all authorized amount. It may not change the authorized amount immediatelly. When it happens depends on the application. Can only be called by the given staking provider’s authorizer. Overwrites pending authorization decrease for the given staking provider and application.
Calls authorizationDecreaseRequested(address stakingProvider, uint256 amount)
for each authorized application. See IApplication
.
Called by the application at its discretion to approve the previously requested authorization decrease request. Can only be called by the application that was previously requested to decrease the authorization for that staking provider. Returns resulting authorized amount for the application.
Decreases the authorization for the given stakingProvider
on the given disabled application
, for all authorized amount. Can be called by anyone.
Pauses the given application’s eligibility to slash stakes. Besides that stakers can't change authorization to the application. Can be called only by the Panic Button of the particular application. The paused application can not slash stakes until it is approved again by the Governance using approveApplication
function. Should be used only in case of an emergency.
Disables the given application. The disabled application can't slash stakers. Also stakers can't increase authorization to that application but can decrease without waiting by calling requestAuthorizationDecrease
at any moment. Can be called only by the governance. The disabled application can't be approved again. Should be used only in case of an emergency.
Sets the Panic Button role for the given application to the provided address. Can only be called by the Governance. If the Panic Button for the given application should be disabled, the role address should be set to 0x0 address.
Sets the maximum number of applications one staking provider can have authorized. Used to protect against DoSing slashing queue. Can only be called by the Governance.
Increases the amount of the stake for the given staking provider.
The sender of this transaction needs to have the amount approved to transfer to the staking contract.
Propagates information about stake top-up from the legacy KEEP staking contract to T staking contract. Can be called only by the owner or the staking provider.
Propagates information about stake top-up from the legacy NU staking contract to T staking contract. Can be called only by the owner or the staking provider.
Reduces the liquid T stake amount by the provided amount and withdraws T to the owner. Reverts if there is at least one authorization higher than the sum of the legacy stake and remaining liquid T stake or if the unstake amount is higher than the liquid T stake amount. Can be called only by the delegation owner or the staking provider.
Sets the legacy KEEP staking contract active stake amount cached in T staking contract to 0. Reverts if the amount of liquid T staked in T staking contract is lower than the highest application authorization. This function allows to unstake from KEEP staking contract and still being able to operate in T network and earning rewards based on the liquid T staked. Can be called only by the delegation owner or the staking provider.
Reduces cached legacy NU stake amount by the provided amount. Reverts if there is at least one authorization higher than the sum of remaining legacy NU stake and liquid T stake for that staking provider or if the untaked amount is higher than the cached legacy stake amount. If succeeded, the legacy NU stake can be partially or fully undelegated on the legacy staking contract. This function allows to unstake from NU staking contract and still being able to operate in T network and earning rewards based on the liquid T staked. Can be called only by the delegation owner or the staking provider.
Sets cached legacy stake amount to 0, sets the liquid T stake amount to 0 and withdraws all liquid T from the stake to the owner. Reverts if there is at least one non-zero authorization. Can be called only by the delegation owner or the staking provider.
Notifies about the discrepancy between legacy KEEP active stake and the amount cached in T staking contract. Slashes the staking provider in case the amount cached is higher than the actual active stake amount in KEEP staking contract. Needs to update authorizations of all affected applications and execute an involuntary allocation decrease on all affected applications. Can be called by anyone, notifier receives a reward.
Notifies about the discrepancy between legacy NU active stake and the amount cached in T staking contract. Slashes the staking provider in case the amount cached is higher than the actual active stake amount in NU staking contract. Needs to update authorizations of all affected applications and execute an involuntary allocation decrease on all affected applications. Can be called by anyone, notifier receives a reward.
Sets the penalty amount for stake discrepancy and reward multiplier for reporting it. The penalty is seized from the delegated stake, and 5% of the penalty, scaled by the multiplier, is given to the notifier. The rest of the tokens are burned. Can only be called by the Governance. See seize
function.
Sets reward in T tokens for notification of misbehaviour of one staking provider. Can only be called by the governance.
Transfer some amount of T tokens as reward for notifications of misbehaviour
Withdraw some amount of T tokens from notifiers treasury. Can only be called by the governance.
Adds staking providers to the slashing queue along with the amount that should be slashed from each one of them. Can only be called by application authorized for all staking providers in the array.
Adds staking providers to the slashing queue along with the amount. The notifier will receive reward per each staking provider from notifiers treasury. Can only be called by application authorized for all staking providers in the array.
Takes the given number of queued slashing operations and processes them. Receives 5% of the slashed amount. Executes involuntaryAllocationDecrease
function on each affected application.
Returns the authorized stake amount of the staking provider for the application.
Returns staked amount of T, Keep and Nu for the specified staking provider.
All values are in T denomination
Returns start staking timestamp.
This value is set at most once.
Returns staked amount of NU for the specified staking provider.
Gets the stake owner, the beneficiary and the authorizer for the specified staking provider address.
Returns length of application array
Returns length of slashing queue
Returns minimum possible stake for T, KEEP or NU in T denomination.
For example, suppose the given staking provider has 10 T, 20 T worth of KEEP, and 30 T worth of NU all staked, and the maximum application authorization is 40 T, then getMinStaked
for that staking provider returns:
0 T if KEEP stake type specified i.e. min = 40 T max - (10 T + 30 T worth of NU) = 0 T
10 T if NU stake type specified i.e. min = 40 T max - (10 T + 20 T worth of KEEP) = 10 T
0 T if T stake type specified i.e. min = 40 T max - (20 T worth of KEEP + 30 T worth of NU) < 0 T In other words, the minimum stake amount for the specified stake type is the minimum amount of stake of the given type needed to satisfy the maximum application authorization given the staked amounts of the other stake types for that staking provider.
Returns available amount to authorize for the specified application
You can learn about APIs of contracts related to the DAO under the following links:
Interface for Keep TokenStaking contract
Seize provided token amount from every member in the misbehaved operators array. The tattletale is rewarded with 5% of the total seized amount scaled by the reward adjustment parameter and the rest 95% is burned.
Gets stake delegation info for the given operator.
Gets the stake owner for the specified operator address.
Gets the beneficiary for the specified operator address.
Gets the authorizer for the specified operator address.
Gets the eligible stake balance of the specified address. An eligible stake is a stake that passed the initialization period and is not currently undelegating. Also, the operator had to approve the specified operator contract.
Operator with a minimum required amount of eligible stake can join the network and participate in new work selection.
Interface for NuCypher StakingEscrow contract
Slash the staker's stake and reward the investigator
Request merge between NuCypher staking contract and T staking contract. Returns amount of staked tokens
Get all tokens belonging to the staker
blockNumber
uint256
The block number to get the quorum at
blockNumber
uint256
The block number to get the proposal threshold at
blockNumber
uint256
The block number to get the vote power at
owner
address
Stake owner address.
beneficiary
address payable
Beneficiary address.
authorizer
address
Authorizer address.
amountToSeize
uint256
Token amount to seize from every misbehaved operator.
rewardMultiplier
uint256
Reward adjustment in percentage. Min 1% and 100% max.
tattletale
address
Address to receive the 5% reward.
misbehavedOperators
address[]
Array of addresses to seize the tokens from.
operator
address
Operator address.
amount
uint256
The amount of tokens the given operator delegated.
createdAt
uint256
The time when the stake has been delegated.
undelegatedAt
uint256
The time when undelegation has been requested. If undelegation has not been requested, 0 is returned.
[0]
address
Stake owner address.
[0]
address payable
Beneficiary address.
[0]
address
Authorizer address.
operator
address
address of stake operator.
operatorContract
address
address of operator contract.
balance
uint256
an uint256 representing the eligible stake balance.
staker
address
Staker's address
penalty
uint256
Penalty
investigator
address
Investigator
reward
uint256
Reward for the investigator
Returns the address of the entity that acts as governance for this contract.
By default, Governor assumes this is either the Governor contract itself, or a timelock if there's one configured. We override this here for the StakerGovernor contract so it's the Tokenholder DAO's Timelock, which we obtain at constructor time.
A wrapper around OpenZeppelin's SafeERC20Upgradeable
but specific to the T token. Use this library in upgradeable contracts. If your contract is non-upgradeable, then the traditional SafeERC20
works. The motivation is to prevent upgradeable contracts that use T from depending on the Address
library, which can be problematic since it uses delegatecall
, which is discouraged by OpenZeppelin for use in upgradeable contracts.
This implementation force-casts T to IERC20Upgradeable
to make it work with SafeERC20Upgradeable
.
T network staking contract supports existing KEEP stakes by allowing KEEP stakers to use their stakes in T network and weights them based on KEEP<>T token ratio. KEEP stake owner is cached in T staking contract and used to restrict access to all functions only owner or operator should call. To cache KEEP stake owner in T staking contract, T staking contract first needs to resolve the owner.
Resolving liquid KEEP stake owner is easy. Resolving token grant stake owner is complicated and not possible to do on-chain from a contract external to KEEP TokenStaking contract. Keep TokenStaking knows the grant ID but does not expose it externally.
KeepStake contract addresses this problem by exposing operator-owner mappings snapshotted off-chain based on events and information publicly available from KEEP TokenStaking contract and KEEP TokenGrant contract. Additionally, it gives the Governance ability to add new mappings in case they are ever needed; in practice, this will be needed only if someone decides to stake their KEEP token grant in KEEP network after 2021-11-11 when the snapshot was taken.
Operator-owner pairs were snapshotted 2021-11-11 in the following way:
Fetch all TokenStaking events from KEEP staking contract.
Filter out undelegated operators.
Filter out canceled delegations.
Fetch grant stake information from KEEP TokenGrant for that operator to determine if we are dealing with grant delegation.
Fetch grantee address from KEEP TokenGrant contract.
Check if we are dealing with ManagedGrant by looking for all created ManagedGrants and comparing their address against grantee address fetched from TokenGrant contract.
Allows the Governance to set new operator-managed grant pair. This function should only be called for managed grants if the snapshot does include this pair.
Allows the Governance to set new operator-grantee pair. This function should only be called for non-managed grants if the snapshot does include this pair.
Resolves KEEP stake owner for the provided operator address. Reverts if could not resolve the owner.
Based on ProxyAdmin
, an auxiliary contract in OpenZeppelin's upgradeability approach meant to act as the admin of a TransparentUpgradeableProxy
. This variant allows an additional actor, the "deputy", to perform upgrades, which originally can only be performed by the ProxyAdmin's owner. See OpenZeppelin's documentation for TransparentUpgradeableProxy
for more details on why a ProxyAdmin is recommended.
Upgrades proxy
to implementation
. This contract must be the admin of proxy
, and the caller must be this contract's owner or the deputy.
Upgrades proxy
to implementation
and calls a function on the new implementation. This contract must be the admin of proxy
, and the caller must be this contract's owner or the deputy.
Staker DAO voting power extraction from staked T positions,
Read the voting weight from the snapshot mechanism in the T staking contracts. Note that this also tracks legacy stakes (NU/KEEP).
See {IGovernor-getVotes}
account
address
Delegate account with T staking voting power
blockNumber
uint256
The block number to get the vote balance at
Compute the total voting power for the Staker DAO.
blockNumber
uint256
The block number to get the voting power at
Threshold Network T token
By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it requires users to delegate to themselves to activate checkpoints and have their voting power tracked.
The EIP-712 typehash for the delegation struct used by delegateBySig
.
Delegates votes from signatory to delegatee
signatory
address
delegatee
address
The address to delegate votes to
deadline
uint256
The time at which to expire the signature
v
uint8
The recovery byte of the signature
r
bytes32
Half of the ECDSA signature pair
s
bytes32
Half of the ECDSA signature pair
Delegate votes from msg.sender
to delegatee
.
delegatee
address
The address to delegate votes to
Hook that is called before any transfer of tokens. This includes minting and burning.
Calling conditions:
when from
and to
are both non-zero, amount
of from
's tokens will be to transferred to to
.
when from
is zero, amount
tokens will be minted for to
.
when to
is zero, amount
of from
's tokens will be burned.
from
and to
are never both zero.
Change delegation for delegator
to delegatee
.
You can learn about APIs of contracts related to the Random Beacon under the following links:
This file documents a contract which is not yet deployed to Mainnet.
Size of a group in the threshold relay.
Time in blocks after which DKG result is complete and ready to be
Initializes SortitionPool and DKGValidator addresses. Can be performed only once.
Determines the current state of group creation. It doesn't take timeouts into consideration. The timeouts should be tracked and notified separately.
Locks the sortition pool and starts awaiting for the group creation seed.
Allows to submit a DKG result. The submitted result does not go through a validation and before it gets accepted, it needs to wait through the challenge period during which everyone has a chance to challenge the result as invalid one. Submitter of the result needs to be in the sortition pool and if the result gets challenged, the submitter will get slashed.
Checks if DKG timed out. The DKG timeout period includes time required for off-chain protocol execution and time for the result publication. After this time a result cannot be submitted and DKG can be notified about the timeout. DKG period is adjusted by result submission offset that include blocks that were mined while invalid result has been registered until it got challenged.
Notifies about DKG timeout.
Notifies about the seed was not delivered and restores the initial DKG state (IDLE).
Approves DKG result. Can be called when the challenge period for the submitted result is finished. Considers the submitted result as valid. For the first submitterPrecedencePeriodLength
blocks after the end of the challenge period can be called only by the DKG result submitter. After that time, can be called by anyone.
Can be called after a challenge period for the submitted result.
Challenges DKG result. If the submitted result is proved to be invalid it reverts the DKG back to the result submission phase.
Can be called during a challenge period for the submitted result.
Due to EIP150, 1/64 of the gas is not forwarded to the call, and will be kept to execute the remaining operations in the function after the call inside the try-catch.
To ensure there is no way for the caller to manipulate gas limit in such a way that the call inside try-catch fails with out-of-gas and the rest of the function is executed with the remaining 1/64 of gas, we require an extra gas amount to be left at the end of the call to the function challenging DKG result and wrapping the call to BeaconDkgValidator and TokenStaking contracts inside a try-catch.
Updates DKG-related parameters
Completes DKG by cleaning up state.
Should be called after DKG times out or a result is approved.
This file documents a contract which is not yet deployed to Mainnet.
Library managing the state of stake authorizations for the operator contract and the presence of operators in the sortition pool based on the stake authorized for them.
Updates authorization-related parameters.
Used by staking provider to set operator address that will operate a node. The given staking provider can set operator address only one time. The operator address can not be changed and must be unique. Reverts if the operator is already set for the staking provider or if the operator address is already in use. Reverts if there is a pending authorization decrease for the staking provider.
Used by T staking contract to inform the beacon that the authorized stake amount for the given staking provider increased.
Reverts if the authorization amount is below the minimum.
The function is not updating the sortition pool. Sortition pool state needs to be updated by the operator with a call to joinSortitionPool
or updateOperatorStatus
.
Should only be callable by T staking contract.
Used by T staking contract to inform the beacon that the authorization decrease for the given staking provider has been requested.
Reverts if the amount after deauthorization would be non-zero and lower than the minimum authorization.
Reverts if another authorization decrease request is pending for the staking provider and not enough time passed since the original request (see authorizationDecreaseChangePeriod
).
If the operator is not known (registerOperator
was not called) it lets to approveAuthorizationDecrease
immediately. If the operator is known (registerOperator
was called), the operator needs to update state of the sortition pool with a call to joinSortitionPool
or updateOperatorStatus
. After the sortition pool state is in sync, authorization decrease delay starts.
After authorization decrease delay passes, authorization decrease request needs to be approved with a call to approveAuthorizationDecrease
function.
If there is a pending authorization decrease request, it is overwritten, but only if enough time passed since the original request. Otherwise, the function reverts.
Should only be callable by T staking contract.
Approves the previously registered authorization decrease request. Reverts if authorization decrease delay have not passed yet or if the authorization decrease was not requested for the given staking provider.
Used by T staking contract to inform the beacon the authorization has been decreased for the given staking provider involuntarily, as a result of slashing.
If the operator is not known (registerOperator
was not called) the function does nothing. The operator was never in a sortition pool so there is nothing to update.
If the operator is known, sortition pool is unlocked, and the operator is in the sortition pool, the sortition pool state is updated. If the sortition pool is locked, update needs to be postponed. Every other staker is incentivized to call updateOperatorStatus
for the problematic operator to increase their own rewards in the pool.
Should only be callable by T staking contract.
Lets the operator join the sortition pool. The operator address must be known - before calling this function, it has to be appointed by the staking provider by calling registerOperator
. Also, the operator must have the minimum authorization required by the beacon. Function reverts if there is no minimum stake authorized or if the operator is not known. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay.
Updates status of the operator in the sortition pool. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay. Function reverts if the operator is not known.
Checks if the operator's authorized stake is in sync with operator's weight in the sortition pool. If the operator is not in the sortition pool and their authorized stake is non-zero, function returns false.
Returns the current value of the staking provider's eligible stake. Eligible stake is defined as the currently authorized stake minus the pending authorization decrease. Eligible stake is what is used for operator's weight in the pool. If the authorized stake minus the pending authorization decrease is below the minimum authorization, eligible stake is 0.
This function can be exposed to the public in contrast to the second variant accepting decreasingBy
as a parameter.
Returns the current value of the staking provider's eligible stake. Eligible stake is defined as the currently authorized stake minus the pending authorization decrease. Eligible stake is what is used for operator's weight in the pool. If the authorized stake minus the pending authorization decrease is below the minimum authorization, eligible stake is 0.
This function is not intended to be exposes to the public. decreasingBy
must be fetched from pendingDecreases
mapping and it is passed as a parameter to optimize gas usage of functions that call eligibleStake
and need to use AuthorizationDecrease
fetched from pendingDecreases
for some additional logic.
Returns the amount of stake that is pending authorization decrease for the given staking provider. If no authorization decrease has been requested, returns zero.
Returns the remaining time in seconds that needs to pass before the requested authorization decrease can be approved. If the sortition pool state was not updated yet by the operator after requesting the authorization decrease, returns type(uint64).max
.
Tokenholder DAO voting power extraction from both liquid and staked T token positions, including legacy stakes (NU/KEEP).
Read the voting weight from the snapshot mechanism in the token and staking contracts. For Tokenholder DAO, there are currently two voting power sources:
Liquid T, tracked by the T token contract
Stakes in the T network, tracked by the T staking contract. Note that this also tracks legacy stakes (NU/KEEP); legacy stakes count for tokenholders' voting power, but not for the total voting power of the Tokenholder DAO (see {_getPastTotalSupply}).
See {IGovernor-getVotes}
Compute the total voting power for Tokenholder DAO. Note how it only uses the token total supply as source, as native T tokens that are staked continue existing, but as deposits in the staking contract. However, legacy stakes can't contribute to the total voting power as they're already implicitly counted as part of Vending Machines' liquid balance; hence, we only need to read total voting power from the token.
TokenStaking is the main staking contract of the Threshold Network. Apart from the basic usage of enabling T stakes, it also acts as a sort of "meta-staking" contract, accepting existing legacy NU/KEEP stakes. Additionally, it serves as application manager for the apps that run on the Threshold Network. Note that legacy NU/KEEP staking contracts see TokenStaking as an application (e.g., slashing is requested by TokenStaking and performed by the legacy contracts).
TokenStaking is upgradeable, using OpenZeppelin's Upgradeability framework. As such, it is required to satisfy OZ's guidelines, like restrictions on constructors, immutable variables, base contracts and libraries. See https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable
Creates a delegation with msg.sender
owner with the given staking provider, beneficiary, and authorizer. Transfers the given amount of T to the staking contract.
The owner of the delegation needs to have the amount approved to transfer to the staking contract.
Copies delegation from the legacy KEEP staking contract to T staking contract. No tokens are transferred. Caches the active stake amount from KEEP staking contract. Can be called by anyone.
The staking provider in T staking contract is the legacy KEEP staking contract operator.
Copies delegation from the legacy NU staking contract to T staking contract, additionally appointing beneficiary and authorizer roles. Caches the amount staked in NU staking contract. Can be called only by the original delegation owner.
Allows the Governance to set the minimum required stake amount. This amount is required to protect against griefing the staking contract and individual applications are allowed to require higher minimum stakes if necessary.
Staking providers are not required to maintain a minimum T stake all the time. 24 hours after the delegation, T stake can be reduced below the minimum stake. The minimum stake in the staking contract is just to protect against griefing stake operation. Please note that each application may have its own minimum authorization though and the authorization can not be higher than the stake.
Allows the Governance to approve the particular application before individual stake authorizers are able to authorize it.
Increases the authorization of the given staking provider for the given application by the given amount. Can only be called by the given staking provider’s authorizer.
Calls authorizationIncreased
callback on the given application to notify the application about authorization change. See IApplication
.
Requests decrease of all authorizations for the given staking provider on all applications by all authorized amount. It may not change the authorized amount immediatelly. When it happens depends on the application. Can only be called by the given staking provider’s authorizer. Overwrites pending authorization decrease for the given staking provider and application.
Calls authorizationDecreaseRequested
callback for each authorized application. See IApplication
.
Called by the application at its discretion to approve the previously requested authorization decrease request. Can only be called by the application that was previously requested to decrease the authorization for that staking provider. Returns resulting authorized amount for the application.
Decreases the authorization for the given stakingProvider
on the given disabled application
, for all authorized amount. Can be called by anyone.
Pauses the given application’s eligibility to slash stakes. Besides that stakers can't change authorization to the application. Can be called only by the Panic Button of the particular application. The paused application can not slash stakes until it is approved again by the Governance using approveApplication
function. Should be used only in case of an emergency.
Disables the given application. The disabled application can't slash stakers. Also stakers can't increase authorization to that application but can decrease without waiting by calling forceDecreaseAuthorization
at any moment. Can be called only by the governance. The disabled application can't be approved again. Should be used only in case of an emergency.
Sets the Panic Button role for the given application to the provided address. Can only be called by the Governance. If the Panic Button for the given application should be disabled, the role address should be set to 0x0 address.
Sets the maximum number of applications one staking provider can have authorized. Used to protect against DoSing slashing queue. Can only be called by the Governance.
Increases the amount of the stake for the given staking provider.
The sender of this transaction needs to have the amount approved to transfer to the staking contract.
Propagates information about stake top-up from the legacy KEEP staking contract to T staking contract. Can be called only by the owner or the staking provider.
Propagates information about stake top-up from the legacy NU staking contract to T staking contract. Can be called only by the owner or the staking provider.
Reduces the liquid T stake amount by the provided amount and withdraws T to the owner. Reverts if there is at least one authorization higher than the sum of the legacy stake and remaining liquid T stake or if the unstake amount is higher than the liquid T stake amount. Can be called only by the owner or the staking provider. Can only be called when 24h passed since the stake has been delegated.
Sets the legacy KEEP staking contract active stake amount cached in T staking contract to 0. Reverts if the amount of liquid T staked in T staking contract is lower than the highest application authorization. This function allows to unstake from KEEP staking contract and still being able to operate in T network and earning rewards based on the liquid T staked. Can be called only by the delegation owner or the staking provider. Can only be called when 24h passed since the stake has been delegated.
This function (or unstakeAll
) must be called before undelegate
/undelegateAt
in Keep staking contract. Otherwise provider can be slashed by notifyKeepStakeDiscrepancy
method.
Reduces cached legacy NU stake amount by the provided amount. Reverts if there is at least one authorization higher than the sum of remaining legacy NU stake and liquid T stake for that staking provider or if the untaked amount is higher than the cached legacy stake amount. If succeeded, the legacy NU stake can be partially or fully undelegated on the legacy staking contract. This function allows to unstake from NU staking contract and still being able to operate in T network and earning rewards based on the liquid T staked. Can be called only by the delegation owner or the staking provider. Can only be called when 24h passed since the stake has been delegated.
This function (or unstakeAll
) must be called before withdraw
in NuCypher staking contract. Otherwise NU tokens can't be unlocked.
Sets cached legacy stake amount to 0, sets the liquid T stake amount to 0 and withdraws all liquid T from the stake to the owner. Reverts if there is at least one non-zero authorization. Can be called only by the delegation owner or the staking provider. Can only be called when 24h passed since the stake has been delegated.
Notifies about the discrepancy between legacy KEEP active stake and the amount cached in T staking contract. Slashes the staking provider in case the amount cached is higher than the actual active stake amount in KEEP staking contract. Needs to update authorizations of all affected applications and execute an involuntary authorization decrease on all affected applications. Can be called by anyone, notifier receives a reward.
Notifies about the discrepancy between legacy NU active stake and the amount cached in T staking contract. Slashes the staking provider in case the amount cached is higher than the actual active stake amount in NU staking contract. Needs to update authorizations of all affected applications and execute an involuntary authorization decrease on all affected applications. Can be called by anyone, notifier receives a reward.
Real discrepancy between T and Nu is impossible. This method is a safeguard in case of bugs in NuCypher staking contract
Sets the penalty amount for stake discrepancy and reward multiplier for reporting it. The penalty is seized from the delegated stake, and 5% of the penalty, scaled by the multiplier, is given to the notifier. The rest of the tokens are burned. Can only be called by the Governance. See seize
function.
Sets reward in T tokens for notification of misbehaviour of one staking provider. Can only be called by the governance.
Transfer some amount of T tokens as reward for notifications of misbehaviour
Withdraw some amount of T tokens from notifiers treasury. Can only be called by the governance.
Adds staking providers to the slashing queue along with the amount that should be slashed from each one of them. Can only be called by application authorized for all staking providers in the array.
This method doesn't emit events for providers that are added to the queue. If necessary events can be added to the application level.
Adds staking providers to the slashing queue along with the amount. The notifier will receive reward per each provider from notifiers treasury. Can only be called by application authorized for all staking providers in the array.
This method doesn't emit events for staking providers that are added to the queue. If necessary events can be added to the application level.
Takes the given number of queued slashing operations and processes them. Receives 5% of the slashed amount. Executes involuntaryAuthorizationDecrease
function on each affected application.
Delegate voting power from the stake associated to the stakingProvider
to a delegatee
address. Caller must be the owner of this stake.
Transfers ownership of the contract to newGuvnor
.
Returns the authorized stake amount of the staking provider for the application.
Returns staked amount of T, Keep and Nu for the specified staking provider.
All values are in T denomination
Returns start staking timestamp.
This value is set at most once.
Returns staked amount of NU for the specified staking provider.
Gets the stake owner, the beneficiary and the authorizer for the specified staking provider address.
Returns length of application array
Returns length of slashing queue
Requests decrease of the authorization for the given staking provider on the given application by the provided amount. It may not change the authorized amount immediatelly. When it happens depends on the application. Can only be called by the given staking provider’s authorizer. Overwrites pending authorization decrease for the given staking provider and application if the application agrees for that. If the application does not agree for overwriting, the function reverts.
Calls authorizationDecreaseRequested
callback on the given application. See IApplication
.
Returns minimum possible stake for T, KEEP or NU in T denomination
For example, suppose the given staking provider has 10 T, 20 T worth of KEEP, and 30 T worth of NU all staked, and the maximum application authorization is 40 T, then getMinStaked
for that staking provider returns:
0 T if KEEP stake type specified i.e. min = 40 T max - (10 T + 30 T worth of NU) = 0 T
10 T if NU stake type specified i.e. min = 40 T max - (10 T + 20 T worth of KEEP) = 10 T
0 T if T stake type specified i.e. min = 40 T max - (20 T worth of KEEP + 30 T worth of NU) < 0 T In other words, the minimum stake amount for the specified stake type is the minimum amount of stake of the given type needed to satisfy the maximum application authorization given the staked amounts of the other stake types for that staking provider.
Returns available amount to authorize for the specified application.
Delegate voting power from the stake associated to the stakingProvider
to a delegatee
address. Caller must be the owner of this stake.
Original abstract function defined in Checkpoints contract had two parameters, delegator
and delegatee
. Here we override it and comply with the same signature but the semantics of the first parameter changes to the stakingProvider
address.
Adds staking providers to the slashing queue along with the amount. The notifier will receive reward per each staking provider from notifiers treasury. Can only be called by application authorized for all staking providers in the array.
Processes one specified slashing event. Executes involuntaryAuthorizationDecrease
function on each affected application.
Synchronize authorizations (if needed) after slashing stake
Convert amount from T to Keep and call seize
in Keep staking contract. Returns remainder of slashing amount in T
Note this internal function doesn't update stake checkpoints
Convert amount from T to NU and call slashStaker
in NuCypher staking contract. Returns remainder of slashing amount in T
Note this internal function doesn't update the stake checkpoints
Removes application with zero authorization from authorized applications array
Creates new checkpoints due to a change of stake amount
Creates new checkpoints due to an increment of a stakers' stake
Creates new checkpoints due to a decrease of a stakers' stake
Returns amount of Nu stake in the NuCypher staking contract for the specified staking provider. Resulting value in T denomination
Returns amount of Keep stake in the Keep staking contract for the specified staking provider. Resulting value in T denomination
Returns the T token amount that's obtained from amount
legacy tokens for the given ratio
, and the remainder that can't be converted.
Returns the amount of legacy tokens that's obtained from tAmount
T tokens for the given ratio
, and the T remainder that can't be converted.
Mechanisms to keep thUSD solvent under changing collateral price
The Stability Pool is the first line of defense in maintaining system solvency. It achieves that by acting as the source of liquidity to repay debt from liquidated Vaults—ensuring that the total thUSD supply always remains backed.
When any Vault is liquidated, an amount of thUSD corresponding to the remaining debt of the Vault is burned from the Stability Pool’s balance to repay its debt. In exchange, the entire collateral from the Vault is transferred to the Stability Pool.
The Stability Pool is funded by users transferring thUSD into it (called Stability Providers). Over time Stability Providers lose a pro-rata share of their thUSD deposits, while gaining a pro-rata share of the liquidated collateral. However, because Vaults are likely to be liquidated at just below 110% collateral ratios, it is expected that Stability Providers will receive a greater dollar-value of collateral relative to the debt they pay off.
Stability Pool Providers will make liquidation gains.
To ensure that the entire Stablecoin supply remains fully backed by collateral, Vaults that fall under the minimum collateral ratio of 110% will be closed (liquidated).
The debt of the Vault is canceled and absorbed by the Stability Pool and its collateral distributed among Stability Providers.
The owner of the Vault still keeps the full amount of thUSD borrowed but loses ~10% value overall hence it is critical to always keep the ratio above 110%, ideally above 150%.
Anybody can liquidate a Vault as soon as it drops below the Minimum Collateral Ratio of 110%. The initiator receives a gas compensation (200 thUSD + 0.5% of the Vaults collateral) as reward for this service.
The liquidation of Vaults is connected with certain gas costs which the initiator has to cover. The cost per Vault was reduced by implementing batch liquidations of up to 160 - 185 Vaults but with the aim of ensuring that liquidations remain profitable even in times of soaring gas prices the protocol offers a gas compensation given by the following formula:
gas compensation = 200 thUSD + 0.5% of Vault's collateral (ETH)
The 200 thUSD is funded by a Liquidation Reserve while the variable 0.5% part (in tBTC) comes from the liquidated collateral, slightly reducing the liquidation gain for Stability Providers.
As liquidations happen just below a collateral ratio of 110%, you will most likely experience a net gain whenever a Vault is liquidated.
Let’s say there is a total of 1,000,000 thUSD in the Stability Pool and your deposit is 100,000 thUSD.
Now, a Vault with debt of 200,000 thUSD and collateral of 10.9 tBTCis liquidated at a tBTC price of $20,000, and thus at a collateral ratio of 109% (= 100% * (10.9 * 20,000) / 200,000). Given that your pool share is 10%, your deposit will go down by 10% of the liquidated debt (20,000 thUSD), i.e. from 100,000 to 80,000 thUSD. In return, you will gain 10% of the liquidated collateral, i.e. 1.09 tBTC, which is currently worth $21,800. Your net gain from the liquidation is $1,800.
Note that depositors can immediately withdraw the collateral received from liquidations and sell it to reduce their exposure to tBTC, if the USD value of tBTC is expected to decrease (for an exception see the next section).
As a general rule, you can withdraw the deposit made to the Stability Pool at any time. There is no minimum lockup duration. However, withdrawals are temporarily suspended whenever there are liquidatable Vault with a collateral ratio below 110% that have not been liquidated yet.
Chainlink price has not been updated for more than 4 hours
Chainlink response call reverts, returns an invalid price or an invalid timestamp
The price change between two consecutive Chainlink price updates is >50%.
While liquidations will occur at a collateral ratio well above 100% most of the time, it is theoretically possible that a Vault gets liquidated below 100% in a flash crash or due to an oracle failure. In such a case, you may experience a loss since the collateral gain will be smaller than the reduction of your deposit.
If thUSD is trading above $1, liquidations may become unprofitable for Stability Providers even at collateral ratios higher than 100%. However, this loss is hypothetical since thUSD is expected to return to the peg, so the “loss” only materializes if you had withdrawn your deposit and sold the thUSD at a price above $1.
Please note that although the system is diligently audited, a hack or a bug that results in losses for the users can never be fully excluded.
If the Stability Pool is empty, the system uses a secondary liquidation mechanism called redistribution. In such a case, the system redistributes the debt and collateral from liquidated Vaults to all other existing Vaults. The redistribution of debt and collateral is done in proportion to the recipient Vault's collateral amount.
To get familiarized with Random Bitcoin contracts API, go .
The protocol uses price feed, falling back to the tBTC:USD oracle under the following (extreme) conditions:
self
struct BeaconDkg.Data
_sortitionPool
contract SortitionPool
Sortition Pool reference
_dkgValidator
contract BeaconDkgValidator
DKGValidator reference
[0]
bool
True if DKG timed out, false otherwise.
self
struct BeaconDkg.Data
result
struct BeaconDkg.Result
Result to approve. Must match the submitted result stored during submitResult
.
misbehavedMembers
uint32[]
Identifiers of members who misbehaved during DKG.
self
struct BeaconDkg.Data
result
struct BeaconDkg.Result
Result to challenge. Must match the submitted result stored during submitResult
.
maliciousResultHash
bytes32
Hash of the malicious result.
maliciousSubmitter
uint32
Identifier of the malicious submitter.
self
struct BeaconDkg.Data
_resultChallengePeriodLength
uint256
New value of the result challenge period length. It is the number of blocks for which a DKG result can be challenged.
_resultChallengeExtraGas
uint256
New value of the result challenge extra gas. It is the extra gas required to be left at the end of the challenge DKG result transaction.
_resultSubmissionTimeout
uint256
New value of the result submission timeout in seconds. It is a timeout for a group to provide a DKG result.
_submitterPrecedencePeriodLength
uint256
New value of the submitter precedence period length in blocks. It is the time during which only the original DKG result submitter can approve it.
self
struct BeaconAuthorization.Data
_minimumAuthorization
uint96
New value of the minimum authorization for the beacon. Without at least the minimum authorization, staking provider is not eligible to join and operate in the network.
_authorizationDecreaseDelay
uint64
New value of the authorization decrease delay. It is the time in seconds that needs to pass between the time authorization decrease is requested and the time the authorization decrease can be approved, no matter the authorization decrease amount.
_authorizationDecreaseChangePeriod
uint64
New value of the authorization decrease change period. It is the time in seconds, before authorization decrease delay end, during which the pending authorization decrease request can be overwritten. If set to 0, pending authorization decrease request can not be overwritten until the entire authorizationDecreaseDelay
ends. If set to value equal authorizationDecreaseDelay
, request can always be overwritten.
account
address
Tokenholder account in the T network
blockNumber
uint256
The block number to get the vote balance at
blockNumber
uint256
The block number to get the vote power at
_token
contract T
Address of T token contract
_keepStakingContract
contract IKeepTokenStaking
Address of Keep staking contract
_nucypherStakingContract
contract INuCypherStakingEscrow
Address of NuCypher staking contract
_keepVendingMachine
contract VendingMachine
Address of Keep vending machine
_nucypherVendingMachine
contract VendingMachine
Address of NuCypher vending machine
_keepStake
contract KeepStake
Address of Keep contract with grant owners
stakingProvider
address
Staking provider address
amount
uint96
Amount of NU to unstake in T denomination
owner
address
Stake owner address.
beneficiary
address payable
Beneficiary address.
authorizer
address
Authorizer address.
_delegator
address
Address of the staking provider acting as delegator
_amount
uint96
Amount of T to increment
increase
bool
True if the change is an increase, false if a decrease
_delegator
address
Address of the staking provider acting as delegator
_amount
uint96
Amount of T to increment
_delegator
address
Address of the stake owner acting as delegator
_amount
uint96
Amount of T to decrease
This file documents a contract which is not yet deployed to Mainnet.
Governable contract.
A constructor is not defined, which makes the contract compatible with upgradable proxies. This requires calling explicitly _transferGovernance
function in a child contract.
Transfers governance of the contract to newGovernance
.
This file documents a contract which is not yet deployed to Mainnet.
Library for verification of 2-pairing-check BLS signatures, including basic, aggregated, or reconstructed threshold BLS signatures, generated using the AltBn128 curve.
Creates a signature over message using the provided secret key.
Wraps the functionality of BLS.verify, but hashes a message to a point on G1 and marshal to bytes first to allow raw bytes verification.
Verify performs the pairing operation to check if the signature is correct for the provided message and the corresponding public key. Public key must be a valid point on G2 curve in an uncompressed format. Message must be a valid point on G1 curve in an uncompressed format. Signature must be a valid point on G1 curve in an uncompressed format.
This file documents a contract which is not yet deployed to Mainnet.
DKGValidator allows performing a full validation of DKG result, including checking the format of fields in the result, declared selected group members, and signatures of operators supporting the result. The operator submitting the result should perform the validation using a free contract call before submitting the result to ensure their result is valid and can not be challenged. All other network operators should perform validation of the submitted result using a free contract call and challenge the result if the validation fails.
Size of a group in the threshold relay.
The minimum number of group members needed to interact according to the protocol to produce a relay entry. The adversary can not learn anything about the key as long as it does not break into groupThreshold+1 of members.
The minimum number of active and properly behaving group members during the DKG needed to accept the result. This number is higher than groupThreshold
to keep a safety margin for members becoming inactive after DKG so that the group can still produce a relay entry.
Size in bytes of a single signature produced by operator supporting DKG result.
Performs a full validation of DKG result, including checking the format of fields in the result, declared selected group members, and signatures of operators supporting the result.
result
struct BeaconDkg.Result
seed
uint256
seed used to start the DKG and select group members
startBlock
uint256
DKG start block
isValid
bool
true if the result is valid, false otherwise
errorMsg
string
validation error message; empty for a valid result
Performs a static validation of DKG result fields: lengths, ranges, and order of arrays.
isValid
bool
true if the result is valid, false otherwise
errorMsg
string
validation error message; empty for a valid result
Performs validation of group members as declared in DKG result against group members selected by the sortition pool.
result
struct BeaconDkg.Result
seed
uint256
seed used to start the DKG and select group members
[0]
bool
true if group members matches; false otherwise
Performs validation of signatures supplied in DKG result. Note that this function does not check if addresses which supplied signatures supporting the result are the ones selected to the group by sortition pool. This function should be used together with validateGroupMembers
.
result
struct BeaconDkg.Result
startBlock
uint256
DKG start block
[0]
bool
true if group members matches; false otherwise
Performs validation of hashed group members that actively took part in DKG.
result
struct BeaconDkg.Result
DKG result
[0]
bool
true if result's group members hash matches with the one that is challenged.
This file documents a contract which is not yet deployed to Mainnet.
Implementations of common elliptic curve operations on Ethereum's (poorly named) alt_bn128 curve. Whenever possible, use post-Byzantium pre-compiled contracts to offset gas costs. Note that these pre-compiles might not be available on all (eg private) chains.
Gets generator of G1 group. Taken from go-ethereum/crypto/bn256/cloudflare/curve.go
Gets generator of G2 group. Taken from go-ethereum/crypto/bn256/cloudflare/twist.go
Gets twist curve B constant. Taken from go-ethereum/crypto/bn256/cloudflare/twist.go
Gets root of the point where x and y are equal.
g1YFromX computes a Y value for a G1 point based on an X value. This computation is simply evaluating the curve equation for Y on a given X, and allows a point on the curve to be represented by just an X value + a sign bit.
Hash a byte array message, m, and map it deterministically to a point on G1. Note that this approach was chosen for its simplicity and lower gas cost on the EVM, rather than good distribution of points on G1.
Decompress a point on G1 from a single uint256.
Wraps the point addition pre-compile introduced in Byzantium. Returns the sum of two points on G1. Revert if the provided points are not on the curve.
Returns true if G1 point is on the curve.
Wraps the scalar point multiplication pre-compile introduced in Byzantium. The result of a point from G1 multiplied by a scalar should match the point added to itself the same number of times. Revert if the provided point isn't on the curve.
Wraps the pairing check pre-compile introduced in Byzantium. Returns the result of a pairing check of 2 pairs (G1 p1, G2 p2) (G1 p3, G2 p4)
g2YFromX computes a Y value for a G2 point based on an X value. This computation is simply evaluating the curve equation for Y on a given X, and allows a point on the curve to be represented by just an X value + a sign bit.
Compress a point on G1 to a single uint256 for serialization.
Compress a point on G2 to a pair of uint256 for serialization.
Unmarshals a point on G1 from bytes in an uncompressed form.
Marshals a point on G1 to bytes form.
Unmarshals a point on G2 from bytes in an uncompressed form.
Decompress a point on G2 from a pair of uint256.
Returns the sum of two gfP2 field elements.
Returns multiplication of two gfP2 field elements.
Returns gfP2 element to the power of the provided exponent.
Returns true if G2 point's y^2 equals x.
Returns true if G2 point is on the curve.
This file documents a contract which is not yet deployed to Mainnet.
This library is used as a registry of created groups.
This library should be used along with DKG library that ensures linear groups creation (only one group creation happens at a time). A candidate group has to be popped or activated before adding a new candidate group.
Performs preliminary validation of a new group public key. The group public key must be unique and have 128 bytes in length. If the validation fails, the function reverts. This function must be called first for a public key of a group added with addGroup
function.
self
struct Groups.Data
groupPubKey
bytes
Candidate group public key
Adds a new candidate group. The group is stored with group public key and group members, but is not yet activated.
The group members list is stored with all misbehaved members filtered out. The code calling this function should ensure that the number of candidate (not activated) groups is never more than one.
self
struct Groups.Data
groupPubKey
bytes
Generated candidate group public key
membersHash
bytes32
Keccak256 hash of members that actively took part in DKG.
Goes through groups starting from the oldest one that is still active and checks if it hasn't expired. If so, updates the information about expired groups so that all expired groups are marked as such.
Terminates group with the provided index. Reverts if the group is already terminated.
self
struct Groups.Data
groupId
uint64
Index in the groupRegistry array.
Returns an index of a randomly selected active group. Terminated and expired groups are not considered as active. Before new group is selected, information about expired groups is updated. At least one active group needs to be present for this function to succeed.
self
struct Groups.Data
seed
uint256
Random number used as a group selection seed.
Setter for group lifetime.
self
struct Groups.Data
lifetime
uint256
Lifetime of a group in blocks.
Checks if group with the given index is terminated.
Gets the cutoff time until which the given group is considered to be active assuming it hasn't been terminated before.
Checks if group with the given index is active and non-terminated.
Gets the number of active groups. Expired and terminated groups are not counted as active.
Evaluates the shift of a selected group index based on the number of expired groups.
Evaluates the shift of a selected group index based on the number of non-expired but terminated groups.
This file documents a contract which is not yet deployed to Mainnet.
Library for handling calls to random beacon consumer.
Sets callback contract.
self
struct Callback.Data
callbackContract
contract IRandomBeaconConsumer
Callback contract.
Executes consumer specified callback for the relay entry request.
self
struct Callback.Data
entry
uint256
The generated random number.
callbackGasLimit
uint256
Callback gas limit.
This file documents a contract which is not yet deployed to Mainnet.
Creates a request to generate a new relay entry. Requires a request fee denominated in T token.
callbackContract
contract IRandomBeaconConsumer
Beacon consumer callback contract.
This file documents a contract which is not yet deployed to Mainnet.
Owns the RandomBeacon
contract and is responsible for updating its governable parameters in respect to governance delay individual for each parameter.
Reverts if called before the governance delay elapses.
changeInitiatedTimestamp
uint256
Timestamp indicating the beginning of the change.
Begins the governance delay update process.
Can be called only by the contract owner.
_newGovernanceDelay
uint256
New governance delay
Finalizes the governance delay update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the random beacon governance transfer process.
Can be called only by the current contract governance.
Finalizes the random beacon governance transfer process.
Can be called only by the current contract governance, after the governance delay elapses.
Begins the relay entry soft timeout update process.
Can be called only by the contract owner.
_newRelayEntrySoftTimeout
uint256
New relay entry submission timeout in blocks
Finalizes the relay entry soft timeout update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the relay entry hard timeout update process.
Can be called only by the contract owner.
_newRelayEntryHardTimeout
uint256
New relay entry hard timeout in blocks
Finalizes the relay entry hard timeout update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the callback gas limit update process.
Can be called only by the contract owner.
_newCallbackGasLimit
uint256
New callback gas limit
Finalizes the callback gas limit update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the group creation frequency update process.
Can be called only by the contract owner.
_newGroupCreationFrequency
uint256
New group creation frequency
Finalizes the group creation frequency update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the group lifetime update process. Group lifetime needs to be shorter than the authorization decrease delay to ensure every active group is backed by enough stake. A new group lifetime value is in blocks and has to be calculated based on the average block time and authorization decrease delay which value is in seconds.
Can be called only by the contract owner.
_newGroupLifetime
uint256
New group lifetime in blocks
Finalizes the group creation frequency update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the DKG result challenge period length update process.
Can be called only by the contract owner.
_newDkgResultChallengePeriodLength
uint256
New DKG result challenge period length in blocks
Finalizes the DKG result challenge period length update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the DKG result challenge extra gas update process.
Can be called only by the contract owner.
_newDkgResultChallengeExtraGas
uint256
New DKG result challenge extra gas
Finalizes the DKG result challenge extra gas update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the DKG result submission timeout update process.
Can be called only by the contract owner.
_newDkgResultSubmissionTimeout
uint256
New DKG result submission timeout in blocks
Finalizes the DKG result submission timeout update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the DKG submitter precedence period length.
Can be called only by the contract owner.
_newDkgSubmitterPrecedencePeriodLength
uint256
New DKG submitter precedence period length in blocks
Finalizes the DKG submitter precedence period length.
Can be called only by the contract owner, after the governance delay elapses.
Begins the sortition pool rewards ban duration update process.
Can be called only by the contract owner.
_newSortitionPoolRewardsBanDuration
uint256
New sortition pool rewards ban duration.
Finalizes the sortition pool rewards ban duration update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the relay entry timeout notification reward multiplier update process.
Can be called only by the contract owner.
_newRelayEntryTimeoutNotificationRewardMultiplier
uint256
New relay entry timeout notification reward multiplier.
Begins the unauthorized signing notification reward multiplier update process.
Can be called only by the contract owner.
_newUnauthorizedSigningNotificationRewardMultiplier
uint256
New unauthorized signing notification reward multiplier.
Finalizes the unauthorized signing notification reward multiplier update process.
Can be called only by the contract owner, after the governance delay elapses.
Finalizes the relay entry timeout notification reward multiplier update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the DKG malicious result notification reward multiplier update process.
Can be called only by the contract owner.
_newDkgMaliciousResultNotificationRewardMultiplier
uint256
New DKG malicious result notification reward multiplier.
Finalizes the DKG malicious result notification reward multiplier update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the relay entry submission failure slashing amount update process.
Can be called only by the contract owner.
_newRelayEntrySubmissionFailureSlashingAmount
uint96
New relay entry submission failure slashing amount
Finalizes the relay entry submission failure slashing amount update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the DKG result submission gas update process.
Can be called only by the contract owner.
_newDkgResultSubmissionGas
uint256
New relay entry submission gas offset
Finalizes DKG result submission gas update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the DKG result approval gas offset update process.
Can be called only by the contract owner.
_newDkgResultApprovalGasOffset
uint256
New DKG approval gas offset
Finalizes the DKG result approval gas offset update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the notify operator inactivity gas offset update process.
Can be called only by the contract owner.
_newNotifyOperatorInactivityGasOffset
uint256
New operator inactivity notification gas offset
Finalizes the notify operator inactivity gas offset update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the relay entry submission gas offset update process.
Can be called only by the contract owner.
_newRelayEntrySubmissionGasOffset
uint256
New relay entry submission gas offset
Finalizes relay entry submission gas offset update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the malicious DKG result slashing amount update process.
Can be called only by the contract owner.
_newMaliciousDkgResultSlashingAmount
uint96
New malicious DKG result slashing amount
Finalizes the malicious DKG result slashing amount update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the unauthorized signing slashing amount update process.
Can be called only by the contract owner.
_newUnauthorizedSigningSlashingAmount
uint96
New unauthorized signing slashing amount
Finalizes the unauthorized signing slashing amount update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the minimum authorization amount update process.
Can be called only by the contract owner.
_newMinimumAuthorization
uint96
New minimum authorization amount.
Finalizes the minimum authorization amount update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the authorization decrease delay update process.
Can be called only by the contract owner.
_newAuthorizationDecreaseDelay
uint64
New authorization decrease delay
Finalizes the authorization decrease delay update process.
Can be called only by the contract owner, after the governance delay elapses.
Begins the authorization decrease change period update process.
Can be called only by the contract owner.
_newAuthorizationDecreaseChangePeriod
uint64
New authorization decrease change period
Finalizes the authorization decrease change period update process.
Can be called only by the contract owner, after the governance delay elapses.
Set authorization for requesters that can request a relay entry. It can be done by the governance only.
requester
address
Requester, can be a contract or EOA
isAuthorized
bool
True or false
Withdraws rewards belonging to operators marked as ineligible for sortition pool rewards.
Can be called only by the contract owner.
recipient
address
Recipient of withdrawn rewards.
Get the time remaining until the governance delay can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the random beacon governance can be transferred.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the relay entry submission soft timeout can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the relay entry hard timeout can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the callback gas limit can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the group creation frequency can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the group lifetime can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the DKG result challenge period length can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the DKG result challenge extra gas can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the DKG result submission timeout can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the wallet owner can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the relay entry submission failure slashing amount can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the malicious DKG result slashing amount can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the unauthorized signing slashing amount can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the minimum authorization amount can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the authorization decrease delay can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the authorization decrease change period can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the sortition pool rewards ban duration can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the relay entry timeout notification reward multiplier duration can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the unauthorized signing notification reward multiplier duration can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the DKG malicious result notification reward multiplier duration can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the DKG result submission gas duration can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the DKG approval gas offset duration can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the operator inactivity notification gas offset duration can be updated.
[0]
uint256
Remaining time in seconds.
Get the time remaining until the relay entry submission gas offset duration can be updated.
[0]
uint256
Remaining time in seconds.
Gets the time remaining until the governable parameter update can be committed.
changeTimestamp
uint256
Timestamp indicating the beginning of the change.
[0]
uint256
Remaining time in seconds.
This file documents a contract which is not yet deployed to Mainnet.
Wraps the modular exponent pre-compile introduced in Byzantium. Returns base^exponent mod p.
Calculates and returns the square root of a mod p if such a square root exists. The modulus p must be an odd prime. If a square root does not exist, function returns 0.
Calculates the Legendre symbol of the given a mod p.
[0]
int256
Returns 1 if a is a quadratic residue mod p, -1 if it is a non-quadratic residue, and 0 if a is 0.
This file documents a contract which is not yet deployed to Mainnet.
Receives relay entry produced by Keep Random Beacon. This function should be called only by Keep Random Beacon.
relayEntry
uint256
Relay entry (random number) produced by Keep Random Beacon.
blockNumber
uint256
Block number at which the relay entry was submitted to the chain.
tBTC SDK is a TypeScript library that provides effortless access to the fundamental features of the tBTC Bitcoin bridge. The SDK allows developers to integrate tBTC into their own applications and offer the power of trustless tokenized Bitcoin to their users.
The SDK documentation consists of the following parts:
This file documents a contract which is not yet deployed to Mainnet.
Seed used as the first relay entry value. It's a G1 point G * PI = G * 31415926535897932384626433832795028841971693993751058209749445923078164062862 Where G is the generator of G1 abstract cyclic group.
Initializes the very first previousEntry
with an initial relaySeed
value. Can be performed only once.
Creates a request to generate a new relay entry, which will include a random number (by signing the previous entry's random number).
Creates a new relay entry. Gas-optimized version that can be called only before the soft timeout. This should be the majority of cases.
Creates a new relay entry. Can be called at any time. In case the soft timeout has not been exceeded, it is more gas-efficient to call the second variation of submitEntry
.
Calculates the slashing amount for all group members.
Must be used when a soft timeout was hit.
Updates relay-related parameters
Set relayEntrySubmissionFailureSlashingAmount parameter.
Retries the current relay request in case a relay entry timeout was reported.
Cleans up the current relay request in case a relay entry timeout was reported.
Returns whether a relay entry request is currently in progress.
Returns whether the current relay request has timed out.
Calculates soft timeout block for the pending relay request.
This file documents a contract which is not yet deployed to Mainnet.
Authorized contracts that can interact with the reimbursment pool. Authorization can be granted and removed by the owner.
Static gas includes:
cost of the refund function
base transaction cost
Max gas price used to reimburse a transaction submitter. Protects against malicious operator-miners.
Receive ETH
Refunds ETH to a spender for executing specific transactions.
Ignoring the result of sending ETH to a receiver is made on purpose. For EOA receiving ETH should always work. If a receiver is a smart contract, then we do not want to fail a transaction, because in some cases the refund is done at the very end of multiple calls where all the previous calls were already paid off. It is a receiver's smart contract resposibility to make sure it can receive ETH. Only authorized contracts are allowed calling this function.
Authorize a contract that can interact with this reimbursment pool. Can be authorized by the owner only.
Unauthorize a contract that was previously authorized to interact with this reimbursment pool. Can be unauthorized by the owner only.
Setting a static gas cost for executing a transaction. Can be set by the owner only.
Setting a max gas price for transactions. Can be set by the owner only.
Withdraws all ETH from this pool which are sent to a given address. Can be set by the owner only.
Withdraws ETH amount from this pool which are sent to a given address. Can be set by the owner only.
The following diagram presents the architecture of the tBTC SDK and its place in the ecosystem:
As you can see, the SDK consists of several major parts:
TBTC
component
Feature services
Shared libraries
TBTC
componentThe role of the SDK feature services is to provide seamless access to the core features of the tBTC bridge. The most important feature services of the SDK are:
Deposits: deposit and mint flow for BTC depositors
Redemptions: unmint and redeem flow for TBTC redeemers
Maintenance: authorized maintenance actions for maintainers (e.g. optimistic minting guardians)
Shared libraries are reusable modules that provide cross-cutting concerns leveraged by multiple feature services and the TBTC
component. The main shared libraries of the SDK are:
Bitcoin: interfaces and utilities necessary to interact with the Bitcoin chain
Contracts: chain-agnostic interfaces allowing to interact with tBTC smart contracts
Electrum: Electrum-based implementation of the Bitcoin client
Ethereum: implementations of tBTC smart contract interfaces for Ethereum chain
Utils: general utility functions
By integrating tBTC, developers can bridge the gap between Bitcoin's liquidity and Ethereum's smart contract capabilities. tBTC provides a decentralized, secure and permissionless way to bring BTC into the Ethereum ecosystem enabling innovative DeFi applications and expanding possibilities for cross-chain interactions.
Utilizing the provided SDKs and developer resources you can seamlessly integrate tBTC into your projects and contribute to the growth of decentralized finance.
This file documents a contract which is not yet deployed to Mainnet.
Keep Random Beacon contract. It lets to request a new relay entry and validates the new relay entry provided by the network. This contract is in charge of all other Random Beacon activities such as group lifecycle or slashing.
Should be owned by the governance contract controlling Random Beacon parameters.
Seed value used for the genesis group selection. https://www.wolframalpha.com/input/?i=pi+to+78+digits
Relay entry callback gas limit. This is the gas limit with which callback function provided in the relay request transaction is executed. The callback is executed with a new relay entry value in the same transaction the relay entry is submitted.
The frequency of new group creation. Groups are created with a fixed frequency of relay requests.
Slashing amount for submitting a malicious DKG result. Every DKG result submitted can be challenged for the time of dkg.ResultChallengePeriodLength
. If the DKG result submitted is challenged and proven to be malicious, the operator who submitted the malicious result is slashed for _maliciousDkgResultSlashingAmount
.
Slashing amount when an unauthorized signing has been proved, which means the private key leaked and all the group members should be punished.
Duration of the sortition pool rewards ban imposed on operators who misbehaved during DKG by being inactive or disqualified and for operators that were identified by the rest of group members as inactive via notifyOperatorInactivity
.
Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about relay entry timeout. Notifiers are rewarded from a notifiers treasury pool. For example, if notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.
Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about unauthorized signing. Notifiers are rewarded from a notifiers treasury pool. For example, if a notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.
Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about a malicious DKG result. Notifiers are rewarded from a notifiers treasury pool. For example, if notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.
Calculated gas cost for submitting a DKG result. This will be refunded as part of the DKG approval process. It is in the submitter's interest to not skip his priority turn on the approval, otherwise the refund of the DKG submission will be refunded to another group member that will call the DKG approve function.
Gas that is meant to balance the DKG result approval's overall cost. Can be updated by the governance based on the current market conditions.
Gas that is meant to balance the operator inactivity notification cost. Can be updated by the governance based on the current market conditions.
Gas that is meant to balance the relay entry submission cost. Can be updated by the governance based on the current market conditions.
Stores current operator inactivity claim nonce for given group. Each claim is made with an unique nonce which protects against claim replay.
Authorized addresses that can request a relay entry.
Assigns initial values to parameters to make the beacon work safely. These parameters are just proposed defaults and they might be updated with update*
functions after the contract deployment and before transferring the ownership to the governance contract.
Updates the values of authorization parameters.
Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.
Updates the values of relay entry parameters.
Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.
Updates the values of group creation parameters.
Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.
Updates the values of reward parameters.
Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.
Updates the values of slashing parameters.
Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.
Updates the values of gas parameters.
Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.
Set authorization for requesters that can request a relay entry.
Can be called only by the contract guvnor, which should be the random beacon governance contract.
Withdraws application rewards for the given staking provider. Rewards are withdrawn to the staking provider's beneficiary address set in the staking contract. Reverts if staking provider has not registered the operator address.
Emits RewardsWithdrawn
event.
Withdraws rewards belonging to operators marked as ineligible for sortition pool rewards.
Can be called only by the contract guvnor, which should be the random beacon governance contract.
Used by staking provider to set operator address that will operate a node. The given staking provider can set operator address only one time. The operator address can not be changed and must be unique. Reverts if the operator is already set for the staking provider or if the operator address is already in use. Reverts if there is a pending authorization decrease for the staking provider.
Lets the operator join the sortition pool. The operator address must be known - before calling this function, it has to be appointed by the staking provider by calling registerOperator
. Also, the operator must have the minimum authorization required by the beacon. Function reverts if there is no minimum stake authorized or if the operator is not known. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay.
Updates status of the operator in the sortition pool. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay. Function reverts if the operator is not known.
Used by T staking contract to inform the beacon that the authorized stake amount for the given staking provider increased.
Reverts if the authorization amount is below the minimum.
The function is not updating the sortition pool. Sortition pool state needs to be updated by the operator with a call to joinSortitionPool
or updateOperatorStatus
.
Can only be called by T staking contract.
Used by T staking contract to inform the beacon that the authorization decrease for the given staking provider has been requested.
Reverts if the amount after deauthorization would be non-zero and lower than the minimum authorization.
Reverts if another authorization decrease request is pending for the staking provider and not enough time passed since the original request (see authorizationDecreaseChangePeriod
).
If the operator is not known (registerOperator
was not called) it lets to approveAuthorizationDecrease
immediately. If the operator is known (registerOperator
was called), the operator needs to update state of the sortition pool with a call to joinSortitionPool
or updateOperatorStatus
. After the sortition pool state is in sync, authorization decrease delay starts.
After authorization decrease delay passes, authorization decrease request needs to be approved with a call to approveAuthorizationDecrease
function.
If there is a pending authorization decrease request, it is overwritten, but only if enough time passed since the original request. Otherwise, the function reverts.
Can only be called by T staking contract.
Approves the previously registered authorization decrease request. Reverts if authorization decrease delay has not passed yet or if the authorization decrease was not requested for the given staking provider.
Used by T staking contract to inform the beacon the authorization has been decreased for the given staking provider involuntarily, as a result of slashing.
If the operator is not known (registerOperator
was not called) the function does nothing. The operator was never in a sortition pool so there is nothing to update.
If the operator is known, sortition pool is unlocked, and the operator is in the sortition pool, the sortition pool state is updated. If the sortition pool is locked, update needs to be postponed. Every other staker is incentivized to call updateOperatorStatus
for the problematic operator to increase their own rewards in the pool.
Triggers group selection if there are no active groups.
\x19Ethereum signed message:
before signing, so the message to sign is: \x19Ethereum signed message:\n${keccak256(chainID,groupPubKey,misbehaved,startBlock)}
Notifies about DKG timeout.
Approves DKG result. Can be called when the challenge period for the submitted result is finished. Considers the submitted result as valid, bans misbehaved group members from the sortition pool rewards, and completes the group creation by activating the candidate group. For the first submitterPrecedencePeriodLength
blocks after the end of the challenge period can be called only by the DKG result submitter. After that time, can be called by anyone.
Challenges DKG result. If the submitted result is proved to be invalid it reverts the DKG back to the result submission phase. It removes a candidate group that was previously registered with the DKG result submission.
Due to EIP-150 1/64 of the gas is not forwarded to the call, and will be kept to execute the remaining operations in the function after the call inside the try-catch. To eliminate a class of attacks related to the gas limit manipulation, this function requires an extra amount of gas to be left at the end of the execution.
Check current group creation state.
Checks if DKG timed out. The DKG timeout period includes time required for off-chain protocol execution and time for the result publication for all group members. After this time result cannot be submitted and DKG can be notified about the timeout.
Creates a request to generate a new relay entry, which will include a random number (by signing the previous entry's random number). Requester must be previously authorized by the governance.
Creates a new relay entry. Gas-optimized version that can be called only before the soft timeout. This should be the majority of cases.
Creates a new relay entry.
Reports a relay entry timeout.
Reports unauthorized groups signing. Must provide a valid signature of the sender's address as a message. Successful signature verification means the private key has been leaked and all group members should be punished by slashing their tokens. Group has to be active or expired. Unauthorized signing cannot be reported for a terminated group. In case of reporting unauthorized signing for a terminated group, or when the signature is invalid, function reverts.
Notifies about operators who are inactive. Using this function, a majority of the group can decide about punishing specific group members who constantly fail doing their job. If the provided claim is proved to be valid and signed by sufficient number of group members, operators of members deemed as inactive are banned for sortition pool rewards for duration specified by _sortitionPoolRewardsBanDuration
parameter. The sender of the claim must be one of the claim signers. This function can be called only for active and non-terminated groups.
The minimum authorization amount required so that operator can participate in the random beacon. This amount is required to execute slashing for providing a malicious DKG result or when a relay entry times out.
Returns the current value of the staking provider's eligible stake. Eligible stake is defined as the currently authorized stake minus the pending authorization decrease. Eligible stake is what is used for operator's weight in the sortition pool. If the authorized stake minus the pending authorization decrease is below the minimum authorization, eligible stake is 0.
Returns the amount of rewards available for withdrawal for the given staking provider. Reverts if staking provider has not registered the operator address.
Returns the amount of stake that is pending authorization decrease for the given staking provider. If no authorization decrease has been requested, returns zero.
Returns the remaining time in seconds that needs to pass before the requested authorization decrease can be approved. If the sortition pool state was not updated yet by the operator after requesting the authorization decrease, returns type(uint64).max
.
Returns operator registered for the given staking provider.
Returns staking provider of the given operator.
Checks if the operator's authorized stake is in sync with operator's weight in the sortition pool. If the operator is not in the sortition pool and their authorized stake is non-zero, function returns false.
Returns true if the given operator is in the sortition pool. Otherwise, returns false.
Selects a new group of operators. Can only be called when DKG is in progress and the pool is locked. At least one operator has to be registered in the pool, otherwise the function fails reverting the transaction.
Returns authorization-related parameters of the beacon.
The minimum authorization is also returned by minimumAuthorization()
function, as a requirement of IApplication
interface.
Returns relay-entry-related parameters of the beacon.
Returns group-creation-related parameters of the beacon.
Returns reward-related parameters of the beacon.
Returns slashing-related parameters of the beacon.
Returns gas-related parameters of the beacon.
Here you can find instructions explaining how to use the SDK in your own project.
To install the tBTC SDK in your project, run:
Here is a brief example demonstrating the use of the SDK in Ethereum:
Here is a brief example demonstrating the use of the SDK in some L2, e.g. Arbitrum:
For a high-level overview of the tBTC protocol, please see the section.
The TBTC
component is the main entry point to the SDK. It provides different ways to initialize the SDK that are supposed to address the common use cases (see guide to learn more). Moreover, the TBTC
component gives access to the SDK core features through feature services as well as low-level direct access to the underlying tBTC smart contracts and Bitcoin network client.
is a decentralized, permissionless Bitcoin bridge developed by the Threshold Network designed to bring Bitcoin (BTC) liquidity to Ethereum and other EVM-compatible networks. It allows Bitcoin holders to mint tBTC, an ERC-20 token fully backed 1:1 by BTC, enabling seamless participation in Ethereum's DeFi ecosystem without relying on centralized intermediaries.
Please note that you will also need to install the library to initialize a signer or provider. To do so, invoke:
self
struct Relay.Data
groupId
uint64
Identifier of the group chosen to handle the request.
self
struct Relay.Data
entry
bytes
Group BLS signature over the previous entry.
groupPubKey
bytes
Public key of the group which signed the relay entry.
self
struct Relay.Data
entry
bytes
Group BLS signature over the previous entry.
groupPubKey
bytes
Public key of the group which signed the relay entry.
[0]
uint96
slashingAmount Amount by which group members should be slashed in case the relay entry was submitted after the soft timeout. The value is zero if entry was submitted on time.
[0]
uint96
Amount by which group members should be slashed in case the relay entry was submitted after the soft timeout.
self
struct Relay.Data
_relayEntrySoftTimeout
uint256
New relay entry soft timeout value. It is the time in blocks during which a result is expected to be submitted so that the group is not slashed.
_relayEntryHardTimeout
uint256
New relay entry hard timeout value. It is the time in blocks for a group to submit the relay entry before slashing for the full slashing amount happens.
self
struct Relay.Data
newRelayEntrySubmissionFailureSlashingAmount
uint96
New value of the parameter.
self
struct Relay.Data
newGroupId
uint64
ID of the group chosen to retry the current request.
[0]
bool
True if there is a request in progress. False otherwise.
[0]
bool
True if the request timed out. False otherwise.
[0]
uint256
The soft timeout block
gasSpent
uint256
Gas spent on a transaction that needs to be reimbursed.
receiver
address
Address where the reimbursment is sent.
_contract
address
Authorized contract.
_contract
address
Authorized contract.
_staticGas
uint256
Static gas cost.
_maxGasPrice
uint256
Max gas price used to reimburse tx submitters.
receiver
address
An address where ETH is sent.
amount
uint256
Amount to withdraw from the pool.
receiver
address
An address where ETH is sent.
_minimumAuthorization
uint96
New minimum authorization amount
_authorizationDecreaseDelay
uint64
New authorization decrease delay in seconds
_authorizationDecreaseChangePeriod
uint64
New authorization decrease change period in seconds
relayEntrySoftTimeout
uint256
New relay entry submission soft timeout
relayEntryHardTimeout
uint256
New relay entry hard timeout
callbackGasLimit
uint256
New callback gas limit
groupCreationFrequency
uint256
New group creation frequency
groupLifetime
uint256
New group lifetime in blocks
dkgResultChallengePeriodLength
uint256
New DKG result challenge period length
dkgResultChallengeExtraGas
uint256
New DKG result challenge extra gas
dkgResultSubmissionTimeout
uint256
New DKG result submission timeout
dkgSubmitterPrecedencePeriodLength
uint256
New DKG result submitter precedence period length
sortitionPoolRewardsBanDuration
uint256
New sortition pool rewards ban duration in seconds.
relayEntryTimeoutNotificationRewardMultiplier
uint256
New value of the relay entry timeout notification reward multiplier
unauthorizedSigningNotificationRewardMultiplier
uint256
New value of the unauthorized signing notification reward multiplier
dkgMaliciousResultNotificationRewardMultiplier
uint256
New value of the DKG malicious result notification reward multiplier
relayEntrySubmissionFailureSlashingAmount
uint96
New relay entry submission failure amount
maliciousDkgResultSlashingAmount
uint96
New malicious DKG result slashing amount
unauthorizedSigningSlashingAmount
uint96
New unauthorized signing slashing amount
dkgResultSubmissionGas
uint256
New DKG result submission gas
dkgResultApprovalGasOffset
uint256
New DKG result approval gas offset
notifyOperatorInactivityGasOffset
uint256
New operator inactivity notification gas offset
relayEntrySubmissionGasOffset
uint256
New relay entry submission gas offset
requester
address
Requester, can be a contract or EOA
isAuthorized
bool
True or false
recipient
address
Recipient of withdrawn rewards.
dkgResult
struct BeaconDkg.Result
DKG result.
dkgResult
struct BeaconDkg.Result
Result to approve. Must match the submitted result stored during submitDkgResult
.
dkgResult
struct BeaconDkg.Result
Result to challenge. Must match the submitted result stored during submitDkgResult
.
[0]
bool
True if DKG timed out, false otherwise.
callbackContract
contract IRandomBeaconConsumer
Beacon consumer callback contract.
entry
bytes
Group BLS signature over the previous entry.
entry
bytes
Group BLS signature over the previous entry.
groupMembers
uint32[]
Identifiers of group members.
groupMembers
uint32[]
Identifiers of group members.
signedMsgSender
bytes
Signature of the sender's address as a message.
groupId
uint64
Group that is being reported for leaking a private key.
groupMembers
uint32[]
Identifiers of group members.
claim
struct BeaconInactivity.Claim
Operator inactivity claim.
nonce
uint256
Current inactivity claim nonce for the given group. Must be the same as the stored one.
groupMembers
uint32[]
Identifiers of group members.
[0]
bool
Flag indicating whether a relay entry request is currently in progress.
[0]
uint32[]
IDs of selected group members.
minimumAuthorization
uint96
The minimum authorization amount required so that operator can participate in the random beacon. This amount is required to execute slashing for providing a malicious DKG result or when a relay entry times out.
authorizationDecreaseDelay
uint64
Delay in seconds that needs to pass between the time authorization decrease is requested and the time that request gets approved. Protects against free-riders earning rewards and not being active in the network.
authorizationDecreaseChangePeriod
uint64
Authorization decrease change period in seconds. It is the time, before authorization decrease delay end, during which the pending authorization decrease request can be overwritten. If set to 0, pending authorization decrease request can not be overwritten until the entire authorizationDecreaseDelay
ends. If set to value equal authorizationDecreaseDelay
, request can always be overwritten.
relayEntrySoftTimeout
uint256
Soft timeout in blocks for a group to submit the relay entry. If the soft timeout is reached for submitting the relay entry, the slashing starts.
relayEntryHardTimeout
uint256
Hard timeout in blocks for a group to submit the relay entry. After the soft timeout passes without relay entry submitted, all group members start getting slashed. The slashing amount increases linearly until the group submits the relay entry or until relayEntryHardTimeout
is reached. When the hard timeout is reached, each group member will get slashed for _relayEntrySubmissionFailureSlashingAmount
.
callbackGasLimit
uint256
Relay entry callback gas limit. This is the gas limit with which callback function provided in the relay request transaction is executed. The callback is executed with a new relay entry value in the same transaction the relay entry is submitted.
groupCreationFrequency
uint256
The frequency of a new group creation. Groups are created with a fixed frequency of relay requests.
groupLifetime
uint256
Group lifetime in blocks. When a group reached its lifetime, it is no longer selected for new relay requests but may still be responsible for submitting relay entry if relay request assigned to that group is still pending.
dkgResultChallengePeriodLength
uint256
The number of blocks for which a DKG result can be challenged. Anyone can challenge DKG result for a certain number of blocks before the result is fully accepted and the group registered in the pool of active groups. If the challenge gets accepted, all operators who signed the malicious result get slashed for and the notifier gets rewarded.
dkgResultChallengeExtraGas
uint256
The extra gas required to be left at the end of the challenge DKG result transaction.
dkgResultSubmissionTimeout
uint256
Timeout in blocks for a group to submit the DKG result. All members are eligible to submit the DKG result. If dkgResultSubmissionTimeout
passes without the DKG result submitted, DKG is considered as timed out and no DKG result for this group creation can be submitted anymore.
dkgSubmitterPrecedencePeriodLength
uint256
Time during the DKG result approval stage when the submitter of the DKG result takes the precedence to approve the DKG result. After this time passes anyone can approve the DKG result.
sortitionPoolRewardsBanDuration
uint256
Duration of the sortition pool rewards ban imposed on operators who misbehaved during DKG by being inactive or disqualified and for operators that were identified by the rest of group members as inactive via notifyOperatorInactivity
.
relayEntryTimeoutNotificationRewardMultiplier
uint256
Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about relay entry timeout. Notifiers are rewarded from a notifiers treasury pool. For example, if notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.
unauthorizedSigningNotificationRewardMultiplier
uint256
Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about unauthorized signing. Notifiers are rewarded from a notifiers treasury pool. For example, if a notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.
dkgMaliciousResultNotificationRewardMultiplier
uint256
Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about a malicious DKG result. Notifiers are rewarded from a notifiers treasury pool. For example, if notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.
relayEntrySubmissionFailureSlashingAmount
uint96
Slashing amount for not submitting relay entry. When relay entry hard timeout is reached without the relay entry submitted, each group member gets slashed for relayEntrySubmissionFailureSlashingAmount
. If the relay entry gets submitted after the soft timeout, but before the hard timeout, each group member gets slashed proportionally to relayEntrySubmissionFailureSlashingAmount
and the time passed since the soft deadline.
maliciousDkgResultSlashingAmount
uint96
Slashing amount for submitting a malicious DKG result. Every DKG result submitted can be challenged for the time of dkg.ResultChallengePeriodLength
. If the DKG result submitted is challenged and proven to be malicious, the operator who submitted the malicious result is slashed for maliciousDkgResultSlashingAmount
.
unauthorizedSigningSlashingAmount
uint96
Slashing amount when an unauthorized signing has been proved, which means the private key leaked and all the group members should be punished.
dkgResultSubmissionGas
uint256
Calculated gas cost for submitting a DKG result. This will be refunded as part of the DKG approval process.
dkgResultApprovalGasOffset
uint256
Gas that is meant to balance the DKG result approval's overall cost.
notifyOperatorInactivityGasOffset
uint256
Gas that is meant to balance the operator inactivity notification cost.
relayEntrySubmissionGasOffset
uint256
Gas that is meant to balance the relay entry submission cost.
Before initializing the tBTC SDK instance in your project, you need to answer the following questions:
What Bitcoin network and which tBTC contracts do you plan to interact with?
Do you want to perform just read-only actions or send transactions as well?
Answering those questions will allow initializing the SDK in the right way. The SDK is prepared to handle common use cases but provides some flexibility as well. This guide explains that in detail.
These guides will show you how to initialize the SDK in mainnet, testnet, crosschain or custom mode.
This file documents a contract which is not yet deployed to Mainnet.
The minimum number of group members needed to interact according to the protocol to produce a valid inactivity claim.
Size in bytes of a single signature produced by member supporting the inactivity claim.
Verifies the inactivity claim according to the rules defined in Claim
struct documentation. Reverts if verification fails.
Group members hash is validated upstream in RandomBeacon.notifyOperatorInactivity()
sortitionPool
contract SortitionPool
Sortition pool reference
claim
struct BeaconInactivity.Claim
Inactivity claim
groupPubKey
bytes
Public key of the group raising the claim
nonce
uint256
Current nonce for group used in the claim
groupMembers
uint32[]
Identifiers of group members
inactiveMembers
uint32[]
Identifiers of members who are inactive
Validates members indices array. Array is considered valid if its size and each single index are in [1, groupSize] range, indexes are unique, and sorted in an ascending order. Reverts if validation fails.
indices
uint256[]
Array to validate
groupSize
uint256
Group size used as reference
This file documents a contract which is not yet deployed to Mainnet.
A stub contract that will be used temporarily until the real-world random beacon client implementation is ready.
Authorized addresses that can request a relay entry.
Arbitrary relay entry. Initially set to the Euler's number. It's updated after each relay entry request.
Executes the callback with an arbitrary relay entry number.
The caller must be an authorized requester.
callbackContract
contract IRandomBeaconConsumer
Beacon consumer callback contract - Wallet Registry
Authorizes a requester of the relay entry.