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...
A tBTC v2 node can be set up using either a docker or binary installation.
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 LQTY 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 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.
NU and KEEP tokens can be upgraded to T tokens via the Vending Machine contracts. As decided by the NU and KEEP communities in the final merge proposal, the conversion ratio for each token is based on the total supply rather than price. The final total supply of NU is ~1,380,688,920 and the total supply of KEEP is ~940,795,010.
As a result, the token factors are:
1 NU: ~3.26 T
1 KEEP: ~4.78 T
Token upgrades can be performed via the Threshold Dashboard which interfaces directly with the Vending Machine smart contracts.
How to delegate staked T tokens
Stakers on Threshold can delegate their stake weights to themselves or a third party for voting on governance proposals.
1. Go to
2. Connect your wallet
3. Enter the delegate address - once an address is entered, a “Delegate” button will appear
4. Click "Delegate" and sign the transaction.
nucypher-ops is an ansible script that automates setup and configuration of a PRE node.
A guide for to setup and configure the tBTC v2 client.




Threshold Application – underlying technology
Conditions-Based Decryption (CBD) is one of two technologies underpinning the Threshold Access Control service, the other being Proxy Re-Encryption. The vast majority of developers will only require CBD technology to provably protect their users' data, and we recommend that all developers start here – by familiarizing themselves with CBD.
In broad terms, CBD enables the users of adopting applications to specify conditions for accessing their encrypted data. If those conditions are not fulfilled – which means formal verification by a cohort of nodes from the Threshold network – then the data remain entirely unreadable to anyone besides the original data owner/encryptor. However, if the predefined conditions are provably satisfied, then the data requester gains decryption rights.
Threshold Decryption
Under the hood, CBD involves splitting a joint secret – a decryption key – into multiples shares and distributing those among authorized and collateralized node operators (stakers in the Threshold network). A minimum number – a threshold – of those operators holding the key shares must be online and actively participate in partial decryptions. These are subsequently combined on the requester's client to reconstruct the original plaintext data.
Conditionality
A range of access condition types can be defined by the data owner. For example:
EVM-based e.g. Does the requester own a given NFT?
RPC-driven e.g. Does the requester have at least X amount of a given token in their wallet?
Time-based e.g. Has a predefined period elapsed, after which requests will be ignored?
These conditions are also composable and can be combined in any logical sequence or decision tree.
Conditions are 'attached' on a per-ciphertext basis. In other words, each and every payload, message or bit can be access-restricted by a unique set of specified conditions. In most situations, condition sets will be automatically reused until the end-user proactively configures them – for example, in order to remove an address from continuing to access the messages in a group chat.
Conditions Verification
Currently, requesters prove their association with condition fulfillment – i.e. their right to receive a threshold number of decrypting shares – by signing a transaction that verifies their ownership of a given Ethereum wallet. That wallet is checked for fulfillment of the specific condition – e.g. owning an NFT in order to access a DAO's knowledge base.
This signature can be cached by the application for a use case-appropriate period of time, such that the user does not have to repeatedly re-sign for access later. However, verification still takes place in the background – for example, if a wallet address is removed from an NFT-gated group-chat by dint of changing the access-granting NFT, they will immediately be unable to see new messages. The cached signature will not give them access any longer than is specified by the data owner/encryptor.
Network Parameterization
CBD is fully decentralized. Therefore, developers have the option to tweak certain network parameters, which affect the collusion-resistance, redundancy, latency and (in future versions) cost of using CBD. For example:
The number of decrypting shares n
The frequency and/or prompt for resampling a new cohort from the node array
The 'hard-coded' node address that always feature in the cohort
This optionality can also be surfaced for end-users – for example, in the form of 'packages' that they might choose between, accommodating their risk and cost preferences . A guide on best practices for choosing/surfacing network parameters will be released soon.
To participate in DAO governance, stakers or 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.
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.
The process for delegating liquid tokens and delegating staked tokens is distinct, and each are explained in the following subsections. 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.
Get involved in staking the Threshold Network
How to make edits
Refer to the following documentation here: https://docs.gitbook.com/
To contribute to Threshold documentation, the best place to start is to join the Discord. You can ask questions there and help contribute to documentation. Join here: http://discord.gg/threshold
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.
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.
Once the process completes, your public key will be displayed. Take note of your Operator Account public key.
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.
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:
2022-10-10T18:30:42.571Z WARN keep-beacon beacon/node.go:78 selecting group not possible: [cannot select group in the sortition pool: [got error [execution reverted: Sortition pool unlocked] while resolving original error [execution reverted: Sortition pool unlocked]]] {"seed": "0x29c60250c292e108e6abf4dcc76cb161d8ae8e803c4d4419eaff6e97f514b080"}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.
geth account new --keystore ./operator-keyB. 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 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.
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 to not imply any on-chain action (e.g. Council and Guild elections). In these cases, there is only a Snapshot vote, with no associated on-chain proposal).
Trust-minimized Access Control
Threshold Access Control enables end-to-end encrypted data sharing and communication without the need to trust a centralized authority. It is the only access control layer available to Web3 developers that has already achieved true decentralization through a live and well-collateralized network, with sensitive cryptographic operations disassembled and distributed across ~250 independently operated servers.
End-users of applications which have integrated Threshold Access Control enjoy the following features & benefits:
End-to-end encryption for everything. Built on the privacy-for-everyone principles of popular end-to-end encrypted messengers but applicable to a far wider set of use cases, including private NFTs, connected vehicles, DBaaS, live-streaming, private DAO group chats, and much more.
Trust-minimization via cryptography and true decentralization. Key management, condition verification and ciphertext re-encryption are operationally distributed across a geographically diverse array of machines/servers, operated by economically independent individuals and commercial entities.
Powerful, per-ciphertext conditionality. Future access to data can be contingent on the fulfillment of nearly any predefined condition, and those conditions attached to any granularity of data payload (e.g. a single message or an entire table).
Flexible condition composability. Conditions of all types can be mixed-and-matched using logical operators and flexible prefix notation into virtually any desired combination.
Tunable collusion-resistance, redundancy & latency. Developers have full control over the cohort(s) of node operators which manage access to a given data payload, user base or entire application. These security parameters can also be packaged into simpler user-facing optionality for custom risk preferences.
Highly incentivized uptime. Threshold Network's multi-app model strongly incentivizes node operators to provision service to tBTC, and its strict availability requirements. Threshold Access Control 'piggybacks' on tBTC uptime, reliability and technical competence.
Optional: keypair-only decryption. If even stricter security guarantees are required, and data recipients' public keys are known in advance, developers may opt for end-user data to be re-encrypted by node operators such that they are only decryptable by pre-designated clients.
The Threshold Access Control service is built on two distinct but interwoven technologies; Conditions-Based Decryption (CBD) and Proxy Re-Encryption (PRE). Both offer trust-minimized end-to-end encryption and access control is executed by the same decentralized array of nodes. There are some trade-offs between (explicit) security and access condition customization, which are explored in the section.
Note for Threshold stakers: the up-and-running 'PRE app' will eventually be renamed to encompass the broader Threshold Access Control service, and will also acquire new functionality via the addition of CBD technology. This will require a DAO-driven upgrade but will not fundamentally change the operational requirements or compensation.
How to delegate liquid T tokens
Liquid T holders who aren't staking on Threshold can delegate their token weights to themselves or a third party for voting on governance proposals.
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
Review available CLI Options below.
$ keep-client start --help
Starts the Keep Client in the foreground
Usage:
keep-client start [flags]
Flags:
--ethereum.url string WS connection URL for Ethereum client.
--ethereum.keyFile string The local filesystem path to Keep operator account keyfile.
--ethereum.miningCheckInterval duration The time interval in seconds in which transaction mining status is checked. If the transaction is not mined within this time, the gas price is increased and transaction is resubmitted. (default 1m0s)
--ethereum.maxGasFeeCap wei The maximum gas fee the client is willing to pay for the transaction to be mined. If reached, no resubmission attempts are performed. (default 500 gwei)
--ethereum.requestPerSecondLimit int Request per second limit for all types of Ethereum client requests. (default 150)
--ethereum.concurrencyLimit int The maximum number of concurrent requests which can be executed against Ethereum client. (default 30)
--ethereum.balanceAlertThreshold wei The minimum balance of operator account below which client starts reporting errors in logs. (default 500000000 gwei)
--network.bootstrap Run the client in bootstrap mode.
--network.peers strings Addresses of the network bootstrap nodes.
-p, --network.port int Keep client listening port. (default 3919)
--network.announcedAddresses strings Overwrites the default Keep client address announced in the network. Should be used for NAT or when more advanced firewall rules are applied.
--network.disseminationTime int Specifies courtesy message dissemination time in seconds for topics the node is not subscribed to. Should be used only on selected bootstrap nodes. (0 = none)
--storage.dir string Location to store the Keep client key shares and other sensitive data.
--clientInfo.port int Client Info HTTP server listening port. (default 9601)
--clientInfo.networkMetricsTick duration Client Info network metrics check tick in seconds. (default 1m0s)
--clientInfo.ethereumMetricsTick duration Client info Ethereum metrics check tick in seconds. (default 10m0s)
--tbtc.preParamsPoolSize int tECDSA pre-parameters pool size. (default 1000)
--tbtc.preParamsGenerationTimeout duration tECDSA pre-parameters generation timeout. (default 2m0s)
--tbtc.preParamsGenerationDelay duration tECDSA pre-parameters generation delay. (default 10s)
--tbtc.preParamsGenerationConcurrency int tECDSA pre-parameters generation concurrency. (default 1)
--tbtc.keyGenerationConcurrency int tECDSA key generation concurrency. (default number of cores)
--developer.bridgeAddress string Address of the Bridge smart contract
--developer.randomBeaconAddress string Address of the RandomBeacon smart contract
--developer.tokenStakingAddress string Address of the TokenStaking smart contract
--developer.walletRegistryAddress string Address of the WalletRegistry smart contract
Global Flags:
-c, --config string Path to the configuration file. Supported formats: TOML, YAML, JSON.
--developer Developer network
--goerli Görli network
--mainnet Mainnet network
Environment variables:
KEEP_ETHEREUM_PASSWORD Password for Keep operator account keyfile decryption.
LOG_LEVEL Space-delimited set of log level directives; set to "help" for help.Advanced configuration options and tBTC v2 staking client options
Here you'll find the Goerli testnet version of the Threshold dapp.
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.
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.
We will make the Signer set permissionless after we have solved some technical obstacles.
Minters and Guardians are here to stay, but will not be the only way to mint.
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 's #dao-contribute channel) and work together with other Threshold DAO members based on your interests and expertise!
The 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 is to build successful, synergistic and long-lasting relationships with other protocols, DAOs and external organizations.
The 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.
As the only genuinely decentralized access control service on the market, Threshold Access Control may also claim to be the most 'trustless' solution available to Web3 app buidlers – or indeed, available to any developer seeking an unambiguous departure from the exploitative Web 2.0 trust paradigm.
Nevertheless, there is no such thing as a third-party integration that imposes zero additional trust burden onto an application's end-users. Rather, when choosing infrastructural technology, it is the nature and texture of the trust burden(s) – or the 'trust assumptions' – that truly matter.
In the case of Threshold Access Control, the trust assumptions are: non-binary – i.e. not reducible to 'trustless' or 'trustful'.
non-static – i.e. they evolve over time based on in-protocol features and exogeneous phenomena. tunable – i.e. adopting developers may select from a range of explicit trust assumptions on behalf of their user base, and/or surface that optionality for end-users to choose themselves.
This section serves to explain the implicit and explicit trust assumptions that are baked into Threshold Access Control, for the and versions. These assumptions are synthesized and exposed to the vast majority of adopting developers in the form of pre-configured
When creating a new cohort, the configuration must include threshold, shares, and porterUri. We also make available the parameters include and exclude which can be used to filter particular Nodes.
A cohort can be serialized to a JSON object so that it can be stored and re-used at a later time.
Similarly, we can read in a valid JSON object to build a new Cohort.
Threshold Network Lingo
The Proof-of-Concept version exists to help developers familiarize themselves with the SDK, API and other architectural/design choices, ahead of the Mainnet version release in Q2 2023.. It is not intended to be utilized as a trust-minimized service. Hence, the trust assumptions are strictly worse than the Mainnet version. One can consider the following limitations to be appended on top of the Mainnet trust :
In the absence of a DKG component, the encryptor (or 'Alice') retains permanent decryption power, regardless of their condition fulfillment later – e.g. transferring the corresponding NFT out of their wallet.
Conditions can technically be 'stripped' from ciphertexts by a sophisticated user, which would enable them to maliciously gain decryption rights by presenting a ciphertext with no attached access conditionality.
Use Threshold Access Control for end-to-end encrypted, end-to-end decentralized data sharing and communication.
-> See in the Fundamentals section for an overview of the over-arching concepts and value propositions.
There are multiple products and versions under the umbrella of 'Threshold Access Control':
Conditions-Based Decryption, Proof-of-Concept Use this version to familiarize yourself with the SDK, API and developer-facing configuration/parametrization. Get started .
External documentation and examples
The node array managing decryption fragments – and validating condition (non/)fulfillment – are running on testnet, are operated primarily by NuCypher team-members, and are not subject to a cryptoeconomic protocol or a requirement to deposit/risk collateral.
Note that these three limitations will be addressed in the CBD Mainnet version. Upgrading from this version to the Mainnet version involves entirely replacing the underlying cryptosystem, which means all data encrypted via the Proof-of-Concept will have to be (downloaded and) encrypted again from plaintext utilizing the new cryptography.






