Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d584750
Removes up.py command, adds up.ts. Defaults to .env, if no present or…
ltardivo Sep 12, 2024
1e4b985
Simplifies setup. Adds bitcoin.conf file. The docker-compose file pic…
ltardivo Sep 18, 2024
43792c9
Adds section Getting Started to README.md
ltardivo Sep 18, 2024
b11a726
Fixes faucet value on browser example
ltardivo Sep 18, 2024
a827dee
Adds Getting Started section to README.md
ltardivo Sep 18, 2024
3c3b815
Updates .env config
ltardivo Sep 19, 2024
1793934
Updates pepecoin.conf files
ltardivo Sep 19, 2024
94385a1
Removes BITCOIN_RPC_AUTH from env files
ltardivo Sep 19, 2024
d740cab
Uses node conf file from chain-setup folder
ltardivo Sep 19, 2024
2e62a2d
Removes unused scripts
ltardivo Sep 19, 2024
282143a
Renaming. Run mocha directly on script.
ltardivo Sep 19, 2024
0941051
Inline test-and-show scripts
ltardivo Sep 20, 2024
e6e52c2
Removes test script
ltardivo Sep 20, 2024
16e35a0
Adds fallbackfee parameter to bitcoin.conf regtest
ltardivo Sep 20, 2024
0ce7f9d
Removes test-and-show on node
ltardivo Sep 20, 2024
fbe9dd5
Deletes test.ts file
ltardivo Sep 25, 2024
e779d23
Force remove data folder on reset at root level
ltardivo Sep 25, 2024
4ed1bed
Uses packages/node environment file at nodeJs tests
ltardivo Oct 1, 2024
e748f33
Removes root level commands for running the node
ltardivo Oct 1, 2024
99b3a4c
Updates logs volume path
ltardivo Oct 1, 2024
43bd1c7
Set test environment file to node /.env
ltardivo Oct 1, 2024
01cba94
Fixes path to node .env
ltardivo Oct 2, 2024
7fe7127
Sets chain and network explicitly from Bitcoin Computer node .env
ltardivo Oct 2, 2024
1809a73
Upload bundles
ltardivo Oct 2, 2024
291e09e
Lint-fix
ltardivo Oct 2, 2024
6ee4869
Merge conflicts resolution
ltardivo Oct 2, 2024
c2ae354
Upload js files
ltardivo Oct 2, 2024
ce2df91
Fix pepecoin conf for testnet
ltardivo Oct 3, 2024
47a5d5c
Updates node README
ltardivo Oct 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
.DS_Store
retype.yml
.vscode
.github
.git
.gitignore
.husky
.huskyrc
.npmignore
imgs
README.md
packages/.DS_Store
packages/nakamotojs/test
packages/nakamotojs/ts_src
packages/node/coverage/
packages/node/logs/
packages/node/node_modules/
packages/node/chain-setup/**/blockchain-data
packages/node/chain-setup/**/db-data
packages/node/data/
packages/node/.env
packages/node/.DS_Store
packages/node/src
Expand Down
7 changes: 3 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
coverage/
logs/
node_modules/
chain-setup/**/blockchain-data
chain-setup/**/db-data
data
.env
.env.aws
.docker.config
Expand All @@ -14,8 +13,8 @@ error.log
bcn.config.json
zmqlog.log
packages/**/node_modules/
packages/**/chain-setup/**/blockchain-data/
packages/**/chain-setup/**/db-data/
packages/**/data/blockchain-data/
packages/**/data/db-data/
# Logs
logs
*.log
Expand Down
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,32 @@ This monorepo contains everything you need to build smart contract based applica
* [Docs](https://github.com/bitcoin-computer/monorepo/tree/main/packages/docs#readme) - The sources for the documentation
* [Website](https://github.com/bitcoin-computer/monorepo/tree/main/packages/website#readme) - The sources for the website

## Legal Notice
## Getting Started

See [here](https://github.com/bitcoin-computer/monorepo/tree/main/packages/lib#legal-notice).
There are three easy ways to get started with Bitcoin Computer smart contracts:

1. Online example: See how it works without any installation requirements! [This](https://docs.bitcoincomputer.io/start/) simple example defines, deploys, and executes a smart contract in your browser.

2. Online tools: Try out the Bitcoin Computer functionality directly with our online [Explorer](https://explorer.bitcoincomputer.io) and [Playgorund](https://explorer.bitcoincomputer.io/playground).

3. Local development:

* Clone this monorepo.

```bash
git clone https://github.com/bitcoin-computer/monorepo.git
cd monorepo
npm install
```

* Run the applications locally by following the instructions in each application's readme file.

Check the latest version of the Bitcoin Computer monorepo on the [releases](https://github.com/bitcoin-computer/monorepo/releases) page.

## Getting Help

Have a look at the [docs](https://docs.bitcoincomputer.io/). If you have any questions, please let us know on <a href="https://t.me/thebitcoincomputer" target="_blank">Telegram</a>, <a href="https://twitter.com/TheBitcoinToken" target="_blank">Twitter</a>, or by email clemens@bitcoincomputer.io.

## Legal Notice

See [here](https://github.com/bitcoin-computer/monorepo/tree/main/packages/lib#legal-notice).
10 changes: 1 addition & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,10 @@
"packages/*"
],
"scripts": {
"build-node": "docker build -t bitcoin-computer-node .",
"check-obfuscation": "./scripts/check-obfuscation.sh",
"down": "cd packages/node && npm run down",
"fund-ltc": "cd packages/node && npm run fund-ltc -- $@",
"fund-btc": "cd packages/node && npm run fund-btc -- $@",
"husky-checks": "./scripts/husky-checks.sh",
"prepare": "husky install",
"prepublishOnly": "./scripts/check-obfuscation.sh",
"reset": "cd packages/node && npm run reset",
"start": "cd /dist/packages/node && npm run start",
"test": "cd packages/node && npm run test; cd ../lib && npm run test",
"up": "cd packages/node && npm run up -- $@"
"prepublishOnly": "./scripts/check-obfuscation.sh"
},
"dependencies": {
"@endo/static-module-record": "^1.0.4"
Expand Down
2 changes: 1 addition & 1 deletion packages/TBC20/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"prettier": "prettier --write \"src/**/*.{js,jsx,ts,tsx,css,scss,md}\"",
"types": "tsc",
"test": "mocha --config .mocharc.json",
"test-and-show": "../../scripts/test-and-show.sh tbc20-test.log "
"test-and-show": "npm run test 2>&1 | tee tbc20-test.log && open tbc20-test.log"
},
"author": "Clemens Ley <clemens@bitcoincomputer.io>",
"license": "Apache-2.0",
Expand Down
66 changes: 66 additions & 0 deletions packages/TBC20/src/token.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* eslint-disable max-classes-per-file */
const { Contract } = await import('@bitcoin-computer/lib');
export class Token extends Contract {
constructor(to, amount, name, symbol = '') {
super({ _owners: [to], amount, name, symbol });
}
transfer(to, amount) {
// Send entire amount
if (typeof amount === 'undefined') {
this._owners = [to];
return null;
}
// Send partial amount in a new object
if (this.amount >= amount) {
this.amount -= amount;
return new Token(to, amount, this.name, this.symbol);
}
throw new Error('Insufficient funds');
}
}
export class TBC20 {
constructor(computer, mod) {
this.computer = computer;
this.mod = mod;
}
async deploy() {
this.mod = await this.computer.deploy(`export ${Token}`);
return this.mod;
}
async mint(publicKey, amount, name, symbol) {
const args = [publicKey, amount, name, symbol];
const token = await this.computer.new(Token, args, this.mod);
return token._root;
}
async totalSupply(root) {
const rootBag = await this.computer.sync(root);
return rootBag.amount;
}
async getBags(publicKey, root) {
const revs = await this.computer.query({ publicKey, mod: this.mod });
const bags = await Promise.all(revs.map(async (rev) => this.computer.sync(rev)));
return bags.flatMap((bag) => (bag._root === root ? [bag] : []));
}
async balanceOf(publicKey, root) {
if (typeof root === 'undefined')
throw new Error('Please pass a root into balanceOf.');
const bags = await this.getBags(publicKey, root);
return bags.reduce((prev, curr) => prev + curr.amount, 0);
}
async transfer(to, amount, root) {
let _amount = amount;
const owner = this.computer.getPublicKey();
const bags = await this.getBags(owner, root);
const results = [];
while (_amount > 0 && bags.length > 0) {
const [bag] = bags.splice(0, 1);
const available = Math.min(_amount, bag.amount);
// eslint-disable-next-line no-await-in-loop
results.push(await bag.transfer(to, available));
_amount -= available;
}
if (_amount > 0)
throw new Error('Could not send entire amount');
await Promise.all(results);
}
}
163 changes: 163 additions & 0 deletions packages/TBC20/test/token.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/* eslint-disable no-unused-expressions */
import { expect } from 'chai';
import { Computer } from '@bitcoin-computer/lib';
import dotenv from 'dotenv';
import { TBC20, Token } from '../src/token';
dotenv.config({ path: '../node/.env' });
const url = process.env.BCN_URL;
const chain = process.env.BCN_CHAIN;
const network = process.env.BCN_NETWORK;
function sleep(delay) {
return new Promise((resolve) => {
setTimeout(resolve, delay);
});
}
const sender = new Computer({ url, chain, network });
const receiver = new Computer({ url, chain, network });
before(async () => {
await sender.faucet(1e7);
});
describe('Token', () => {
describe('Using fungible tokens without a helper class', () => {
let token;
describe('Minting a fungible token', async () => {
it('Sender mints a token', async () => {
token = await sender.new(Token, [sender.getPublicKey(), 3, 'test']);
});
it('The meta data should be set', async () => {
expect(token.amount).to.eq(3);
expect(token._owners).deep.equal([sender.getPublicKey()]);
expect(token.name).to.eq('test');
expect(token.symbol).to.eq('');
expect(token._id).to.be.a('string');
expect(token._rev).to.be.a('string');
expect(token._root).to.be.a('string');
});
});
describe('Transferring the NFT', () => {
let newToken;
it('Sender transfers the NFT to receiver', async () => {
newToken = await token.transfer(receiver.getPublicKey(), 1);
});
it('The meta data of token should be set correctly', () => {
expect(token.amount).to.eq(2);
expect(token._owners).deep.equal([sender.getPublicKey()]);
expect(token.name).to.eq('test');
expect(token.symbol).to.eq('');
expect(token._id).to.be.a('string');
expect(token._rev).to.be.a('string');
expect(token._root).to.be.a('string');
});
it('The meta data of newToken should be set correctly', () => {
expect(newToken.amount).to.eq(1);
expect(newToken._owners).deep.equal([receiver.getPublicKey()]);
expect(newToken.name).to.eq('test');
expect(newToken.symbol).to.eq('');
expect(newToken._id).to.be.a('string');
expect(newToken._rev).to.be.a('string');
expect(newToken._root).to.be.a('string');
});
});
});
describe('Using fungible tokens with a helper class', () => {
describe('mint', () => {
const tbc20 = new TBC20(sender);
let root;
it('Should create the tbc20 object', async () => {
const publicKey = tbc20.computer.getPublicKey();
root = await tbc20.mint(publicKey, 200, 'test', 'TST');
expect(root).not.to.be.undefined;
expect(typeof root).to.eq('string');
expect(root.length).to.be.greaterThan(64);
});
it('Should mint a root token', async () => {
const rootToken = await sender.sync(root);
expect(rootToken).not.to.be.undefined;
expect(rootToken._id).to.eq(root);
expect(rootToken._rev).to.eq(root);
expect(rootToken._root).to.eq(root);
expect(rootToken.amount).to.eq(200);
expect(rootToken.name).to.eq('test');
expect(rootToken.symbol).to.eq('TST');
});
});
describe('totalSupply', () => {
it('Should return the supply of tokens', async () => {
const tbc20 = new TBC20(sender);
const publicKey = tbc20.computer.getPublicKey();
const root = await tbc20.mint(publicKey, 200, 'test', 'TST');
const supply = await tbc20.totalSupply(root);
expect(supply).to.eq(200);
});
});
describe('balanceOf', () => {
it('Should throw an error if the root is not set', async () => {
const publicKeyString = sender.getPublicKey();
const tbc20 = new TBC20(sender);
expect(tbc20).not.to.be.undefined;
try {
await tbc20.balanceOf(publicKeyString, undefined);
expect(true).to.eq(false);
}
catch (err) {
expect(err.message).to.eq('Please pass a root into balanceOf.');
}
});
it('Should compute the balance', async () => {
const tbc20 = new TBC20(sender);
const publicKey = tbc20.computer.getPublicKey();
const root = await tbc20.mint(publicKey, 200, 'test', 'TST');
await sleep(200);
const res = await tbc20.balanceOf(publicKey, root);
expect(res).to.eq(200);
});
});
describe('transfer', () => {
it('Should transfer a token', async () => {
const computer2 = new Computer({ url, chain, network });
const tbc20 = new TBC20(sender);
const publicKey = tbc20.computer.getPublicKey();
const root = await tbc20.mint(publicKey, 200, 'test', 'TST');
await sleep(200);
await tbc20.transfer(computer2.getPublicKey(), 20, root);
await sleep(200);
const res = await tbc20.balanceOf(publicKey, root);
expect(res).to.eq(180);
});
it('Should transfer random amounts to different people', async () => {
const computer2 = new Computer({ url, chain, network });
const computer3 = new Computer({ url, chain, network });
const tbc20 = new TBC20(sender);
const publicKey = tbc20.computer.getPublicKey();
const root = await tbc20.mint(publicKey, 200, 'multiple', 'MULT');
const amount2 = Math.floor(Math.random() * 100);
const amount3 = Math.floor(Math.random() * 100);
await sleep(200);
await tbc20.transfer(computer2.getPublicKey(), amount2, root);
await sleep(200);
await tbc20.transfer(computer3.getPublicKey(), amount3, root);
await sleep(200);
const res = await tbc20.balanceOf(publicKey, root);
expect(res).to.eq(200 - amount2 - amount3);
const res2 = await tbc20.balanceOf(computer2.getPublicKey(), root);
expect(res2).to.eq(amount2);
const res3 = await tbc20.balanceOf(computer3.getPublicKey(), root);
expect(res3).to.eq(amount3);
});
it('Should fail if the amount is greater than the balance', async () => {
const computer2 = new Computer({ url, chain, network });
const tbc20 = new TBC20(sender);
const publicKey = tbc20.computer.getPublicKey();
const root = await tbc20.mint(publicKey, 200, 'test', 'TST');
await sleep(200);
try {
await tbc20.transfer(computer2.getPublicKey(), 201, root);
expect(true).to.eq('false');
}
catch (err) {
expect(err.message).to.eq('Could not send entire amount');
}
});
});
});
});
16 changes: 9 additions & 7 deletions packages/TBC20/test/token.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@ import { Computer } from '@bitcoin-computer/lib'
import dotenv from 'dotenv'
import { TBC20, Token } from '../src/token'

dotenv.config({ path: '../../.env' })
dotenv.config({ path: '../node/.env' })

const url = process.env.BCN_URL
const chain = process.env.BCN_CHAIN
const network = process.env.BCN_NETWORK

function sleep(delay: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, delay)
})
}

const sender = new Computer({ url })
const receiver = new Computer({ url })
const sender = new Computer({ url, chain, network })
const receiver = new Computer({ url, chain, network })

before(async () => {
await sender.faucet(1e7)
Expand Down Expand Up @@ -130,7 +132,7 @@ describe('Token', () => {

describe('transfer', () => {
it('Should transfer a token', async () => {
const computer2 = new Computer()
const computer2 = new Computer({ url, chain, network })
const tbc20 = new TBC20(sender)
const publicKey = tbc20.computer.getPublicKey()
const root = await tbc20.mint(publicKey, 200, 'test', 'TST')
Expand All @@ -142,8 +144,8 @@ describe('Token', () => {
})

it('Should transfer random amounts to different people', async () => {
const computer2 = new Computer()
const computer3 = new Computer()
const computer2 = new Computer({ url, chain, network })
const computer3 = new Computer({ url, chain, network })
const tbc20 = new TBC20(sender)
const publicKey = tbc20.computer.getPublicKey()
const root = await tbc20.mint(publicKey, 200, 'multiple', 'MULT')
Expand All @@ -165,7 +167,7 @@ describe('Token', () => {
})

it('Should fail if the amount is greater than the balance', async () => {
const computer2 = new Computer()
const computer2 = new Computer({ url, chain, network })
const tbc20 = new TBC20(sender)
const publicKey = tbc20.computer.getPublicKey()
const root = await tbc20.mint(publicKey, 200, 'test', 'TST')
Expand Down
Loading