{"id":13414426,"url":"https://github.com/keppel/lotion","last_synced_at":"2025-03-14T21:32:34.660Z","repository":{"id":24061786,"uuid":"100509296","full_name":"keppel/lotion","owner":"keppel","description":"✨ Smooth, easy blockchain apps ✨","archived":true,"fork":false,"pushed_at":"2022-06-02T20:50:20.000Z","size":1656,"stargazers_count":971,"open_issues_count":40,"forks_count":135,"subscribers_count":52,"default_branch":"develop","last_synced_at":"2024-05-21T13:15:25.708Z","etag":null,"topics":["blockchain","cosmos","lotion","lotionjs","tendermint"],"latest_commit_sha":null,"homepage":"https://lotionjs.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/keppel.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-08-16T16:19:27.000Z","updated_at":"2024-05-20T03:57:14.000Z","dependencies_parsed_at":"2022-07-11T19:54:52.521Z","dependency_job_id":null,"html_url":"https://github.com/keppel/lotion","commit_stats":null,"previous_names":["nomic-io/lotion"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keppel%2Flotion","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keppel%2Flotion/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keppel%2Flotion/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keppel%2Flotion/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/keppel","download_url":"https://codeload.github.com/keppel/lotion/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221509012,"owners_count":16834812,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","cosmos","lotion","lotionjs","tendermint"],"created_at":"2024-07-30T21:00:21.010Z","updated_at":"2024-10-26T07:31:07.182Z","avatar_url":"https://github.com/keppel.png","language":"TypeScript","funding_links":[],"categories":["Language bundles","TypeScript"],"sub_categories":["Javascript bundle"],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003cbr\u003e\n  \u003ca href=\"https://github.com/keppel/lotion\"\u003e\u003cimg src=\"https://user-images.githubusercontent.com/1269291/36411921-a4eadaf6-15cc-11e8-9614-b316de38d534.png\" alt=\"Lotion\" width=\"200\"\u003e\u003c/a\u003e\n  \u003cbr\u003e\n      ✨ Lotion ✨\n  \u003cbr\u003e\n  \u003cbr\u003e\n\u003c/h1\u003e\n\n\u003ch4 align=\"center\"\u003eSmooth, easy blockchain apps. Powered by Tendermint consensus.\u003c/h4\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://travis-ci.org/keppel/lotion\"\u003e\n    \u003cimg src=\"https://img.shields.io/travis/nomic-io/lotion/master.svg\"\n         alt=\"Travis Build\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/lotion\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/dm/lotion.svg\"\n         alt=\"NPM Downloads\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/lotion\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/lotion.svg\"\n         alt=\"NPM Version\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://slack.lotionjs.com\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/chat-on%20slack-7A5979.svg\" alt=\"chat on slack\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/keppel/lotion\"\u003e\n    \u003cimg src=\"https://img.shields.io/codecov/c/github/keppel/lotion/develop.svg\" alt=\"test coverage\"\u003e\n  \u003c/a\u003e\n  \n\u003c/p\u003e\n\u003cbr\u003e\n\nLotion is a new way to create blockchain apps in JavaScript, which aims to make writing new blockchains fast and fun. It builds on top of [Tendermint](https://tendermint.com) using the [ABCI](https://github.com/tendermint/abci) protocol. Lotion lets you write secure, scalable applications that can easily interoperate with other blockchains on the [Cosmos Network](https://cosmos.network/) using [IBC](https://github.com/cosmos/ics).\n\nLotion itself is a tiny framework; its true power comes from the network of small, focused modules built upon it. Adding a fully-featured cryptocurrency to your blockchain, for example, takes only a [few lines of code.](https://github.com/mappum/coins)\n\nNote: the security of this code has not yet been evaluated. If you expect your app to secure real value, please use [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) instead.\n\n## Installation\n\nLotion requires **node v7.6.0** or higher, and a mac or linux machine.\n\n```\n$ npm install lotion\n```\n\n## Usage\n\n`app.js`:\n\n```js\nlet lotion = require('lotion')\n\nlet app = lotion({\n  initialState: {\n    count: 0\n  }\n})\n\napp.use(function(state, tx) {\n  if (state.count === tx.nonce) {\n    state.count++\n  }\n})\n\napp.start()\n```\n\n## Introduction\n\nLotion lets you build blockchains. At any moment in time, the whole state of your blockchain is represented by a single JavaScript object called the `state`.\n\nUsers will create `transactions`: JavaScript objects that tell the application how to mutate the blockchain's `state`.\n\nEvery user who runs your Lotion app will interact with the same blockchain. Anyone can create a `transaction`, and it will automagically find its way to everyone else running the app and mutate their `state`. Everyone's `state` objects will constantly be kept in sync with each other.\n\nA Lotion application is often a single function of signature `(state, tx)` which mutates your blockchain's `state` in response to a transaction `tx`. Both are just objects.\n\nThis cosmic wizardry is made possible by a magic piece of software named [Tendermint](https://github.com/tendermint/tendermint) which exists specifically for synchronizing state machines across networks.\n\n### Blockchains and Tendermint\n\nThe goal of a blockchain is to represent a single state being concurrently edited. In order to avoid conflicts between concurrent edits, it represents the state as a ledger: a series of transformations (transactions) applied to an initial state. The blockchain must allow all connected nodes to agree about which transformations are valid, and their ordering within the ledger.\n\nTo accomplish this, a blockchain is composed of three protocols: the **network** protocol, **consensus** protocol, and **transaction** protocol.\n\nThe **network** protocol is how nodes in the network tell each other about new transactions, blocks, and other nodes; usually a p2p gossip network.\n\nThe **consensus** protocol is the set of rules that nodes should follow to determine which particular ordered set of transformations should be in the ledger at a given moment. In Bitcoin, the chain with the highest difficulty seen by a node is treated as authoritatively correct.\n\nThe **transaction** protocol describes what makes transactions valid, and how they should mutate the blockchain's state.\n\n**_When you're writing a Lotion app, you're only responsible for writing the transaction protocol._** Under the hood, Tendermint is handling the consensus and network protocols. When you start your lotion app, a Tendermint node is also started which will handle all of the communication with other nodes running your lotion app.\n\n## Modules\n\n| name                                                 | description                              |\n| ---------------------------------------------------- | ---------------------------------------- |\n| [coins](https://github.com/mappum/coins)             | fully-featured cryptocurrency middleware |\n| [htlc](https://github.com/mappum/htlc)               | hashed timelock contracts on coins       |\n| [shea](https://github.com/keppel/shea)               | on-chain client code management          |\n| [merk](https://github.com/mappum/merk)               | merkle AVL trees in javascript           |\n\n## Contributors\n\nLotion is a cosmic journey for the mind brought to you by:\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore --\u003e\n| [\u003cimg src=\"https://avatars2.githubusercontent.com/u/1269291?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJudd\u003c/b\u003e\u003c/sub\u003e](https://twitter.com/juddkeppel)\u003cbr /\u003e[💻](https://github.com/keppel/lotion/commits?author=keppel \"Code\") [📖](https://github.com/keppel/lotion/commits?author=keppel \"Documentation\") [🤔](#ideas-keppel \"Ideas, Planning, \u0026 Feedback\") [⚠️](https://github.com/keppel/lotion/commits?author=keppel \"Tests\") | [\u003cimg src=\"https://avatars2.githubusercontent.com/u/398285?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eMatt Bell\u003c/b\u003e\u003c/sub\u003e](https://github.com/mappum)\u003cbr /\u003e[💻](https://github.com/keppel/lotion/commits?author=mappum \"Code\") [🤔](#ideas-mappum \"Ideas, Planning, \u0026 Feedback\") [⚠️](https://github.com/keppel/lotion/commits?author=mappum \"Tests\") [🔌](#plugin-mappum \"Plugin/utility libraries\") | [\u003cimg src=\"https://avatars1.githubusercontent.com/u/6021933?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJordan Bibla\u003c/b\u003e\u003c/sub\u003e](http://www.jordanbibla.com)\u003cbr /\u003e[🎨](#design-jolesbi \"Design\") | [\u003cimg src=\"https://avatars0.githubusercontent.com/u/18440102?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eGautier Marin\u003c/b\u003e\u003c/sub\u003e](https://github.com/gamarin2)\u003cbr /\u003e[📝](#blog-gamarin2 \"Blogposts\") | [\u003cimg src=\"https://avatars3.githubusercontent.com/u/1147244?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJackson Roberts\u003c/b\u003e\u003c/sub\u003e](https://github.com/Jaxkr)\u003cbr /\u003e[💻](https://github.com/keppel/lotion/commits?author=Jaxkr \"Code\") | [\u003cimg src=\"https://avatars3.githubusercontent.com/u/758121?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eMark Price\u003c/b\u003e\u003c/sub\u003e](http://spentak.com)\u003cbr /\u003e[📖](https://github.com/keppel/lotion/commits?author=spentak \"Documentation\") [✅](#tutorial-spentak \"Tutorials\") [💡](#example-spentak \"Examples\") [📹](#video-spentak \"Videos\") | [\u003cimg src=\"https://avatars2.githubusercontent.com/u/14792822?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eEvan Leong\u003c/b\u003e\u003c/sub\u003e](http://www.fountapp.com)\u003cbr /\u003e[🎨](#design-evanmayo \"Design\") |\n| :---: | :---: | :---: | :---: | :---: | :---: | :---: |\n| [\u003cimg src=\"https://avatars0.githubusercontent.com/u/8525850?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eChjango Unchained\u003c/b\u003e\u003c/sub\u003e](https://cosmos.network)\u003cbr /\u003e[📝](#blog-Chjango \"Blogposts\") [📋](#eventOrganizing-Chjango \"Event Organizing\") | [\u003cimg src=\"https://avatars3.githubusercontent.com/u/18755233?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eSaifRehman\u003c/b\u003e\u003c/sub\u003e](https://github.com/SaifRehman)\u003cbr /\u003e[💡](#example-SaifRehman \"Examples\") | [\u003cimg src=\"https://avatars3.githubusercontent.com/u/1772945?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eLola Dam\u003c/b\u003e\u003c/sub\u003e](https://github.com/rllola)\u003cbr /\u003e[🐛](https://github.com/keppel/lotion/issues?q=author%3Arllola \"Bug reports\") [💻](https://github.com/keppel/lotion/commits?author=rllola \"Code\") | [\u003cimg src=\"https://avatars1.githubusercontent.com/u/2449579?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eDjenad Razic\u003c/b\u003e\u003c/sub\u003e](http://www.machinezdesign.com)\u003cbr /\u003e[💻](https://github.com/keppel/lotion/commits?author=MisterDr \"Code\") | [\u003cimg src=\"https://avatars3.githubusercontent.com/u/5900925?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAdmir Sabanovic\u003c/b\u003e\u003c/sub\u003e](http://dev.ba)\u003cbr /\u003e[💻](https://github.com/keppel/lotion/commits?author=criticalbh \"Code\") | [\u003cimg src=\"https://avatars1.githubusercontent.com/u/5405348?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eArne Meeuw\u003c/b\u003e\u003c/sub\u003e](http://meeuw.me)\u003cbr /\u003e[💬](#question-ameeuw \"Answering Questions\") [🤔](#ideas-ameeuw \"Ideas, Planning, \u0026 Feedback\") | [\u003cimg src=\"https://avatars1.githubusercontent.com/u/36277340?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eProps.love\u003c/b\u003e\u003c/sub\u003e](https://www.props.love)\u003cbr /\u003e[💻](https://github.com/keppel/lotion/commits?author=propslove \"Code\") |\n| [\u003cimg src=\"https://avatars0.githubusercontent.com/u/172531?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ePeng Zhong\u003c/b\u003e\u003c/sub\u003e](http://cosmos.network)\u003cbr /\u003e[🎨](#design-nylira \"Design\") [💡](#example-nylira \"Examples\") [🤔](#ideas-nylira \"Ideas, Planning, \u0026 Feedback\") |\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nContributions of any kind welcome!\n\n## API\n\n### `let app = require('lotion')(opts)`\n\nCreate a new Lotion app.\n\nHere are the available options for `opts` which you can override:\n\n```js\n{\n  initialState: {},            // initial blockchain state\n  keyPath: 'keys.json',        // path to keys.json. generates own keys if not specified.\n  genesisPath: 'genesis.json', // path to genesis.json. generates new one if not specified.\n  peers: [],                   // array of '\u003chost\u003e:\u003cp2pport\u003e' of initial tendermint nodes to connect to. does automatic peer discovery if not specified.\n  logTendermint: false,        // if true, shows all output from the underlying tendermint process\n  p2pPort: 26658,              // port to use for tendermint peer connections\n  rpcPort: 26657               // port to use for tendermint rpc\n}\n```\n\n### `app.use(function(state, tx, chainInfo) { ... })`\n\nRegister a transaction handler. Given a `state` and `tx` object, mutate `state` accordingly.\n\nTransaction handlers will be called for every transaction, in the same order you passed them to `app.use()`.\n\nTransaction handlers must be deterministic: for a given set of `state`/`tx`/`chainInfo` inputs, you **must** mutate `state` in the same way.\n\n`chainInfo` is an object like:\n\n```js\n{\n  time: 1541415248, // timestamp of the latest block. (unix seconds)\n  validators: {\n    '\u003cbase64-encoded pubkey\u003e' : 20, // voting power distribution for validators. requires understanding tendermint.\n    '\u003cother pubkey\u003e': 147 // it's ok if you're not sure what this means, this is usually hidden from you.\n  }\n}\n```\n\nIf you'd like to change how much voting power a validator should have, simply mutate chainInfo.validators[pubKey] at any point!\n\n### `app.useBlock(function(state, chainInfo) { ... })`\n\nAdd middleware to be called once per block, even if there haven't been any transactions. Should mutate `state`, see above to read more about `chainInfo`.\n\nMost things that you'd use a block handler for can and should be done as `transactions`.\n\n### `app.start()`\n\nStarts your app.\n\n## Global Chain Identifiers and Light Clients\n\nLotion apps each have a unique global chain identifier (GCI). You can light client verify any running Lotion app from any computer in the world as long as you know its GCI.\n\n```js\nlet { connect } = require('lotion')\nlet GCI = '6c94c1f9d653cf7e124b3ec57ded2589223a96416921199bbf3ef3ca610ffceb'\n\nlet { state, send } = await connect(GCI)\n\nlet count = await state.count\nconsole.log(count) // 0\n\nlet result = await send({ nonce: 0 })\nconsole.log(result) // { height: 42, ok: true }\n\ncount = await state.count\nconsole.log(count) // 1\n```\n\nUnder the hood, the GCI is used to discover and torrent the app's genesis.json.\n\nIt's also used as the rendezvous point with peers on the bittorrent dht and through multicast DNS to find a full node light client verify.\n\nYou can get the GCI of an app being run by a full node like this:\n\n```js\nlet app = require('lotion')({ initialState: { count: 0 } })\n\nlet { GCI } = await app.start()\nconsole.log(GCI) // '6c94c1f9d653cf7e124b3ec57ded2589223a96416921199bbf3ef3ca610ffceb'\n```\n\n## Links\n\n- go read more at [https://lotionjs.com](https://lotionjs.com)!\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkeppel%2Flotion","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkeppel%2Flotion","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkeppel%2Flotion/lists"}