Authorizer
An ethereum address appointed by an owner to authorize applications on behalf of the owner. An application must be approved by the authorizer before the staking provider is eligible to participate.
Beneficiary
An ethereum address where the rewards for participation are sent, earned by the staking provider, on behalf of the owner. A beneficiary doesn’t sign or publish any protocol-relevant transactions, but any currency or tokens earned by the staking provider will be transferred to the beneficiary.
Delegated stake
An owner’s staked tokens, delegated to the staking provider by the owner. Delegation enables token owners to have their wallets offline and their stake operated by staking providers on their behalf.
Application
An external smart contract or a set of smart contracts utilizing functionalities offered by Threshold Network. Example applications are: random beacon, proxy re-encryption, and tBTC. Applications authorized for the given staking provider are eligible to slash the stake delegated to that staking provider.
Threshold Cryptography
Threshold cryptography is a revolutionary technology that distributes sensitive operations across multiple independent entities – like nodes in a network – and requires a threshold, or minimum number of those entities to cooperate for the operation to be successful.
Staking Provider
An ethereum address of a party authorized to operate in the network on behalf of a given owner. The staking provider handles the everyday operations on the delegated stake without actually owning the staked tokens. A staking provider can not simply transfer away delegated tokens, however, it should be noted that the staking provider’s misbehavior may result in slashing tokens and thus the entire staked amount is indeed at stake.
Note that many projects in the Web3 infrastructure space seek to obscure this reality by loosely labelling their solution as 'decentralized', but fail to explain precisely what the trust implications are in practice. Beware of ambiguity!
It is possible to implement Revocation using Conditions that rely on a function call to a Custom Smart Contract. This allows the handling of revocation to be decentralized and transparent. Here is an example of a smart contract (not suitable for production):
pragma solidity 0.8.7;
contract Revocation {
mapping(address => bool) public isRevoked;
function revoke(address user) public {
isRevoked[user] = true;
}
function unRevoke(address user) public {
isRevoked[user] = false;
}
}And the associated Condition:
const revocationCondition = {
contractAddress: 'DEPLOYED_CONTRACT_ADDRESS',
method: 'isRevoked',
parameters: [':userAddress'],
functionAbi: {
inputs: [
{
internalType: 'address',
name: '',
type: 'address',
},
],
name: 'isRevoked',
outputs: [
{
internalType: 'bool',
name: '',
type: 'bool',
},
],
stateMutability: 'view',
type: 'function',
},
chain: 'ethereum',
returnValueTest: {
comparator: '==',
value: false,
},
};The condition we have defined calls the isRevoked function of the smart contract and passes the user's address. If the call returns false (not revoked, i.e. granted), then decryption will occur. If the call returns true (is revoked), then decryption will fail.
const config = {
threshold: 3,
shares: 5,
porterUri: 'https://porter-ibex.nucypher.community',
};
const newCohort = await Cohort.create(config, (include = []), (exclude = []));const cohortJSON = newCohort.toJSON();
console.log(cohortJSON);
// {
// "ursulaAddresses": [
// "0x5cf1703a1c99a4b42eb056535840e93118177232",
// "0x7fff551249d223f723557a96a0e1a469c79cc934",
// "0x9c7c824239d3159327024459ad69bb215859bd25"
// ],
// "threshold": 2,
// "shares": 3,
// "porterUri": "https://porter-ibex.nucypher.community"
// }const importedCohort = Cohort.fromJSON(cohortJSON);
console.log(importedCohort);
// Cohort {
// ursulaAddresses: [
// '0x5cf1703a1c99a4b42eb056535840e93118177232',
// '0x7fff551249d223f723557a96a0e1a469c79cc934',
// '0x9c7c824239d3159327024459ad69bb215859bd25'
// ],
// configuration: {
// threshold: 2,
// shares: 3,
// porterUri: 'https://porter-ibex.nucypher.community'
// }
// }During the early days of the system; the testnet and chaosnet phases, it is important to ensure that the Stakers 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, GG18, cannot identify misbehaving signers.
The point about GG18 is crucial. Without being able to identify misbehaving Stakers, 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 yet production-ready codebases.
They are not open source.
They exist only as whitepapers.
To address this issue, we have been developing a proof-of-concept for CGGMP and exploring FROST. Once we are confident in these areas, we will open up Custodianship to any staker running a node and staking the minimum amount of T. This will create a permissionless alternative to Optimistic Minting through the Guardians and Minters, albeit slightly slower.
Guardians and Minters will remain permissioned indefinitely, as they are a set of high-trust public operators with their reputations on the line. 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.
If a Guardian or Minter misbehaves, the Threshold DAO can vote to remove them.
Once sweeping is enabled and the Signers are permissionless, 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.
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 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.
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.
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.
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:
Wallets are created periodically based on governance. changes the time between wallets and 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 , requiring 51-of-100 Signers to cooperate.
The 100 signers on each wallet are chosen with our , and the randomness is provided by the .
The probability that a 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.
This page will guide you through Binary setup steps.
Download the client binary file, make sure you are in the correct directory.
After the download completes, use the command below to display the contents of the folder:
Extract the compressed file:
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:
For a complete list of client commands and flags, see .
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.


