Simple Crowdfunding

I’ve played a little bit with a crowdfunding campaign corresponding to the example provided in the
ErgoScript White Paper (page 6) and found that it could be
done even with current wallet API. This post is about how to do crowdfunding on top of Ergo. The post is also proposing a concrete campaign to fund post-EIP1 crowdfunding script development.

If you want to get into details, please read next section, “The Script”. Otherwise, just read “How To Donate” and “Crowdfunding Project Proposal” sections below.

The Script

The simplest crowdfunding script, according to the
ErgoScript White Paper (page 6), is “a script for the following crowdfunding situation: a project backer (with key backerPubKey) wishes to give money to a project (with key projectPubKey), but only if the project raises enough money (at least minToRaise) from other sources by a deadline (expressed in terms of HEIGHT). To give money to the project, the backer will create an output box protected by the following script. The script contains two conditions: one for the case the deadline has passed (enabling the backer to get the money back) and one for the case it succeeded (enabling the project to spend the money if the amount is at least minToRaise before the deadline). In order to ensure enough money has been raised,
the script will search the output collection for a box with a sufficient value going to the projectPubKey. To check where the value of the output box is going, the script will read the script protecting the output box and compare it to the script corresponding to proveDlog(projectPubKey) ; this script can be obtained byprojectPubKey.propBytes.”

