├── .babelrc ├── .editorconfig ├── .eslintrc.json ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .prettierignore ├── .prettierrc.yml ├── .travis.yml ├── LICENSE ├── README.md ├── client ├── app.js ├── components │ ├── AboutUs.js │ ├── AllTransactions.js │ ├── BitcoinsInfo.js │ ├── Chart.js │ ├── ChartTwo.js │ ├── FAQs.js │ ├── Footer.js │ ├── HomePage.js │ ├── MessageForm.js │ ├── UserInfo.js │ ├── auth-form.js │ ├── index.js │ ├── navbar.js │ ├── searchBar.js │ ├── signUp.js │ ├── signup.js │ ├── user-home.spec.js │ └── userHome.js ├── history.js ├── index.js ├── routes.js ├── socket.js └── store │ ├── allUsers.js │ ├── index.js │ ├── transactions.js │ ├── user.js │ └── user.spec.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── images │ ├── LightText.htm │ ├── LightText_files │ │ ├── bundle.js │ │ ├── css │ │ ├── css(1) │ │ ├── lightbulb.png │ │ ├── lightbulbblack.png │ │ ├── semantic.min.css │ │ └── style.css │ ├── Sihem_1.jpg │ ├── download-1.png │ ├── download.png │ ├── iphone.png │ ├── lightText.gif │ ├── lightbulb.png │ ├── lightbulbblack.png │ ├── maurice.jpeg │ ├── milan.jpeg │ ├── screen.png │ ├── screen2.png │ ├── screen3.png │ ├── screen4.png │ └── tali.jpeg ├── index.html └── style.css ├── script ├── deploy ├── encrypt-heroku-auth-token ├── seed.js └── seed.spec.js ├── server ├── Util │ └── chart.js ├── api │ ├── admin.macaroon │ ├── crypto.js │ ├── index.js │ ├── lightning.js │ ├── promise.js │ ├── receive_sms.js │ ├── rpc.proto │ ├── send_sms.js │ ├── testnet │ │ ├── admin.macaroon │ │ ├── base64Admin.macaroon │ │ ├── base64tls.cert │ │ ├── tls (1).cert │ │ ├── tls (1).key │ │ ├── tls (2).cert │ │ ├── tls (2).key │ │ ├── tls (3).cert │ │ ├── tls (4).cert │ │ ├── tls (5).cert │ │ ├── tls (6).cert │ │ ├── tls.cert │ │ └── tls.key │ ├── transactions.js │ ├── users.js │ └── users.spec.js ├── auth │ ├── google.js │ └── index.js ├── db │ ├── db.js │ ├── index.js │ └── models │ │ ├── index.js │ │ ├── transactions.js │ │ ├── user.js │ │ └── user.spec.js ├── index.js └── socket │ └── index.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/react", 4 | "@babel/env" 5 | /* 6 | Babel uses these "presets" to know how to transpile your Javascript code. Here's what we're saying with these: 7 | 8 | 'react': teaches Babel to recognize JSX - a must have for React! 9 | 10 | 'env': teaches Babel to transpile Javascript . This preset is highly configurable, and you can reduce the size of your bundle by limiting the number of features you transpile. Learn more here: https://github.com/babel/babel-preset-env 11 | */ 12 | ], 13 | "plugins": [ 14 | /* 15 | These plugins teach Babel to recognize EcmaScript language features that have reached "stage 2" in the process of approval for inclusion in the official EcmaScript specification (called the "TC39 process"). There are 5 stages in the process, starting at 0 (basically a brand new proposal) going up to 4 (finished and ready for inclusion). Read more about it here: http://2ality.com/2015/11/tc39-process.html. Using new language features before they're officially part of EcmaScript is fun, but it also carries a risk: sometimes proposed features can change substantially (or be rejected entirely) before finally being included in the language, so if you jump on the bandwagon too early, you risk having your code be dependent on defunct/nonstandard syntax! "Stage 2" is a fairly safe place to start - after stage 2, the feature is well on its way to official inclusion and only minor changes are expected. 16 | */ 17 | "@babel/plugin-syntax-dynamic-import", 18 | "@babel/plugin-syntax-import-meta", 19 | "@babel/plugin-proposal-class-properties", 20 | "@babel/plugin-proposal-json-strings", 21 | [ 22 | "@babel/plugin-proposal-decorators", 23 | { 24 | "legacy": true 25 | } 26 | ], 27 | "@babel/plugin-proposal-function-sent", 28 | "@babel/plugin-proposal-export-namespace-from", 29 | "@babel/plugin-proposal-numeric-separator", 30 | "@babel/plugin-proposal-throw-expressions" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [*.{yml,yaml}] 16 | indent_style = space 17 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["fullstack", "prettier", "prettier/react"], 4 | "rules": { 5 | "semi": 0 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to this Project 2 | 3 | For pull requests to be merged, authors should: 4 | 5 | * Write any applicable unit tests 6 | * Add any relevant documentation 7 | * Reference any relevant issues 8 | * Obtain a review from a team member 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | For bugs, please include the following: 2 | 3 | * What is the expected behavior? 4 | * What is the actual behavior? 5 | * What steps reproduce the behavior? 6 | 7 | For features, please specify at least minimal requirements, e.g.: 8 | 9 | * "As a user, I want a notification badge showing unread count, so I can easily manage my messages" 10 | * "As a developer, I want linting to work properly with JSX, so I can see when there is a mistake" 11 | * "As an admin, I want a management panel for users, so I can delete spurious accounts" 12 | 13 | --- 14 | 15 | _Issue description here…_ 16 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Assignee Tasks 2 | 3 | * [ ] added unit tests (or none needed) 4 | * [ ] written relevant docs (or none needed) 5 | * [ ] referenced any relevant issues (or none exist) 6 | 7 | ### Guidelines 8 | 9 | Please add a description of this Pull Request's motivation, scope, outstanding issues or potential alternatives, reasoning behind the current solution, and any other relevant information for posterity. 10 | 11 | --- 12 | 13 | _Your PR Notes Here_ 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | public/bundle.js 3 | public/bundle.js.map 4 | secrets.js 5 | .DS_Store 6 | npm-debug.log 7 | yarn-error.log 8 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | public/bundle.js 2 | public/bundle.js.map 3 | package-lock.json 4 | package.json 5 | -------------------------------------------------------------------------------- /.prettierrc.yml: -------------------------------------------------------------------------------- 1 | # printWidth: 80 # 80 2 | # tabWidth: 2 # 2 3 | # useTabs: false # false 4 | semi: false # true 5 | singleQuote: true # false 6 | # trailingComma: none # none | es5 | all 7 | bracketSpacing: false # true 8 | # jsxBracketSameLine: false # false 9 | # arrowParens: avoid # avoid | always 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - node # uses most recent stable node version 4 | services: 5 | - postgresql # starts up postgres 6 | addons: 7 | postgresql: '9.6' # highest available postgres version on Travis 8 | dist: trusty # uses trusty environment 9 | sudo: false # when on trusty, uses Docker containers for speed 10 | notifications: 11 | email: 12 | on_success: change # default: change (only when going from broken to fixed) 13 | on_failure: always # default: always (which is annoying, as it should be) 14 | install: 15 | - npm ci # faster, goes only from package-lock 16 | before_script: 17 | - psql -c 'create database "lighttext-test";' -U postgres # remember to change this name if you change it elsewhere (e.g. package.json) 18 | script: 19 | - npm test # test the code 20 | - npm run build-client # make the bundle 21 | 22 | # before_deploy: 23 | # - rm -rf node_modules # omit from the tarball, since we skip cleanup 24 | # deploy: 25 | # skip_cleanup: true # prevents travis from deleting the build 26 | # provider: heroku 27 | # app: YOUR-HEROKU-APP-NAME-HERE # see README 28 | # api_key: 29 | # secure: YOUR-***ENCRYPTED***-API-KEY-HERE # see README 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Fullstack Academy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LightText 2 | 3 | LightText (LT) is a lightning wallet that allows you to send and receive bitcoin payments over the lightning network. LT is an SMS client aimed to provide access to crypto infrastructure for individuals without smartphones. 4 | 5 | Grab your favorite Nokia phone, sign up, fund your account with bitcoin and begin paying friends and lightning invoices. 6 | 7 | Website : [light-text.herokuapp.com](https://light-text.herokuapp.com/) 8 | 9 | Youtube : https://youtu.be/SxjsJ4FDSzI 10 | 11 | 12 | 13 | ![screen1](https://github.com/light-text/lightText/blob/master/public/images/screen.png) 14 | 15 | ![screen2](https://github.com/light-text/lightText/blob/master/public/images/screen2.png) 16 | 17 | ![screen4](https://github.com/light-text/lightText/blob/master/public/images/screen4.png) 18 | 19 | ![screen3](https://github.com/light-text/lightText/blob/master/public/images/screen3.png) 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /client/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import {Navbar, Footer} from './components' 4 | import Routes from './routes' 5 | 6 | const App = () => { 7 | return ( 8 |
9 | 10 | 11 |
13 | ) 14 | } 15 | 16 | export default App 17 | -------------------------------------------------------------------------------- /client/components/AboutUs.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default function AboutUs() { 4 | return ( 5 |
6 |
7 |

About us

8 |
9 |
10 |
11 | Tali 12 |
13 |
14 | Taulant Vokshi 15 |

United States

16 |
17 | 18 | @Taulantvokshi 19 |
20 | 26 |
27 |
28 |
29 |
30 | Milan 31 |
32 |
33 | Milan Patel 34 |

United States

35 |
36 | 37 | @milanhpatel 38 |
39 | 45 |
46 |
47 |
48 |
49 | Sihem 50 |
51 |
52 | Sihem Meriki 53 |

France

54 |
55 | 56 | @SihemMrk 57 |
58 | 64 |
65 |
66 |
67 |
68 | Maurice 69 |
70 |
71 | Maurice Shalam 72 |

United States

73 |
74 | 75 | @mshalam 76 |
77 | 83 |
84 |
85 |
86 |
87 |
88 | Created at Fullstack Academy of Code in New York 89 |
90 |
91 |
92 | ) 93 | } 94 | -------------------------------------------------------------------------------- /client/components/AllTransactions.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {getTransactionThunk} from '../store/transactions' 4 | import {Table} from 'semantic-ui-react' 5 | import Moment from 'react-moment' 6 | import 'moment-timezone' 7 | /** 8 | * COMPONENT 9 | */ 10 | export class UserInfo extends React.Component { 11 | constructor(props) { 12 | super(props) 13 | this.state = { 14 | receiverTransaction: [], 15 | senderTransaction: [] 16 | } 17 | } 18 | async componentDidMount() { 19 | await this.props.getTransaction() 20 | this.setState({ 21 | receiverTransaction: this.props.history.transaction.receiver, 22 | senderTransaction: this.props.history.transaction.sender 23 | }) 24 | } 25 | render() { 26 | const receiverTransaction = this.state.receiverTransaction 27 | const senderTransaction = this.state.senderTransaction 28 | let receiverTransactionHtml = ( 29 | 30 | 31 | No transaction recorded 32 | 33 | 34 | ) 35 | let senderTransactionHtml = ( 36 | 37 | 38 | No transaction recorded 39 | 40 | 41 | ) 42 | if (receiverTransaction.length > 0) { 43 | receiverTransactionHtml = receiverTransaction.map((transaction, i) => { 44 | return ( 45 | 46 | {transaction.sender.username} 47 | 48 | {transaction.amount} satoshis 49 | 50 | 51 | {transaction.createdAt} 52 | 53 | 54 | ) 55 | }) 56 | } 57 | if (senderTransaction.length > 0) { 58 | senderTransactionHtml = senderTransaction.map((transaction, i) => { 59 | return ( 60 | 61 | {transaction.receiver.username} 62 | 63 | {transaction.amount} satoshis 64 | 65 | 66 | {transaction.createdAt} 67 | 68 | 69 | ) 70 | }) 71 | } 72 | return ( 73 |
74 |

Your transactions

75 |
76 |
77 |
78 |

Received

79 | 80 | 81 | 82 | From 83 | 84 | Amount 85 | 86 | Date 87 | 88 | 89 | 90 | {receiverTransactionHtml} 91 |
92 |
93 |
94 |

Sent

95 | 96 | 97 | 98 | To 99 | 100 | Amount 101 | 102 | Date 103 | 104 | 105 | 106 | {senderTransactionHtml} 107 |
108 |
109 |
110 |
111 |
112 | ) 113 | } 114 | } 115 | 116 | /** 117 | * CONTAINER 118 | */ 119 | const mapState = state => { 120 | return { 121 | user: state.user, 122 | history: state.transactions 123 | } 124 | } 125 | const dispatchMapState = dispatch => { 126 | return { 127 | getTransaction: () => dispatch(getTransactionThunk()) 128 | } 129 | } 130 | 131 | export default connect(mapState, dispatchMapState)(UserInfo) 132 | -------------------------------------------------------------------------------- /client/components/BitcoinsInfo.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {input} from 'semantic-ui-react' 3 | export default class BitcoinInfo extends React.Component { 4 | constructor() { 5 | super() 6 | this.state = { 7 | date: '', 8 | rate: '', 9 | value: 1 10 | } 11 | this.onChange = this.onChange.bind(this) 12 | } 13 | componentDidMount() { 14 | var that = this 15 | var date = new Date().getDate() 16 | var month = new Date().getMonth() + 1 17 | var year = new Date().getFullYear() 18 | var hours = new Date().getHours() 19 | var min = new Date().getMinutes() 20 | var sec = new Date().getSeconds() 21 | that.setState({ 22 | date: 23 | date + '/' + month + '/' + year + ' ' + hours + ':' + min + ':' + sec 24 | }) 25 | fetch('https://api.coindesk.com/v1/bpi/currentprice.json') 26 | .then(response => response.json()) 27 | .then(responseJson => { 28 | this.setState({ 29 | rate: responseJson.bpi.USD.rate_float 30 | }) 31 | // console.log('eur to bit : ' + responseJson.bpi.EUR.rate) 32 | }) 33 | .catch(error => { 34 | console.error(error) 35 | }) 36 | } 37 | onChange(e) { 38 | const re = /^[0-9\b]+$/ 39 | if (e.target.value === '' || re.test(e.target.value)) { 40 | this.setState({value: e.target.value}) 41 | } 42 | } 43 | render() { 44 | const result = this.state.rate * this.state.value 45 | return ( 46 |
47 |

Bitcoins Information

48 |

Last Update : {this.state.date}

49 |

50 | Today's rate : 1 Bitcoin = {Number(this.state.rate).toFixed(2)} USD 51 |

52 |

Convert your bitcoins to dollars :

53 |

54 |

55 | 63 |
64 |

= {Number(result).toFixed(2)} USD

65 |
66 | ) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /client/components/Chart.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {Bar, Pie, Polar} from 'react-chartjs-2' 4 | import {getTransactionThunk} from '../store/transactions' 5 | class ChartTwo extends React.Component { 6 | constructor(props) { 7 | super(props) 8 | this.createChart = this.createChart.bind(this) 9 | } 10 | async componentDidMount() { 11 | await this.props.getTransactions() 12 | } 13 | 14 | createChart(data, status) { 15 | return { 16 | labels: [...Object.keys(data)], 17 | datasets: [ 18 | { 19 | label: status, 20 | backgroundColor: [ 21 | '#d34848', 22 | '#ff8162', 23 | '#fffa67', 24 | 'rgba(153, 102, 255, 0.2)', 25 | '#62374e' 26 | ], 27 | data: [...Object.values(data)] 28 | } 29 | ] 30 | } 31 | } 32 | 33 | render() { 34 | const receiveData = {} 35 | 36 | !!this.props.history.transaction.sender && 37 | this.props.history.transaction.sender.forEach(user => { 38 | const username = user.receiver.username 39 | !receiveData[username] 40 | ? (receiveData[username] = user.amount) 41 | : (receiveData[username] += user.amount) 42 | }) 43 | 44 | return ( 45 |
46 | 47 |
48 | ) 49 | } 50 | } 51 | const mapStateToProps = state => { 52 | return {history: state.transactions} 53 | } 54 | const mapDispatchToProps = dispatch => { 55 | return {getTransactions: () => dispatch(getTransactionThunk())} 56 | } 57 | 58 | export default connect(mapStateToProps, mapDispatchToProps)(ChartTwo) 59 | -------------------------------------------------------------------------------- /client/components/ChartTwo.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {Bar, Pie, Polar} from 'react-chartjs-2' 4 | import {getTransactionThunk} from '../store/transactions' 5 | class Chart extends React.Component { 6 | constructor(props) { 7 | super(props) 8 | this.createChart = this.createChart.bind(this) 9 | } 10 | async componentDidMount() { 11 | await this.props.getTransactions() 12 | } 13 | 14 | createChart(data, status) { 15 | return { 16 | labels: [...Object.keys(data)], 17 | datasets: [ 18 | { 19 | label: status, 20 | backgroundColor: [ 21 | '#616f39', 22 | '#a7d129', 23 | '#f8eeb4', 24 | 'rgba(153, 102, 255, 0.2)', 25 | '#62374e' 26 | ], 27 | data: [...Object.values(data)] 28 | } 29 | ] 30 | } 31 | } 32 | 33 | render() { 34 | const sendData = {} 35 | 36 | !!this.props.history.transaction.receiver && 37 | this.props.history.transaction.receiver.forEach(user => { 38 | const username = user.sender.username 39 | !sendData[username] 40 | ? (sendData[username] = user.amount) 41 | : (sendData[username] += user.amount) 42 | }) 43 | 44 | return ( 45 |
46 | 47 |
48 | ) 49 | } 50 | } 51 | const mapStateToProps = state => { 52 | return {history: state.transactions} 53 | } 54 | const mapDispatchToProps = dispatch => { 55 | return {getTransactions: () => dispatch(getTransactionThunk())} 56 | } 57 | 58 | export default connect(mapStateToProps, mapDispatchToProps)(Chart) 59 | -------------------------------------------------------------------------------- /client/components/FAQs.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Link} from 'react-router-dom' 3 | 4 | export default function FAQs() { 5 | return ( 6 |
7 |

FAQs

8 |
9 |

10 | What are the advantages of the Lightning Network ? 11 |

12 | 13 |

14 | Instant Payments. 15 | 16 | Lightning-fast blockchain payments without worrying about block 17 | confirmation times. Security is enforced by blockchain 18 | smart-contracts without creating a on-blockchain transaction for 19 | individual payments. Payment speed measured in milliseconds to 20 | seconds.{' '} 21 | 22 |

23 |

24 | Scalability. 25 | 26 | Capable of millions to billions of transactions per second across 27 | the network. Capacity blows away legacy payment rails by many 28 | orders of magnitude. Attaching payment per action/click is now 29 | possible without custodians. 30 | 31 |

32 |

33 | Low Cost. 34 | 35 | By transacting and settling off-blockchain, the Lightning Network 36 | allows for exceptionally low fees, which allows for emerging use 37 | cases such as instant micropayments. 38 | 39 |

40 |

41 | Cross Blockchains. 42 | 43 | Cross-chain atomic swaps can occur off-chain instantly with 44 | heterogeneous blockchain consensus rules. So long as the chains 45 | can support the same cryptographic hash function, it is possible 46 | to make transactions across blockchains without trust in 3rd party 47 | custodians. 48 | 49 |

50 |
51 |
52 |
53 |

How do I send Bitcoin with LightText ?

54 | 55 | You can send Bitcoin by texting 'SEND' + the amount you want to send + 56 | the username or number of the person you want to send to. For more 57 | information go back to the Home page. 58 | 59 |
60 |
61 | ) 62 | } 63 | -------------------------------------------------------------------------------- /client/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Link} from 'react-router-dom' 3 | 4 | export default function Footer() { 5 | return ( 6 |
7 |
8 | 9 | Home 10 | 11 | 12 | FAQs 13 | 14 |
15 |
16 |

© LightText All Rights Reserved. 2019

17 |
18 |
19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /client/components/HomePage.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | // import {Link} from 'react-router-dom' 3 | import {Signup} from './signUp' 4 | import {AboutUs} from './' 5 | import BitcoinInfo from './BitcoinsInfo' 6 | 7 | export default function HomePage() { 8 | return ( 9 |
10 |
11 |
12 |
13 |

How It Works

14 | 15 | 16 | With LightText you can send Bitcoins by SMS. You have to register 17 | with us and send money to someone registered. You don't need 18 | Internet, just a phone number. 19 | 20 |

Lightning Wallets ⚡

21 |

with zero configuration

22 | 23 | Unfairly cheap and fast transactions. LightText brings zero 24 | configuration, ready to use, user friendly Lightning Network 25 | Wallets for iOS and Android. Read more about our open source. 26 | 27 |
28 |
29 | 30 |
37 | 48 | 53 |
54 |
55 |
56 |
57 |
58 | 59 |
60 |
61 | It is easy if you can text, you can crypto ! 62 |
63 |
64 |
65 |
66 | 67 |
68 |
69 |
70 |
71 |