npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

bitcoin-cash-forever

v0.0.4

Published

A bitcoin perpetuity utility

Downloads

12

Readme

bitcoin-cash-forever

A simple on-chain perpetuity contract for bitcoin cash.

🐉 pre-alpha release disclaimer 🐉

This is a brand new contract, using brand new features of bitcoin cash. [2022-06]

Please DO NOT load your life savings on it.

Although the contract strives to keep it simple, there are significant risks to repeatedly using P2SH addresses, long term.

This contract has not undergone any kind of peer-review or security audit. It is just a working concept and is being presented here for a broader audience.

There is absolutely NO way to recover funds if the initial address is incorrect or compromised far into the future.

🐉 🐉 🐉 🐉 🐉 🐉 🐉 🐉 🐉 🐉 🐉 🐉 🐉 🐉 🐉

Introduction

A perpetuity is an annuity, or instrument for regular payments, that has no end. This tool uses a bitcoin script contract written with CashScript, to pay some fixed percentage of its total rolling balance, to a predetermined address, at regular intervals, in a manner that can be triggered by any executor that knows, or can infer, the parameters of the contract.

Obviously, there is no such thing as an infinite amount of a fixed-supply currency, luckily it's later than you think. Both for simplicity, and because what we consider "dust" may be spendable on the network in the future as fees are decreased, there is no cutout behavior when the funds near depletion.

This is an example of the total payout schedule for 1 BCH, paid in 1/120 at a time with a 4000 sat fee.

Example payout of 1 BCH in 120th increments, with a 4000 sat executor fee

Starting with one coin, the monthly installments would look something like this:

Monthly Installments

The ods worksheet to make these graphs is included in the source repo.

Installing

In your preferred node environment, run your version of:

npm i bitcoin-cash-forever # -g

Usage

A full list of parameters is given with the -h flag.

1. Creating the contract

To create a new perpetuity with the default parameters, simply provide a receiving address:

npx bitcoin-cash-forever --address bitcoincash:qrtyy8w9yv6ffqtny9gp56m8kztl3nwwzcqyzsv32k

Note: the provided address must be a P2PKH address. The command will fail if a P2SH (contract) address is provided.

Which will return the new address for the contract with the balance and info:

Alpha Software. DON'T PUT YOUR LIFE SAVINGS ON THIS CONTRACT!!! 
# Perpetuity to pay 1/120 total, every 4000 blocks, after a 3400 (sat) executor allowance
contract address:           bitcoincash:pz42rjlv3lyxuxz67g33cju6g7my8rm74yphkx9mws
contract principal:         0

Since the default parameters seem fine, once the contract is funded, it can be spent about once every 4000 blocks or 27.7 days.

2. Executing the Contract

If the funds are spendable, they'll be spent if all the same parameters are passed again. Remember to take a little something for your troubles with the --exAddress contract as the executor of this contract.

👇 You can support the tor project by trying the command below. Actually, this is a real contract with real money on it. 👇

👇 No wallet necessary, try to execute this contract 👇

npx bitcoin-cash-forever --address bitcoincash:qrtyy8w9yv6ffqtny9gp56m8kztl3nwwzcqyzsv32k --exAddress <YOUR CASHADDR HERE>

🤞

Alpha Software. DON'T PUT YOUR LIFE SAVINGS ON THIS CONTRACT!!! 
# Perpetuity to pay 1/120 total, every 4000 blocks, after a 3400 (sat) executor allowance
contract address:           bitcoincash:pz42rjlv3lyxuxz67g33cju6g7my8rm74yphkx9mws
contract principal:         10187408
installment:              - 84896
executor fee:             - 3245
miner fee:                - 152
=============================================
next balance:               10099114

Abusing

When attempting to call the contract before the timelock has expired, an error should be returned.

Internal Error: Transaction failed with reason: the transaction was rejected by network rules.

non-BIP68-final (code 64)

with the accompanying meep debugging code:

meep debug --tx=02000000010564285bb7058b44e7a6efe1a33731921c90f370be25ebb630809d5d2c81acdb000000004c4b017802480d14d6421dc5233494817321501a6b67b097f8cdce1602a00f0376a9147b7e0288ac7e00cd88b27551cd02a914c1a97e01877e88c0c676537a967c78947b9400cc7ba26951cca1a00f000002a04b0100000000001976a914d6421dc5233494817321501a6b67b097f8cdce1688acaa199a000000000017a914aaa1cbec8fc86e185af2231c4b9a47b6438f7ea987955b0b00 --idx=0 --amt=10187408 --pkscript=a914aaa1cbec8fc86e185af2231c4b9a47b6438f7ea987

Testing

When using the --testnet flag, the default parameters are sped up a bit, with the contract paying every block and paying 12.5% of the remaining balance each time.

# Perpetuity to pay 1/8 total, every 1 blocks, after a 3400 (sat) executor allowance

Options

bitcoin-cash-forever -h


$ bitcoin-cash-forever

--testnet         Use testnet, defaults to 12.5% payout each block
--deposit         give the deposit address for the contract and exit
--address #0      receiving cash address to send coins to, i.e. beneficiary address
--period #0       how often (in blocks) the contract pays (default: 4000, about monthly)
--allowance #0    the executor's allowance for miner fees & administration (default: 3400 sats)
--decay #0        the divisor for the fraction taking in each installment (default: 100, i.e. 1/100 or 1% each installment)
--exAddress #0    address for fee taken by executor for submitting transaction
--fee #0          transaction fee override

Cashscript Contract

pragma cashscript >= 0.7.0;

// v20220522

// This is an experimental perpetuity contract 
// Although tested, a full audit has not been done
// DO NOT PUT YOUR LIFE SAVINGS HERE!

contract Perpetuity(

    // interval for payouts, in blocks
    int period,

    // PKH of the beneficiary, the address receiving payments
    bytes20 recipientPkh,

    // extra allowance for administration of contract
    // fees are paid from executors' allowance. 
    int executorAllowance,

    // divisor for the payout, each payout must be greater than the total
    // amount held on the contract divided by this number
    int decay
) {
    function execute() {

        // Check that the first output sends to the recipient
        bytes25 recipientLockingBytecode = new LockingBytecodeP2PKH(recipientPkh);
        require(tx.outputs[0].lockingBytecode == recipientLockingBytecode);

        // Check that time has passed and that time locks are enabled
        require(tx.age >= period);
            
        // require the second output to match the active bytecode
        require(tx.outputs[1].lockingBytecode == new LockingBytecodeP2SH(hash160(this.activeBytecode)));


        // Get the total value on the contract
        int currentValue = tx.inputs[this.activeInputIndex].value;

        // The payout is the current value divided by the decay
        int installment = currentValue/decay;

        // Calculate value returned to the contract
        int returnedValue = currentValue - installment - executorAllowance;

        // Check that the outputs send the correct amounts
        require(tx.outputs[0].value >= installment);
        require(tx.outputs[1].value >= returnedValue);
            
    }

}