n2-highcpu-2
Self-hosted
2 vCPU / 2 GB RAM / 1 GiB Persistent Storage
AWS
c5.large
Azure
F2s v2
Google Cloud
Congratulations, your node is up and running.
$ curl localhost:9601/metrics
# TYPE connected_peers_count gauge
connected_peers_count 108 1623235129569
# TYPE connected_bootstrap_count gauge
connected_bootstrap_count 10 1623235129569
# TYPE eth_connectivity gauge
eth_connectivity 1 1623235129789$ curl localhost:9601/diagnostics
{
"client_info" {
"ethereum_address":"0xDcd4199e22d09248cA2583cBDD2759b2acD22381",
"network_id":"16Uiu2HAkzYFHsqbwt64ZztWWK1hyeLntRNqWMYFiZjaKu1PZgikN"
},
"connected_peers": [
{"ethereum_address":"0x3712C6fED51CECA83cA953f6FF3458f2339436b4","network_id":"16Uiu2HAkyYtzNoWuF3ULaA7RMfVAxvfQQ9YRvRT3TK4tXmuZtaWi"},
{"ethereum_address":"0x4bFa10B1538E8E765E995688D8EEc39C717B6797","network_id":"16Uiu2HAm9d4MG4LNrwkFmugD2pX7frm6ZmA4vE3EFAEjk7yaoeLd"},
{"ethereum_address":"0x650A9eD18Df873cad98C88dcaC8170531cAD2399","network_id":"16Uiu2HAkvjVWogUk2gq6VTNLQdFoSHXYpobJdZyuAYeoWD66e8BD"},
...
]
}cd /home/keep
wget https://github.com/keep-network/keep-core/releases/download/v2.0.0-m2/keep-client-mainnet-v2.0.0-m2-linux-amd64.tar.gzls -latar xzvf downloaded-file-name-here.tar.gz--ethereum.url "wss://mainnet-ETH-enpoint-here"
--mainnet
--storage.dir "/home/keep/storage"
--ethereum.keyFile "/home/keep/config/UTC--Your-Operator-Key-Name"
# to configure your node to use your machine's public IP
--network.announcedAddresses "/ip4/your.ipv4.address.here/tcp/3919"
# to configure your node to use DNS, provide your DNS in the following
# format
# /dns4/bootstrap-1.test.keep.network/tcp/3919
./keep-client start --ethereum.url "wss://mainnet-ETH-enpoint-here" --mainnet --storage.dir "/home/keep/storage" --ethereum.keyFile "/home/keep/config/UTC--Your-Operator-Key-Name" --network.announcedAddresses "/ip4/your.ipv4.address.here/tcp/3919"
▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀
▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌
▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓
Trust math, not hardware.
-----------------------------------------------------------------------------------
| Keep Client Node |
| |
| Version: Version: v2.0.0-m1 (4d745f6d0) |
| |
| Operator: 0x_your_operator_address |
| |
| Port: 3919 |
| IPs : /ip4/111.222.333.444/tcp/3919/ipfs/redacted |
| |
| Contracts: |
| RandomBeacon : 0x5499f54b4A1CB4816eefCf78962040461be3D80b |
| WalletRegistry : 0x46d52E41C2F300BC82217Ce22b920c34995204eb |
| TokenStaking : 0x01B67b1194C75264d06F808A921228a95C765dd7 |
-----------------------------------------------------------------------------------(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
nandpis the discrete probability distribution of the number of successes in a sequence ofnindependent 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.
That means we can use a Binomial Probability Calculator to answer our question:
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!
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:
✅ Bitcoin (BTC)
✅ Ethereum (ETH) for Ethereum transaction gas costs
✅ Bitcoin compatible wallet
✅ Ethereum compatible wallet
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.
🎉 You're ready to mint! Go to the tBTC dapp here:
Connect your preferred Ethereum wallet to the tBTC dapp by selecting Connect Wallet.
Navigate to the . 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.
🎉 You've successfully minted tBTC! 🎉
A Strategy combines all possible configuration parameters for using CBD. It takes the following parameters:
cohort - a Cohort object
conditionSet? - an optional ConditionSet. If used, all encryptions made via this strategy have a default Condition Set assigned
aliceSecretKey? - an optional Secret Key for the encrypter
bobSecretKey? - an optional SecretKey for decrypter
If the optional secret keys are not provided, new ones will be generated instead.
Assuming we have a Cohort already defined, we can construct a Strategy:
Before we can encrypt/decrypt, the Threshold network needs to be made aware of our Strategy. We do this by deploying:
Strategy.deploy takes 2 parameters:
label - this is a string that the network uses to identify the strategy
provider - deploying a Strategy requires writing to the smart contract, so a connection to a wallet is required via a Web3 provider
Deploying a strategy returns a new DeployedStrategy object. This object grants us access to the encrypter and decrypter which can then be used throughout an application.
Strategies can be exported allowing them to be reused easily. The syntax is the same whether the strategy has been deployed or not.
Similarly, we can import and export the decrypter objects to JSON. This allows us to rebuild the decrypter on a client facing application:
CBD allows adopting developers to pull a range of 'trust levers' in order to satisfy and assuage the trust, risk, cost, redundancy and latency preferences of their end-users. However, correctly selecting individual parameters across each and every trust/risk dimension requires a deep understanding of the underlying mechanisms and cryptology. Moreover, these parameters must be combined into a coherent bundle that, as a whole, aligns with the risk aversion and trust-minimization desiderata of end-users. Hence, to avoid burdening developers with onerous analysis, the Threshold team has constructed a set of pre-configured 'trust packages'. They are introduced and detailed .
The context for configuring the trust packages follows below.
The foundation of the Threshold Access Control trust model (and indeed, threshold cryptography in general) is the concept of a Cohort; a group of Threshold nodes temporarily employed to either:
Collectively generate and manage part of a public key that can be used to encrypt one or more data payloads.











Collectively manage a decryption fragment associated with a single data payload and provide the fragment to requesters who fulfill pre-specified conditions.
All Cohorts are parametrized on formation, including the Cohort size (n) and Cohort threshold (m). These parameters are the inputs for the following core trust assumptions:
The first is the orderly threshold assumption, wherein the protocol relies on a minimum number – the threshold – of node operators within each Cohort to follow the protocol correctly. For example, a 16-of-32 cohort would require at least 16 nodes to be online, responsive and (ideally) run an up-to-date version of CBD software. If any fewer than 16 are online, data requesters will be unable to retrieve decryption fragments.
The second is the honest threshold assumption, the protocol's most fundamental form of collusion-resistance – that is, protection against deliberate, unlawful attempts to access private data. In this case, the protocol relies on a minimum number of operators to be ‘honest’ – i.e. not susceptible to bribery, coercion or other attempts to maliciously collude. This minimum is calculated as the threshold node count (m) subtracted from the total cohort size, plus one (n - m + 1). Using the same example as before, a 16-of-32 Cohort would require a minimum of 32 - 16 + 1 = 17 honest operators. In other words, if at least 17 individual operators refuse to collude, there is nothing the remaining 15 operators can do, regardless of their war chest or aggregate stake power.
Note that the orderly threshold and honest threshold assumptions are conceptually similar to the more common honest majority assumption. However, they are more flexible than simply requiring those who control 50% of the staked tokens to be honest. Unlike most BFT or pBFT-based protocols, the honest threshold can be partially decoupled from the operators’ stake weights, depending on the cohort sampling parameters specified by the developer or end-user.
Some example cohort size and threshold configurations can be seen in Create Security Optionality With Reusable Cohorts
The orderly threshold and honest threshold trust assumptions above treat each Cohort as an isolated group, where the chosen parameters (m-of-n) determine the group’s redundancy, latency and collusion resistance. However, the reality is that each Cohort is selected from a larger sample of Threshold nodes, which is far larger than the typical/optimal size of each cohort – there is not necessarily much overlap between Cohorts.
Therefore, the mechanisms through which nodes are selected to form Cohorts carry their own trust assumptions. More specifically, the sampling parameters impact the security and collusion-resistance of a given data sharing flow. Sampling parametrization can be divided into; (1) those relating to frequency and prompting of (re-)sampling, and (2) compositional requirements to form a Cohort, besides the top-level m & n parameters.
Members of a Cohort can be replaced as frequently as is practical, with the main constraint being the bandwidth overhead of key discovery. A more regular re-sampling of Cohort members provides a form of increased collusion-resistance, as an attacker would have less time to discover, contact and bribe/coerce the requisite threshold of operators in order to access sensitive material.
The logic which prompts the refreshing of Cohort members is also customizable. For example, a group chat application might include the option to mark a conversation as 'sensitive', in which case messages sent within this conversation will be assigned to and managed by fresh Cohorts with a greater frequency (or randomness) than regular messages.
Developers may also toggle certain Cohort characteristics via the sampling mechanism. For example, they might force a percentage of Cohort positions to be filled exclusively by:
Node operators who have staked a minimum (or maximum) sum of T tokens.
Specific Ethereum addresses (e.g. nodes operated by the adopting developer themselves, or their partners).
Node operators who have not initiated stake unbonding in the past X months.
Node operators who also (or do not) provision service to other Threshold applications, such as tBTCv2.
Node operators who have a minimum historical availability (for example, as measured via their verifiable tBTCv2 activity).
The protocol is also permissionless and psuedonymous (Ethereum addresses), which means the total population of node operators will expand, contract and change its composition over time, and that change will not be perfectly discernible.
The node population is also non-uniform; rather, it is comprised of a heterogeneous set of operators, ranging from the hobbyist to institutional stakers. Although there is a degree of standardization with respect to requisite machine memory, CPU power, latency and availability, the actual underlying servers are only observable anecdotally – i.e. this cannot yet be verified on-chain. However, this anecdotal, informal insight into the node population can be supplemented and corroborated with conclusions drawn from on-chain activity, such as slashing or unbonding events.
import { Cohort, Strategy } from '@nucypher/nucypher-ts';
const config = {
threshold: 3,
shares: 5,
porterUri: 'https://porter-ibex.nucypher.community',
};
const newCohort = await Cohort.create(config);
const newStrategy = Strategy.create(
newCohort
);import detectEthereumProvider from '@metamask/detect-provider';
import providers from 'ethers';
const MMprovider = await detectEthereumProvider();
const mumbai = providers.providers.getNetwork(80001);
if (MMprovider) {
const web3Provider = new providers.providers.Web3Provider(
MMprovider,
mumbai
);
const newDeployed = await newStrategy.deploy('test', web3Provider);
}const encrypter = newDeployed.encrypter;
const decrypter = newDeployed.decrypter;
const plaintext = 'this is a secret';
const encryptedMessageKit = encrypter.encryptMessage(plaintext);
const decryptedMessage = await decrypter.retrieveAndDecrypt([
encryptedMessageKit,
]);import { DeployedStrategy } from '@nucypher/nucypher-ts';
const configJSON = newDeployed.toJSON();
console.log(configJSON);
/*
LARGE JSON OBJECT
*/
const importedStrategy = DeployedStrategy.fromJSON(configJSON);import { DeployedStrategy } from '@nucypher/nucypher-ts';
const decrypter = newDeployed.decrypter;
const decrypterJSON = decrypter.toJSON();
// save this JSON are send it over a side channel to a client facing app
// on the client app
import { tDecDecrypter } from '@nucypher/nucypher-ts';
const newDecrypter = tDecDecrypter.fromJSON(decrypterJSON);Delivered in @threshold-network/[email protected] package.
T Token
Delivered in @keep-network/[email protected] and @keep-network/[email protected] packages.
Delivered in @keep-network/[email protected] package.
This page will guide you through Docker setup steps.
Install or update Docker to the latest version. Visit the 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 (Rootless mode).
Next, choose ONE of the following options. 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.
Create the tbtcv2.service file:
Paste the following in the tbtcv2.service file:
This tutorial is a quick way for developers to learn about the Threshold Access Control service by building with the Proof-of-Concept (PoC) version of .
Note that the underlying vary between versions and technologies; these are explained in detail for the , , and versions.
To begin, we need to install the nucypher-ts library:
One of the nucypher-ts dependencies takes advantage of . In order to run nucypher-ts in the browser, we have to from the source files. This process is mostly automated by the wrapper generated by .
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:
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.
cd /etc/systemd/system/
nano tbtcv2.service[Unit]
Description=tBTC v2 client
After=network.target
Wants=network.target
[Service]
Environment="ETHEREUM_WS_URL=<Ethereum API WS URL>"
Environment="OPERATOR_KEY_FILE_NAME=<Operator Account keyfile name>"
Environment="OPERATOR_KEY_FILE_PASSWORD=<Operator Account keyfile password>"
Environment="PUBLIC_IP=/dns4/<PUBLIC_IP_OF_MACHINE>/tcp/3919"
Environment="CONFIG_DIR=/home/<user name>/keep/config"
Environment="STORAGE_DIR=/home/<user name>/keep/storage"
# These items only apply if you setup rootless-mode.
# Do not enable unless using rootless mode. Don't forget to adjust user UID.
#Environment="XDG_RUNTIME_DIR=/run/<user name>/<user UID>/"
#Environment="DOCKER_HOST=unix:///run/<user name>/<user UID>/docker.sock"
Type=simple
WorkingDirectory=/home/<user>
ExecStart=/usr/bin/docker run \
--volume ${CONFIG_DIR}:/mnt/keep/config \
--volume ${STORAGE_DIR}:/mnt/keep/storage \
--env KEEP_ETHEREUM_PASSWORD=${OPERATOR_KEY_FILE_PASSWORD} \
--env LOG_LEVEL=info \
--log-opt max-size=100m \
--log-opt max-file=3 \
-p 3919:3919 \
-p 9601:9601 \
keepnetwork/keep-client:latest \
start \
--ethereum.url ${ETHEREUM_WS_URL} \
--ethereum.keyFile /mnt/keep/config/${OPERATOR_KEY_FILE_NAME} \
--storage.dir /mnt/keep/storage \
--network.announcedAddresses $PUBLIC_IP
Restart=always
RestartSec=15s
[Install]
WantedBy=default.target
nano keep.sh# Keep tBTC v2 Client
#
# Ethereum endpoint WebSocket URL
# This can be a provider such as Infura, Alchemy, Ankr, etc or your own Geth Nodeq
# ETHEREUM_WS_URL="wss://mainnet.infura.io/ws/v3/redacted_credentials"
# note: only replace characters inside the " ". The Quotation marks must be retained
ETHEREUM_WS_URL="<Ethereum API WS URL>"
# copied to home/keep/config earlier
OPERATOR_KEY_FILE_NAME="<Operator Account keyfile name>"
# password set during Operator Account Address creation
OPERATOR_KEY_FILE_PASSWORD="<Operator Account keyfile password>"
# To configure your node with a Public IP, enter it below.
PUBLIC_IP="<PUBLIC_IP_OF_MACHINE>"
# Alternatively, you can use DNS.
# To configure DNS, modify the last line of the script
# and add your DNS in the following format:
# /dns4/bootstrap-1.test.keep.network/tcp/3919
# Setup configuration and storage directories
# THESE MUST BE PERSISTENT STORAGE
CONFIG_DIR="/home/keep/config"
STORAGE_DIR="/home/keep/storage"
docker run \
--detach \
--restart on-failure \
--volume $CONFIG_DIR:/mnt/keep/config \
--volume $STORAGE_DIR:/mnt/keep/storage \
--env KEEP_ETHEREUM_PASSWORD=$OPERATOR_KEY_FILE_PASSWORD \
--env LOG_LEVEL=info \
--log-opt max-size=100m \
--log-opt max-file=3 \
-p 3919:3919 \
-p 9601:9601 \
keepnetwork/keep-client:latest \
start \
--ethereum.url $ETHEREUM_WS_URL \
--ethereum.keyFile /mnt/keep/config/$OPERATOR_KEY_FILE_NAME \
--storage.dir /mnt/keep/storage \
--network.announcedAddresses /ip4/$PUBLIC_IP/tcp/3919
sudo chmod +x keep.shsudo bash keep.shdocker --versionsudo systemctl start tbtcv2sudo systemctl status tbtcv2docker pssystemctl enable tbtcv2reboot nowsudo docker pssudo docker logs stinky_brownie >& /path/to/output/file
▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀
▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌
▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓
Trust math, not hardware.
-----------------------------------------------------------------------------------
| Keep Client Node |
| |
| Version: Version: v2.0.0-m1 (4d745f6d0) |
| |
| Operator: 0x_your_operator_address |
| |
| Port: 3919 |
| IPs : /ip4/111.222.333.444/tcp/3919/ipfs/redacted |
| |
| Contracts: |
| RandomBeacon : 0x5499f54b4A1CB4816eefCf78962040461be3D80b |
| WalletRegistry : 0x46d52E41C2F300BC82217Ce22b920c34995204eb |
| TokenStaking : 0x01B67b1194C75264d06F808A921228a95C765dd7 |
-----------------------------------------------------------------------------------Integrations Guild Multisig
Marketing Guild Multisig
TBTC
TBTCVault
VendingMachine
WalletRegistry
CoveragePool
TokenStaking
KeepStake
NU<>T Vending Machine
KEEP<>T Vending Machine
GovernorBravo TimelockController
Council Multisig
Bridge
RandomBeacon
PRE Application
SubscriptionManager (Polygon-mainnet)
NU Token
StakingEscrow
KEEP Token
TokenStaking
Treasury Guild Multisig
WorkLock
Visit nucypher-ts/examples for more information on using nucypher-ts in your web application.
Next, we will create a Cohort based on our risk preferences. A Cohort is a group of nodes that work together to control access to data. Threshold and Shares are two parameters used to create a Cohort. For example, a 3-of-5 Cohort needs at least 3 of the 5 members to provide shares to access the original data.
To create a Cohort, use the following code:
Notice that we provided a porterUri parameter. Porter is a web-based service that interacts with nodes on the network on behalf of applications. It acts as an "Infura for Threshold Access Control". In this example, we used a Porter endpoint for the tapir testnet.
Conditions are the requirements for a data requester or recipient to access the plaintext data – i.e. what they will need to prove later to gain decryption rights.
The ERC721Ownership condition checks the owner of a given token ID. It can be customized by using the ownerOf contract method and comparing it with the requestor's signature. For more information, see the References section.
We will now specify the conditions that must be met to access the data. In this tutorial, we will require that the requester owns an ERC721 token with a token ID of 5954.
We will now combine the Cohort, ConditionSet, and any other necessary parameters into a Strategy. Strategies are a convenient way to bundle together frequently used configurations, including specific combinations of network parameters and conditionality.
Next, we will deploy this Strategy to the Threshold Network. To do that, we're going to transact on Polygon Mumbai:
For more information about customizing and reusing Cohort, Condition, and Strategy objects, see the References page in the documentation.
We can now encrypt data using the newly deployed Strategy. At this point, we can also specify new conditions on which data access will be predicated. These will take a higher precedence and override the default conditions contained in the Strategy. For this example, let's make it so the overriding requirement is that the requester's wallet hold a minimum number (three) of NFTs. The NFTs are from the same collection that we specified in Step 3. Note that Threshold nodes will check this new condition using the balanceOf method.
To encrypt the plaintext:
The resulting encryptedMessageKit contains the encrypted data and associated condition(s).
Finally, we will test the conditional access control service by requesting decryption rights:
At decryption time, the requester will be asked to verify their address by signing a message in MetaMask. This is where conditionContext comes into play – if the requester's address controls the minimum number (or greater) of the specified NFT, they are eligible to receive the requisite number of decryption fragments. By assembling these fragments, they are able to decrypt and view the plaintext encrypted in the previous step.
The following samples showcase integrations with React-based web apps, and serve as an 'end-to-end' reference for creating conditions-based encryption & decryption:
yarn add @nucypher/nucypher-tsyarn add ethers @metamask/detect-providerimport { Cohort } from '@nucypher/nucypher-ts';
const config = {
threshold: 3,
shares: 5,
porterUri: 'https://porter-tapir.nucypher.community',
};
const newCohort = await Cohort.create(config);import { Conditions } from '@nucypher/nucypher-ts';
const NFTOwnership = new Conditions.ERC721Ownership({
contractAddress: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
chain: 5, // Tapir network uses Görli testnet
parameters: [5954],
});import { Conditions, ConditionSet } from '@nucypher/nucypher-ts';
const conditions = new ConditionSet([
NFTOwnership,
// Other conditions can be added here
]);import { Strategy } from '@nucypher/nucypher-ts';
const newStrategy = Strategy.create(newCohort, conditions);import detectEthereumProvider from '@metamask/detect-provider';
import { providers } from 'ethers';
const MMprovider = await detectEthereumProvider();
const mumbai = providers.getNetwork(80001);
const web3Provider = new providers.Web3Provider(MMprovider, mumbai);
const newDeployed = await newStrategy.deploy('test', web3Provider);const NFTBalanceConfig = {
contractAddress: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
standardContractType: 'ERC721',
chain: 5,
method: 'balanceOf',
parameters: [':userAddress'],
returnValueTest: {
comparator: '>=',
value: 3,
},
};
const NFTBalance = new Conditions.Condition(NFTBalanceConfig);
const encrypter = newDeployed.encrypter;
const plaintext = 'this is a secret';
const encryptedMessageKit = encrypter.encryptMessage(
plaintext,
new ConditionSet([NFTBalance])
);const decrypter = newDeployed.decrypter;
const conditionContext = conditions.buildContext(web3Provider);
const decryptedMessage = await decrypter.retrieveAndDecrypt(
[encryptedMessageKit],
conditionContext
);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 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.
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.
export KEEP_CLIENT_CONFIG_DIR=$(pwd)/config
export KEEP_CLIENT_ETHEREUM_WS_URL="<Ethereum API WS URL>"
export STAKING_PROVIDER_KEY_FILE_PASSWORD="<Staking Provider Account Key File Password>"
export STAKING_PROVIDER_KEY_FILE_NAME="<Staking Provider Account Key File Name>"
export OPERATOR_ADDRESS="<Operator Account Address>"
docker run \
--volume $KEEP_CLIENT_CONFIG_DIR:/mnt/keep-client/config \
--env KEEP_CLIENT_ETHEREUM_PASSWORD=$STAKING_PROVIDER_KEY_FILE_PASSWORD
us-docker.pkg.dev/keep-test-f3e0/public/keep-client:latest \
ethereum \
--ethereum.url $KEEP_CLIENT_ETHEREUM_WS_URL \
--ethereum.keyFile /mnt/keep-client/config/$STAKING_PROVIDER_KEY_FILE_NAME \
beacon random-beacon register-operator --submit \
$OPERATOR_ADDRESSexport KEEP_CLIENT_CONFIG_DIR=$(pwd)/config
export KEEP_CLIENT_ETHEREUM_WS_URL="<Ethereum API WS URL>"
export STAKING_PROVIDER_KEY_FILE_PASSWORD="<Staking Provider Account Key File Password>"
export STAKING_PROVIDER_KEY_FILE_NAME="<Staking Provider Account Key File Name>"
export OPERATOR_ADDRESS="<Operator Account Address>"
docker run \
--volume $KEEP_CLIENT_CONFIG_DIR:/mnt/keep-client/config \
--env KEEP_CLIENT_ETHEREUM_PASSWORD=$STAKING_PROVIDER_KEY_FILE_PASSWORD
us-docker.pkg.dev/keep-test-f3e0/public/keep-client:latest \
ethereum \
--ethereum.url $KEEP_CLIENT_ETHEREUM_WS_URL \
--ethereum.keyFile /mnt/keep-client/config/$STAKING_PROVIDER_KEY_FILE_NAME \
ecdsa wallet-registry register-operator --submit
$OPERATOR_ADDRESSStakes on Threshold can take the following forms:
T stake using liquid T created on the Threshold Dashboard
Legacy NU stake migrated to T from the NuCypher Dashboard
Legacy KEEP stake migrated to T from the Keep Dashboard
Here is a summary of the overall process:
Go to
Connect your wallet
Your T balance will be shown - click on "Stake"
There will be a pop-up describing the staking process; click the check-box to acknowledge you have read the requirements
Go to
Click "Stake NU on Threshold"
Authorize Threshold Staking for the Keep Network legacy stake -
Got 2 minutes? Check out an introduction video to the Threshold Network:
Follow our handy guides to get started on staking basics as quickly as possible:
Staking on ThresholdLearn the fundamentals of the Threshold Network to get a deeper understanding of our main features:
tBTC Bitcoin BridgeThreshold Access ControlA Bitcoin-backed Stablecoin
Threshold USD (thUSD) is a stablecoin soft-pegged against USD and backed by ETH and tBTC as collaterals with a minimum collateral ratio of 110%.
With either BTC or ETH as your collateral, you'll be able to borrow USD at low interest rate.
Threshold USD is a modified fork of 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, is completed through an .
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.
Choose an amount of T to stake and confirm the transaction



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.


You can delegate running an application node to one of the node-as-a-service Staking Providers listed below.
Conditions can be combined into Condition Sets using AND and OR operators.
The below example shows how to authenticate that a requester owns an NFT in one of two different collections.
If we wanted to store this Condition Set for later use we could export it to JSON:
And then easily import:
Security Policies for Threshold Network
If you identify vulnerabilities with any Threshold Network code, please email with relevant information to your findings. We will work with researchers to coordinate vulnerability disclosure between our stakers, partners, and users to ensure the successful mitigation of vulnerabilities.
Throughout the reporting process, we expect researchers to honor an embargo period that may vary depending on the severity of the disclosure. This ensures that we have the opportunity to fix any issues, identify further issues (if any), and inform our users.
Sometimes vulnerabilities are more sensitive in nature and require extra precautions. We are happy to work together to use a more secure medium, such as Signal. Email and we will coordinate a communication channel that we're both comfortable with.
A great place to begin your research is by working on our testnet. Please see our to get started. We ask that you please respect network machines and their owners. If you find a vulnerability that you suspect has given you access to a machine against the owner's permission, stop what you're doing and immediately email .
The Threshold team will make its best effort to respond to a new report within 48 hours
const genuineUndead = new Conditions.ERC721Balance({
contractAddress: '0x209e639a0EC166Ac7a1A4bA41968fa967dB30221',
});
const gnomePals = new Conditions.ERC721Balance({
contractAddress: '0x5dB11d7356aa4C0E85Aa5b255eC2B5F81De6d4dA',
});
const NFTConditionSet = new ConditionSet([
genuineUndead,
Operator.OR(),
gnomePals,
]);const NFTConditionSetJSON = NFTConditionSet.toJSON();
console.log(NFTConditionSetJSON);
// [
// {
// "chain": "ethereum",
// "method": "balanceOf",
// "parameters": [
// ":userAddress"
// ],
// "standardContractType": "ERC721",
// "returnValueTest": {
// "comparator": ">",
// "value": 0
// },
// "contractAddress": "0x209e639a0EC166Ac7a1A4bA41968fa967dB30221"
// },
// {
// "operator": "or"
// },
// {
// "chain": "ethereum",
// "method": "balanceOf",
// "parameters": [
// ":userAddress"
// ],
// "standardContractType": "ERC721",
// "returnValueTest": {
// "comparator": ">",
// "value": 0
// },
// "contractAddress": "0x5dB11d7356aa4C0E85Aa5b255eC2B5F81De6d4dA"
// }
// ]const newConditionSet = ConditionSet.fromJSON(NFTConditionSetJSON);The Threshold team will try to make an initial assessment of a bug's relevance, severity, and exploitability, and communicate this back to the reporter.
The Threshold DAO does have a bug bounty available, which is dispensed on a case-by-case basis.
The following Bug Bounty amounts were approved by the DAO in the TIP-041 proposal:
Critical: Up to $500,000 in T tokens.
High: Up to $50,000 in T tokens.
Medium: Up to $5,000 in T tokens.
Low: Up to $500 in T tokens.
The following attacks are excluded from the Bug Bounty program:
Attacks that the reporter has already exploited themselves, leading to damage.
Attacks requiring access to leaked keys/credentials.
Basic economic governance attacks (e.g. 51% attack).
Lack of liquidity.
Sybil attacks.
The following activities are prohibited by this bug bounty program:
Any testing with mainnet or public testnet contracts; all testing should be done on private testnets.
Attempting phishing or other social engineering attacks against our contributors and/or users.
Any denial of service attacks.
Automated testing of services that generates significant amounts of traffic.
Public disclosure of an unpatched vulnerability in an embargoed bounty.
Rewards are distributed according to the impact of the vulnerability based on the Immunefi Vulnerability Severity Classification System V2.2. This is a simplified 5-level scale, with separate scales for websites/apps, smart contracts, and blockchains/DLTs, focusing on the impact of the vulnerability reported.
Threshold DAO is currently in the process of establishing a Bug Bounty program on Immunefi.
Download, install, build, and test with:
Install git hooks
Generate contract typings
Prepare a new release
To launch a local development version of the documentation:
This will launch a local server, available at http://localhost:3000.
To release a new version of the documentation:
Publish a new release on NPM.
Pay attention to the output of these commands and fix your release if needed.
Follow instructions from the command output to finalize the process.
git clone https://github.com/nucypher/nucypher-ts
cd nucypher-ts
yarn install
yarn build
yarn testnpx husky installyarn typechainyarn run prepare-releasecd website
yarn run startyarn run docusaurus docs:version 1.1.0Optional logging configuration for the tBTC v2 staking client.
Logging can be configured with environment variables. Please see sample settings:
LOG_LEVEL=DEBUG
IPFS_LOGGING_FMT=nocolor
GOLOG_FILE=/var/log/keep/keep.log
GOLOG_TRACING_FILE=/var/log/keep/trace.jsonyarn prepare-release
# Or, to publish an alpha release
yarn prepare-release:alphaUpdate procedure for the tBTC v2 client depends on installation method
The following instructions assume your docker install followed these installation instructions.
These steps are specific to the Client: v2.0.0-m2 (Mainnet) release and may change.
The latest release is available on GitHub.
Open the systemd service file created during the initial install.
~/etc/systemd/system/The install instructions named the service tbtcv2.service. Locate your service file and open it in your prefered editor. For simplicity we use nano here. You may need sudo.
sudo nano tbtcv2.serviceThe service should look like this:
Locate the following line:
Make the following change to this line only:
Save and exit the service file.
Reload the daemon and restart the service:
Verify your client updated by visiting your status page:
Look for :
If you simply used the docker container launch script, the following change needs to be made to the script prior to relaunching the script.
Open the launch script from your storage location
Locate the following line:
Make the following change to this line only:
Save and exit the service file.
Use the following to determine your docker container's name
The ID of your tBTC v2 container will be shown, copy the container ID and paste it into the folowing:
To launch the tBTC v2 client again, execute:
This install method requires downloading the latest version of the binary. Follow the installation steps provided .
[Unit]
Description=tBTC v2 client
After=network.target
Wants=network.target
[Service]
Environment="ETHEREUM_WS_URL=<Ethereum API WS URL>"
Environment="OPERATOR_KEY_FILE_NAME=<Operator Account keyfile name>"
Environment="OPERATOR_KEY_FILE_PASSWORD=<Operator Account keyfile password>"
Environment="PUBLIC_IP=/dns4/<PUBLIC_IP_OF_MACHINE>/tcp/3919"
Environment="CONFIG_DIR=/home/<user name>/keep/config"
Environment="STORAGE_DIR=/home/<user name>/keep/storage"
# These items only apply if you setup rootless-mode.
# Do not enable unless using rootless mode. Don't forget to adjust user UID.
#Environment="XDG_RUNTIME_DIR=/run/<user name>/<user UID>/"
#Environment="DOCKER_HOST=unix:///run/<user name>/<user UID>/docker.sock"
Type=simple
WorkingDirectory=/home/<user>
ExecStart=/usr/bin/docker run \
--volume ${CONFIG_DIR}:/mnt/keep/config \
--volume ${STORAGE_DIR}:/mnt/keep/storage \
--env KEEP_ETHEREUM_PASSWORD=${OPERATOR_KEY_FILE_PASSWORD} \
--env LOG_LEVEL=info \
--log-opt max-size=100m \
--log-opt max-file=3 \
-p 3919:3919 \
-p 9601:9601 \
keepnetwork/keep-client:latest \
start \
--ethereum.url ${ETHEREUM_WS_URL} \
--ethereum.keyFile /mnt/keep/config/${OPERATOR_KEY_FILE_NAME} \
--storage.dir /mnt/keep/storage \
--network.announcedAddresses $PUBLIC_IP
Restart=always
RestartSec=15s
[Install]
WantedBy=default.target
Providing configurable security to end-users is easy with Reusable Cohorts. Below we define three cohorts: small, medium, and large.
smallCohort, mediumCohort, and largeCohort can then be reused by multiple Strategies.
const smallConfig = {
threshold: 3,
shares: 5,
porterUri: 'https://porter-tapir.nucypher.community',
};
const mediumConfig = {
threshold: 11,
shares: 20,
porterUri: 'https://porter-tapir.nucypher.community',
};
const largeConfig = {
threshold: 51,
shares: 100,
porterUri: 'https://porter-tapir.nucypher.community',
};
const smallCohort = await Cohort.create(smallConfig);
const mediumCohort = await Cohort.create(mediumConfig);
const largeCohort = await Cohort.create(largeConfig);keepnetwork/keep-client:latest \keepnetwork/keep-client:v2.0.0-m2 \ sudo systemctl daemon-reload
sudo systemctl restart tbtcv2http://111.222.333.444:9601/metricsclient_info{version="v2.0.0-m2"}nano keep.shkeepnetwork/keep-client:latest \keepnetwork/keep-client:v2.0.0-m2 \sudo docker pssudo docker kill CONTAINER_IDsudo bash keep.shA 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-majoriy-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. An insurance backstop (the coverage pools), serves as an emergency fallback in the event a wallet is compromised.
Unlike other solutions on the market, users of tBTC trust math, not hardware or people.
Threshold application – underlying technology
PRE is an end-to-end encryption protocol that is a more scalable, more flexible form of public-key encryption and enables a group of proxy entities to transform encrypted data from one public key to another, without the power to decrypt the data or gain access to any private keys. PRE equips developers, applications and end-users with secrets management and dynamic access control capabilities. The nodes on the Threshold Network act as these proxy entities and use threshold cryptography to securely and cooperatively re-encrypt data for recipients based on access conditions defined by the data owner.
PRE is directly applicable to use cases that aim to maintain data ownership while facilitating data sharing capabilities such as paid subscriptions to encrypted content, or the transfer of data ownership for encrypted NFTs. Data, wherever stored, remains private and encrypted while data owners maintain the ability to share that data and cryptographically enforce access controls. Want to get started staking with Threshold and running a node for PRE? Follow this guide:
PRE Node SetupCompilation of current multisigs for the Threshold Council and Guilds
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.
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.
The work directory contains data generated by the client that should persist the client restarts or relocations. If the
workAssuming 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
cd /home
mkdir keep
cd keep
mkdir storage configcd ~/operator-keyls -la
cp name_of_account_key_file /home/keep/config/name_of_account_key_fileThis page focuses on Condition types and composition. To understand how Conditions are added and enforced with respect to runtime, check out the Condition Hierarchies page. Several distinct categories of access conditions can be specified and combined:
EVM - on-chain state, eg NFT ownership, ETH balance, tx status, contract function call
RPC - ethereum RPC calls as defined in the Official API
Timelock - time-based conditions, eg Block Height
We provide many helper objects to streamline the creation of common conditions. An expressive API also allows much more granular control of conditions, and we will provide examples of both methods wherever possible.
Conditions.ERC721Ownership is a shortcut for building conditions that test for ownership of a specific ERC721 token (NFT):
If we want to be more verbose we can use Conditions.Condition. The above and below examples are completely equivalent:
Conditions.ERC721Balance is a shortcut for building conditions that test for ownership of at least one ERC721 token (NFT) within a collection.
Alternatively:
Conditions.TimelockCondition is a shortcut for building conditions that test against block height.
or:
Conditions.RpcCondition is a shortcut for building conditions that test against standard .
or:
Conditions.Condition provides full control over the configuration of a Condition. It takes parameters:
contractAddress is the public address of the contract we'd like to query.
standardContractType can take values from ERC20 and ERC721. Alternatively, an ABI can be passed through if a non standard contract is being used.
Here we're checking whether the user owns any T Threshold Network token:
In this example, we will check that the user is able to vote in the T Threshold DAO. The Threshold staking contract is located at . The function we wish to call is getVotes which takes an address as its parameter. We need to provide the contractAddress, functionName, functionParams, and functionAbi when defining the condition.
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
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.
To read more about multiaddress see the .
Conditions can be attached at several steps in the TAC lifecycle, and they have a fixed hierarchy at runtime. This means default Conditions can be specified and subsequently overwritten later on in the process.
Conditions can be attached directly to a Strategy. They have the lowest precedence and are a great place for including defaults or 'fall back' conditions.
import { Cohort, Conditions, ConditionSet, Strategy } from '@nucypher/nucypher-ts';
const config = {
threshold: 3,
shares: 5,
porterUri: 'https://porter-tapir.nucypher.community',
};
const newCohort = await Cohort.create(config);
const NFTOwnership = new Conditions.ERC721Ownership({
contractAddress: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
chain: 5, // Tapir network uses Görli testnet
parameters: [5954],
})
const conditions = new ConditionSet([NFTOwnership]);
const newStrategy = Strategy.create(
newCohort,
conditions
);All encrypter objects that a deployed Strategy produces will automatically have these conditions included. Therefore, all encrypted messages will require these conditions to be satisfied.
This is the next level of precedence in the hierarchy, where each encrypter object can have its own conditions. Assuming the above strategy has been deployed, we can attach conditions in the following way:
const encrypter = deployedStrategy.encrypter;
const newNFTOwnership = new Conditions.ERC721Ownership({
contractAddress: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
chain: 5,
parameters: [5000], // let's change the specific NFT
})
encrypter.conditions = new ConditionSet([newNFTOwnership])This will overwrite the Strategy conditions we defined above - only the new Conditions will be evaluated, not both. All messages encrypted with encrypter will require newNFTOwnership to be satisfied.
This is the final, and highest priority, Condition type. When encrypting a message, Conditions can be added that apply only to this specific encryption. Again, they will overwrite any Conditions specified during Strategy creation or within the encrypter.
Here we've actually made our Condition more relaxed, and only require a non-zero balance with the NFT contract.
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.
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.
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.
Network
network.port
TCP
3919
Status
clientInfo.port
TCP
9601
const NFTBalance = new Conditions.ERC721Balance({
contractAddress: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
chain: 5,
});
const plaintext = 'this is a secret';
const encryptedMessageKit = encrypter.encryptMessage(plaintext, new ConditionSet([NFTBalance]));functionAbi is the ABI of the function we'd like to call. This is optional if the contract is a standard ERC20, ERC721 or ERC1155.chain - currently only ethereum is supported, please if you require non-Ethereum based conditions.
method the contract method that will be called.
parameters are the parameters that will be passed to the contract's method.
returnValueTest defines how the return value of the contract call should be evaluated.
const NFTOwnership = new Conditions.ERC721Ownership({
contractAddress: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
// check for ownership of NFT with token ID 5954
parameters: [5954],
});const NFTOwnershipConfig = {
contractAddress: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
standardContractType: 'ERC721',
chain: 1,
method: 'ownerOf',
parameters: [5954],
returnValueTest: {
comparator: '==',
value: ':userAddress',
},
};
const NFTOwnership = new Conditions.Condition(NFTOwnershipConfig);const NFTBalance = new Conditions.ERC721Balance({
contractAddress: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
});const NFTBalanceConfig = {
contractAddress: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
standardContractType: 'ERC721',
chain: 5,
method: 'balanceOf',
parameters: [':userAddress'],
returnValueTest: {
comparator: '>',
value: 0,
},
};
const NFTBalance = new Conditions.Condition(NFTBalanceConfig);const timelock = Conditions.TimelockCondition({
returnValueTest: {
comparator: '>',
value: 100,
},
});const timelockConfig = {
contractAddress: '',
standardContractType: '',
chain: 5,
method: 'timelock',
returnValueTest: {
comparator: '>',
value: 100,
},
};
const timelock = Conditions.Condition(timelockConfig);const rpc = new Conditions.RpcCondition({
chain: 1,
method: 'eth_getBalance',
parameters: [
":userAddress",
"latest"
],
returnValueTest: {
comparator: ">=",
value: 10000000000000
}
});const rpcConfig = {
contractAddress: '',
standardContractType: '',
chain: 1,
method: 'eth_getBalance',
parameters: [':userAddress', 'latest'],
returnValueTest: {
comparator: '>=',
value: 10000000000000,
},
};
const rpc = Conditions.Condition(rpcConfig);const ERC20Conditions = {
contractAddress: '0xCdF7028ceAB81fA0C6971208e83fa7872994beE5',
standardContractType: 'ERC20',
chain: 5,
method: 'balanceOf',
parameters: [':userAddress'],
returnValueTest: {
comparator: '>',
value: 0,
},
};const customABICondition = {
contractAddress: '0x01B67b1194C75264d06F808A921228a95C765dd7',
method: 'getVotes',
parameters: [':userAddress'],
functionAbi: {
inputs: [
{
internalType: 'address',
name: 'account',
type: 'address',
},
],
name: 'getVotes',
outputs: [
{
internalType: 'uint96',
name: '',
type: 'uint96',
},
],
stateMutability: 'view',
type: 'function',
},
chain: 1,
returnValueTest: {
comparator: '>',
value: 0,
},
};




Delivered in @threshold-network/[email protected] NPM package.
T Token
Delivered in @keep-network/[email protected] NPM package.
Delivered in @keep-network/[email protected], @keep-network/[email protected] and @keep-network/[email protected] NPM packages.
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:
./keep-client --config /path/to/your/config.toml start# This is a sample TOML configuration file for the Keep client.
[ethereum]
URL = "ws://127.0.0.1:8546"
KeyFile = "/Users/someuser/ethereum/data/keystore/UTC--2018-03-11T01-37-33.202765887Z--AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAAAAAAAA"
# Uncomment to override the defaults for transaction status monitoring.
# MiningCheckInterval is the interval in which transaction
# mining status is checked. If the transaction is not mined within this
# time, the gas price is increased and transaction is resubmitted.
#
# MiningCheckInterval = 60 # 60 sec (default value)
# MaxGasFeeCap specifies the maximum gas fee cap the client is
# willing to pay for the transaction to be mined. The offered transaction
# gas cost can not be higher than the max gas fee cap value. If the maximum
# allowed gas fee cap is reached, no further resubmission attempts are
# performed. This property should be set only for Ethereum. In case of
# legacy non-EIP-1559 transactions, this field works in the same way as
# `MaxGasPrice` property.
#
# MaxGasFeeCap = "500 Gwei" # 500 Gwei (default value)
# Uncomment to enable Ethereum node rate limiting. Both properties can be
# used together or separately.
#
# RequestsPerSecondLimit sets the maximum average number of requests
# per second which can be executed against the Ethereum node.
# All types of Ethereum node requests are rate-limited,
# including view function calls.
#
# RequestsPerSecondLimit = 150
# ConcurrencyLimit sets the maximum number of concurrent requests which
# can be executed against the Ethereum node at the same time.
# This limit affects all types of Ethereum node requests,
# including view function calls.
#
# ConcurrencyLimit = 30
# BalanceAlertThreshold defines a minimum value of the operator's account
# balance below which the client will start reporting errors in logs.
# A value can be provided in `wei`, `Gwei` or `ether`, e.g. `7.5 ether`,
# `7500000000 Gwei`.
#
# BalanceAlertThreshold = "0.5 ether" # 0.5 ether (default value)
[network]
Bootstrap = false
Peers = [
"/ip4/127.0.0.1/tcp/3919/ipfs/16Uiu2HAmFRJtCWfdXhZEZHWb4tUpH1QMMgzH1oiamCfUuK6NgqWX",
]
Port = 3920
# Uncomment to override the node's default addresses announced in the network
# AnnouncedAddresses = ["/dns4/example.com/tcp/3919", "/ip4/80.70.60.50/tcp/3919"]
# Uncomment to enable courtesy message dissemination for topics this node is
# not subscribed to. Messages will be forwarded to peers for the duration
# specified as a value in seconds.
# Message dissemination is disabled by default and should be enabled only
# on selected bootstrap nodes. It is not a good idea to enable dissemination
# on non-bootstrap node as it may clutter communication and eventually lead
# to blacklisting the node. The maximum allowed value is 90 seconds.
#
# DisseminationTime = 90
[storage]
Dir = "/my/secure/location"
# ClientInfo exposes metrics and diagnostics modules.
#
# Metrics collects and exposes information useful for external monitoring tools usually
# operating on time series data.
# All values exposed by metrics module are quantifiable or countable.
#
# The following metrics are available:
# - connected peers count
# - connected bootstraps count
# - eth client connectivity status
#
# Diagnostics module exposes the following information:
# - list of connected peers along with their network id and ethereum operator address
# - information about the client's network id and ethereum operator address
[clientInfo]
Port = 9601
# NetworkMetricsTick = 60
# EthereumMetricsTick = 600
# Uncomment to overwrite default values for TBTC config.
#
# [tbtc]
# PreParamsPoolSize = 3000
# PreParamsGenerationTimeout = "2m"
# PreParamsGenerationDelay = "10s"
# PreParamsGenerationConcurrency = 1
# KeyGenConcurrency = 1
# Developer options to work with locally deployed contracts
#
# [developer]
# TokenStakingAddress = "0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
# RandomBeaconAddress = "0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
# WalletRegistryAddress = "0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
# BridgeAddress = "0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"TokenStaking
KeepStake
NU<>T Vending Machine
KEEP<>T Vending Machine
NU Token
StakingEscrow (stub)
KEEP Token
TokenStaking
Simple PRE Application (Tapir testnet)
Bridge
RandomBeacon
TBTC
TBCTVault
VendingMachine
WalletRegistry
This document provides basic instructions for use of the nucypher-ops utility for setting up PRE nodes.
Nucypher-ops is an ansible script that will setup and configure a PRE node for you. Currently, the script supports AWS and Digital Ocean. This document will guide you through the setup process using visuals from DigitalOcean.
Install Ubuntu 20.04.4 LTS through the Windows Store:
To begin, update your local machine and install dependencies
sudo apt update
sudo apt
Read prompts and respond appropriately. This will take a few minutes.
Install Python and pip on your local machine, if you don't have it already:
Python Website
Visit the
PyPA Website
Visit the and follow the steps provided to make sure that you have a working Python with pip installed.
To begin, update your local machine and install dependencies
Read prompts and respond appropriately. This will take a few minutes.
Generate an SSH key pair. We will need the public key.
Visit the website to learn about OpenSSH.
Copy the highlighted part
In your Digital Ocean dashboard:
Go to Settings > Security and click the Add SSH Key button.
Paste the key into the box, give your key a name, and click the Add SSH Key button.
Open a Text Document to make notes. Copy the SSH Fingerprint into this text file.
While we're here, let's create an API key as well. Go to API > Tokens/Keys and click the Generate New Token button.
Name your token and click the Generate New Token button.
Copy the API Key into your Text file or password manager.
The PRE application requires access to an Ethereum endpoint, as well as a Polygon endpoint. One solution is to use a provider such as , , or . Each has their own pros and cons. Review them carefully.
Once you have made your decision(s) and signed up for an account, login to your account and setup an endpoint for Ethereum. The setup steps are very straightforward for each provider.
Make sure you select Mainnet for each endpoint. You will receive what looks like a https web address, Infura calls it an Endpoint, Quicknode refers to it as a Web3 endpoint. Make sure that the endpoint you copy starts with https.
Copy each of the endpoints to your text document or into your password manager. We will use them shortly.
Let's review and make sure you have everything needed to be successful:
SSH key pair fingerprint
API Access token
Endpoint URL for Ethereum
Endpoint URL for Polygon
These items should be kept readily available.
This will download the utility, and install dependencies. This process will take several minutes.
Execute the following and be ready to answer questions from the utility:
This will connect to your Digital Ocean account, spin up a VPS, configure and secure it, and install all of the necessary software for you.
The utility will ask which provider you are using. Answer accordingly and press ENTER.
Provide your API Key and press ENTER.
Provide your SSH Fingerprint and press ENTER.
Then be patient.
In a few minutes, you'll be ready to bond your stake.
Provide your ETH endpoint when requested and press ENTER.
Provide your Polygon endpoint when requested and press ENTER.
Wait for it...
The items at the bottom are your node's IP address and Operator address, to which you will need to bond your stake.
To bond your stake to your new PRE node, click below:
Nucypher-ops is a convenient tool for deploying a PRE node on the Threshold network. In case you need to make changes to the configuration of the utility on your local machine, these are the default directories where config files are stored locally:
To find out about other features try
if you need to update your node to a new version of NuCypher just execute
sudo apt update
sudo apt upgrade
sudo apt-get install libffi-dev python3-dev python3-pip python3-virtualenv build-essential libssl-devssh-keygen -t rsa
cat .ssh/id_rsa.pubpip install nucypher-opsnucypher-ops nodes createnucypher-ops ursula deploy~/.local/share/nucypher-ops~/Library/Application Support/nucypher-opsnucypher-ops --helpnucypher-ops ursula update

















This page will show you how to launch a tBTC v2 node on the testnet.
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
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 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.
To create a new Ethereum account, (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.
Once the process completes, your public key will be displayed. Take note of your Operator Account public key.
Your Operator Account will need to be funded with goerli 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.
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.
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 .
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.
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.
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.
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.
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.
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 for the root user with the command provided in the 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 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:
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.
c5.large
Azure
F2s v2
Google Cloud
n2-highcpu-2
Self-hosted
2 vCPU / 2 GB RAM / 1 GiB Persistent Storage
geth account new --keystore ./operator-keyNetwork
network.port
TCP
3919
cd /home
mkdir keep
cd keep
mkdir storage configcd ~/operator-keyls -la
cp name_of_account_key_file /home/keep/config/name_of_account_key_filedocker --versionnano keep.sh# Keep Testnet tBTC v2 Client
#
# Ethereum endpoint WebSocket URL
# This can be a provider such as Infura, Alchemy, Ankr, etc or your own Geth Nodeq
# ETHEREUM_WS_URL="wss://goerli.infura.io/ws/v3/redacted_credentials"
# note: only replace characters inside the " ". The Quotation marks must be retained
ETHEREUM_WS_URL="<Ethereum API WS URL>"
# copied to home/keep/config earlier
OPERATOR_KEY_FILE_NAME="<Operator Account keyfile name>"
# password set during Operator Account Address creation
OPERATOR_KEY_FILE_PASSWORD="<Operator Account keyfile password>"
# To configure your node with a Public IP, enter it below.
PUBLIC_IP="<PUBLIC_IP_OF_MACHINE>"
# Alternatively, you can use DNS.
# To configure DNS, modify the last line of the script
# and add your DNS in the following format:
# /dns4/bootstrap-1.test.keep.network/tcp/3919
# Setup configuration and storage directories
# THESE MUST BE PERSISTENT STORAGE
CONFIG_DIR="/home/keep/config"
STORAGE_DIR="/home/keep/storage"
docker run \
--detach \
--restart on-failure \
--volume $CONFIG_DIR:/mnt/keep/config \
--volume $STORAGE_DIR:/mnt/keep/storage \
--env KEEP_ETHEREUM_PASSWORD=$OPERATOR_KEY_FILE_PASSWORD \
--env LOG_LEVEL=info \
--log-opt max-size=100m \
--log-opt max-file=3 \
-p 3919:3919 \
-p 9601:9601 \
us-docker.pkg.dev/keep-test-f3e0/public/keep-client \
start \
--goerli \
--ethereum.url $ETHEREUM_WS_URL \
--ethereum.keyFile /mnt/keep/config/$OPERATOR_KEY_FILE_NAME \
--storage.dir /mnt/keep/storage \
--network.announcedAddresses /ip4/$PUBLIC_IP/tcp/3919
sudo chmod +x keep.shsudo bash keep.shsudo docker pssudo docker logs stinky_brownie >& /path/to/output/file
▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀
▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌
▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓
Trust math, not hardware.
-----------------------------------------------------------------------------------
| Keep Client Node |
| |
| Version: Version: v2.0.0-m1 (4d745f6d0) |
| |
| Operator: 0x_your_operator_address |
| |
| Port: 3919 |
| IPs : /ip4/111.222.333.444/tcp/3919/ipfs/redacted |
| |
| Contracts: |
| RandomBeacon : 0x2bA82903B635a96154A515488d2952E86D6adc3A |
| WalletRegistry : 0x2363cc10b7680000C02E4a7067A68d1788ffc86F |
| TokenStaking : 0x69f962a0fbA5635e84eC94131f9072108E2E4F24 |
-----------------------------------------------------------------------------------Status
clientInfo.port
TCP
9601





Threshold Website
Staking Dashboard
PRE Application Dashboard
Github(s)
Discord
Governance Forum
Blog