As currently API does not support embedding of custom environment variables (only predefined like HEIGHT), the only way to compile the script is to replace such variables in the script from the white-paper with concrete values. For example, consider that a crowdfunding campaign is successful if it is raising 500 Ergs before block number 50,000. For backerPubKey and projectPubKey we can use PK() function which accepts only P2PK serialized keys at the moment. Then the modified script from the WhitePaper becomes the following:

   val backerPubKey = PK("9h7DHKSDgE4uvP8313GVGdsEg3AvdAWSSTG7XZsLwBfeth4aePG")
   val projectPubKey = PK("9gBSqNT9LH9WjvWbyqEvFirMbYp4nfGHnoWdceKGu45AKiya3Fq") 
   val deadline = 50000
   val minToRaise = 500L * 1000000000 
   val fundraisingFailure = HEIGHT >= deadline && backerPubKey
   val enoughRaised = {(outBox: Box) =>outBox.value >= minToRaise 
                              && outBox.propositionBytes == projectPubKey.propBytes
   val fundraisingSuccess = HEIGHT < deadline && projectPubKey && OUTPUTS.exists(enoughRaised)
   fundraisingFailure || fundraisingSuccess                     

How To Donate

First of all, JSON is not supporting multi-line strings, so you need to replace line breaks with \n.
Also, quotes are to be escaped, so use " instead of ". The resulting JSON will be sent to /script/p2sAddress.
To donate to a project, first get your address from /wallet/addresses, take e.g. first of them. Put the address
into the backerPubKey, so a request to /script/p2sAddress will be like following after this step:

 {"source": "{ val backerPubKey = PK(\"9...\") \n val projectPubKey = PK(\"9gBSqNT9LH9WjvWbyqEvFirMbYp4nfGHnoWdceKGu45AKiya3Fq\") \n val deadline = 50000 \n val minToRaise = 500L * 1000000000 \n val fundraisingFailure = HEIGHT >= deadline && backerPubKey \n val enoughRaised = {(outBox: Box) => outBox.value >= minToRaise && outBox.propositionBytes == projectPubKey.propBytes} \n val fundraisingSuccess = HEIGHT < deadline && projectPubKey && OUTPUTS.exists(enoughRaised) \n fundraisingFailure || fundraisingSuccess }"}                              

with your address instead of “9…”.

Send the string to /script/p2sAddress to get some a response like:

  "address": "GB3kh2izpWKvyZfMboQwsEscjPaZcz9WrzGqZB4ZrkzRreiFMV6HZYWXGMK3rqCjDCoPgWGNzfnYSUhivW4a1VRYPE7uZXwKnBcqWcRkiuTx6QW55EcPcWeELUsumwdtKoFtWY583nWnKZff"

Copy address string (GB3… in our example) and send money to it via /wallet/payment/send , a request to the API method to send 10 Ergs (10 Billion nanoErgs) will be like following:

   "address": "GB3kh2izpWKvyZfMboQwsEscjPaZcz9WrzGqZB4ZrkzRreiFMV6HZYWXGMK3rqCjDCoPgWGNzfnYSUhivW4a1VRYPE7uZXwKnBcqWcRkiuTx6QW55EcPcWeELUsumwdtKoFtWY583nWnKZff",
   "value": 10000000000

That’s all!

Now wallet will automatically find the box on the blockchain, as it contains public key which belongs to the wallet in the refund condition. The wallet then periodically checks whether the box is spendable by constructing a simplest transaction with the box as an input and just one output (to the same address). After refund height (50,000 in our example) the wallet will be able to spend the box and so box value will be added to /wallet/balances.

Please note that this will be not the case after EIP-1 implementation as wallet will use narrow recognition patterns by then.

How To Collect Donations

Wallet which is associated with the project public key will find incoming boxes on the blockchain. However, it will failto make sure that boxes are spendable, as wallet currently is using a simplest transaction for that, and script is failing for such spending transaction.

Before /wallet/boxes/uncertain method being implemented, the only way for project to find incoming boxes. Then /wallet/transaction/send with manually provided (in “inputsRaw”) serialized boxes (use /utxo/byIdBinary to get serialized box by its identifier).

I did it by myself and got this transaction

Please note that EIP-1 will break this workflow as well.

Crowdfunding Project Proposal

So I propose to raise 500 Ergs before block 50,000 for developing command-line scripts (in Python) for organizing and participating in crowdfunding campaigns after EIP-1 implementation. Command-line scripts are more suitable than doing requests manually, and also could be used for building graphic interfaces on top of them.

The treasury provides half of the funds, so others need to give other 250 collectively. In case of campaign failure refunds will be got automatically. As collecting pledges is not trivial at the moment, I will lead the project role, so please use the key 9gBSqNT9LH9WjvWbyqEvFirMbYp4nfGHnoWdceKGu45AKiya3Fq (controlled by me).

To give money, please follow “How To Donate” section above with replacing backerPubKey with your public key, and pledge amount with a proper value (please note that it is in nanoErgs, 1 Erg = 1000000000 nanoErgs).


This seems like a great first focus for getting people to use smart contracts on the network.

I’d be interested in taking this project up and writing this crowdfunding CLI app, though doing so in Rust. Given that it’ll be compiled/cross-platform/able to be converted to WASM and thus used easily in JS and overall improve interoperability, I think it’s a good choice and will make it easier down-the-line to put a GUI on top if it ends up finding a good amount of usage.

I should be able to spare some time on the weekends, and given this isn’t too large of a project, I believe it shouldn’t take too long to get a functioning version once EIP-1 is implemented.


A pledge of 250 Ergs by Foundation has been done

The crowdfunding is already successful!

Successfully gathers two boxes, one of 250 Ergs (from foundation), another of ~357 Ergs, thus ~607 Ergs in total.

There’s also unspent pledge box of 10 Ergs created by the following transaction : . It requires for 1000 Ergs to be collected by spending transaction, thus could not be spent at the moment.


This is great to hear. I would like to say thanks to the community and if anyone wishes to keep up with progress on the development of the crowdfunding CLI feel free to check out the github repo:


Just a note to say that this could be simplified by removing the constraint that the output must go to the project owner, since there is already a constraint further down that requires the transaction is signed by the project owner:

projectPubKey && OUTPUTS.exists(enoughRaised)

In other words, the project owner can already send the funds anywhere they want in the next transaction, so the script could be simplified by letting them send the funds wherever they want as soon as the threshold is met prior to the deadline.

The simplified condition looks like this:

val enoughRaised = { (outBox: Box) => outBox.value >= minToRaise }

1 Like

I’ve created a P2S web tool to help bookmark and share these types of contracts; if you click on this link you should get the above ErgoScript contract for which you will need to modify to include your backerPubKey refund address.

[Note: as I noted in my previous comment, I’ve removed the constraint that the project owner must send the funds to their own address, which simplifies the contract slightly.]

Click on “Get P2S Address” to generate the P2S address for a valid contract, otherwise it will show the error information.

As you edit the contact, it should automatically update the URL, so you can bookmark it and/or share (note that the URL can get quite long for longer contracts).

Obviously, use at your own risk etc. since you are trusting my node and trusting that my server hasn’t been hacked.

1 Like

That’s a good point on the redundant check. Currently I am using the original script for the CLI app, but I’ll look into making the edit tomorrow.

Edit: Just thinking about it, having to withdraw all funds to the project/campaign address could be a good way to really make it easy later on to see whether or not a campaign was successful and easier to track how the funds are spent later on since it all gets moved into a new box at the campaign address. I’ll keep it as is for now, but if people overwhelmingly prefer without this restriction then it can be changed.


After getting a bit excited to see this proceed forward I’ve pulled a couple late nights and pushed aside a few more responsibilities than maybe I should have, but nonetheless I bring you the Ergo Crowdfund CLI App in an early alpha yet functional form. (As such please take some time to test it first before trusting it with serious funds. It should all be relatively safe, but this is bleeding edge software after all.)

What currently works:

  1. Creating a local campaign/saving the data related to it
  2. Exporting said created campaign and sharing it with others via file
  3. Importing/tracking campaigns created by others and saving those campaigns locally.
  4. Backing/sending funds to tracked (locally stored) campaigns. (The app automatically fills out the crowdfund script, generates the P2S address, and then sends the specified number of Ergs to the P2S address via node wallet api)
  5. Saves data about backed campaigns (how many Erg you previously sent, and the tx id of said spend)

In the future, especially after EIP-1, tracking campaigns on-chain and seeing how they are progressing/the result will be implemented, and also the ability for a campaign creator (or technically the owner of the address a campaign is set up for) to be able to withdraw funds if the campaign was successful.

There’s an extensive readme/instructions, and for now you have to compile it yourself, but if you have any questions feel free to ask.


There’s another box of 42 Ergs boxId: 1dc4f025cbf3331849bcb06e16fc46d7ce53938eef2d54299d915695f0a1c9a4 , transaction Id: 6e9a5544fae833dd2deb52b4a2203b3f50c322967d7542acb7bbc690b26dc59a . Unfortunately, I spent time around block #50,000 on the road mostly, not without some problems, thus was not able to collect the box :frowning: Will compensate 42 Ergs from my ergs then.

Respective owners of the two boxes above, please, withdraw them.

@robert will contact you directly to send the funds.

Now as we have a tool for the crowdfunding, what else can we crowdfund?

1 Like

Don’t worry, that was me! I’ve forwarded the 42 ERG to your projectPubKey: fc30c618c5f6bce72bc8e7806d0d526ca553b7d945d72e323a2853beb16224c4

1 Like

I’ve been looking into implementing the necessary primitives to support signing transactions and messages on Ledger (the hardware wallet). Still not quite sure how much work it will be, but I think this would be a good candidate.

1 Like

I think you forgot to link to the second donation that you weren’t able to claim:

  • boxid: b8a6a4b5ed10af873ce56f4e65feb99a600b82d04361291c0990545c0ae952e5
  • txid: f6725cab9e734cd03bfe6917b9b7e9562ec4b5f6bbb47236a8bab6e9451f6b5f
  • but in a strange twist, I think this donation was from your own address (9gBSqNT9LH9WjvWbyqEvFirMbYp4nfGHnoWdceKGu45AKiya3Fq) - and I’ve just realised you mentioned it earlier in the thread; it is only spendable if the crowdfund total ≥ 1000 ERG.

Thanks to you both.

I think that’s a great idea for crowdfunding. I’m sure a number of people would be interested in supporting that.

I would recommend that we have somewhat of a standard for crowdfunding campaigns to make it easy for people to find them, read about them, and back them. A separate category (or sub-category) on the forum which is specifically for crowdfunding campaigns would allow for easy cataloguing, and in the title having tags such as [Ongoing] or [Complete] or [Ended] would be a plus.

On top of that I think providing users with both the exported campaign file which they can download + import as well as a 1 liner for tracking the campaign which people can copy + paste to track the campaign locally would be ideal.
(ie. ./ergo_cf track "First Ergo Crowdfund" 9gBSqNT9LH9WjvWbyqEvFirMbYp4nfGHnoWdceKGu45AKiya3Fq 50000 500)

1 Like

After a week of updates from my previous post and the fact that users will be wanting to use the CLI tool in the near future for new campaigns, I decided to go ahead and officially release v0.1.0 of the tool and provide precompiled binaries for Linux x86, Linux ARM, and Windows.

If there is demand I can reasonably easily cross-compile for Android or other non-mac targets reasonably easily. If anyone runs into any issues please let me know.


I’ve been looking into implementing the necessary primitives to support signing transactions and messages on Ledger (the hardware wallet). Still not quite sure how much work it will be, but I think this would be a good candidate.

I think this is a perfect candidate for next candidate, and the Foundation can secure its success.

@robert played with the tool, well done!

1 Like

650 Ergs (250 + 357 + 42 = 649, and I’ve added 1 Erg) have been sent to @robert !

1 Like

Thank you once again to everyone that supported the project. I’ll be looking forward to passing some of these Ergs I just got on to others in the community to support new interesting crowdfunding campaigns as they pop up.


Thought it was worth posting here, about a month ago there were some properties of the crowdfunding smart contract which were formally verified which you can check out on github here

This means that currently one can argue that crowdfunding campaigns on Ergo are one of the most secure crowdfunding methods currently available just 3 months after launch of main net. Quite exciting.


Sounds really nice! Could you elaborate on how the verification works and the theory behind it? What exactly does this allow us to claim? (in particular, does it test for all inputs?)