mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-01 11:33:41 +03:00
Merge pull request #5149 from finned-palmer/switch-to-typescript
btc-wallet: Port btc-wallet to typescript.
This commit is contained in:
commit
3f38506125
2
pkg/btc-wallet/.eslintignore
Normal file
2
pkg/btc-wallet/.eslintignore
Normal file
@ -0,0 +1,2 @@
|
||||
config/webpack.dev.js
|
||||
config/webpack.prod.js
|
@ -6,9 +6,10 @@ const urbitrc = require('./urbitrc');
|
||||
const fs = require('fs-extra');
|
||||
const _ = require('lodash');
|
||||
|
||||
function copy(src,dest) {
|
||||
return new Promise((res,rej) =>
|
||||
fs.copy(src,dest, err => err ? rej(err) : res()));
|
||||
function copy(src, dest) {
|
||||
return new Promise((res, rej) =>
|
||||
fs.copy(src, dest, (err) => (err ? rej(err) : res()))
|
||||
);
|
||||
}
|
||||
|
||||
class UrbitShipPlugin {
|
||||
@ -35,9 +36,12 @@ let devServer = {
|
||||
historyApiFallback: true,
|
||||
};
|
||||
|
||||
const router = _.mapKeys(urbitrc.FLEET || {}, (value, key) => `${key}.localhost:9000`);
|
||||
const router = _.mapKeys(
|
||||
urbitrc.FLEET || {},
|
||||
(value, key) => `${key}.localhost:9000`
|
||||
);
|
||||
|
||||
if(urbitrc.URL) {
|
||||
if (urbitrc.URL) {
|
||||
devServer = {
|
||||
...devServer,
|
||||
index: '',
|
||||
@ -45,17 +49,17 @@ if(urbitrc.URL) {
|
||||
'/~btc/js/bundle/index.*.js': {
|
||||
target: 'http://localhost:9000',
|
||||
pathRewrite: (req, path) => {
|
||||
return '/index.js'
|
||||
}
|
||||
return '/index.js';
|
||||
},
|
||||
},
|
||||
'**': {
|
||||
changeOrigin: true,
|
||||
target: urbitrc.URL,
|
||||
router,
|
||||
// ensure proxy doesn't timeout channels
|
||||
proxyTimeout: 0
|
||||
}
|
||||
}
|
||||
proxyTimeout: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -63,30 +67,16 @@ module.exports = {
|
||||
node: { fs: 'empty' },
|
||||
mode: 'development',
|
||||
entry: {
|
||||
app: './src/index.js'
|
||||
app: './src/index.tsx',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(j|t)sx?$/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: ['@babel/preset-env', ['@babel/preset-react', {
|
||||
runtime: 'automatic',
|
||||
development: 'true',
|
||||
importSource: '@welldone-software/why-did-you-render',
|
||||
}]],
|
||||
plugins: [
|
||||
'@babel/transform-runtime',
|
||||
'@babel/plugin-proposal-object-rest-spread',
|
||||
'@babel/plugin-proposal-optional-chaining',
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
'react-hot-loader/babel'
|
||||
]
|
||||
}
|
||||
loader: 'ts-loader',
|
||||
},
|
||||
exclude: /node_modules/
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
@ -96,33 +86,31 @@ module.exports = {
|
||||
// Translates CSS into CommonJS
|
||||
'css-loader',
|
||||
// Compiles Sass to CSS
|
||||
'sass-loader'
|
||||
]
|
||||
}
|
||||
]
|
||||
'sass-loader',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.ts', '.tsx']
|
||||
extensions: ['.js', '.ts', '.tsx'],
|
||||
},
|
||||
devtool: 'inline-source-map',
|
||||
devServer: devServer,
|
||||
plugins: [
|
||||
new UrbitShipPlugin(urbitrc)
|
||||
],
|
||||
plugins: [new UrbitShipPlugin(urbitrc)],
|
||||
watch: true,
|
||||
watchOptions: {
|
||||
poll: true,
|
||||
ignored: '/node_modules/'
|
||||
ignored: '/node_modules/',
|
||||
},
|
||||
output: {
|
||||
filename: 'index.js',
|
||||
chunkFilename: 'index.js',
|
||||
path: path.resolve(__dirname, '../dist'),
|
||||
publicPath: '/',
|
||||
globalObject: 'this'
|
||||
globalObject: 'this',
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
usedExports: true
|
||||
}
|
||||
usedExports: true,
|
||||
},
|
||||
};
|
||||
|
@ -6,55 +6,46 @@ module.exports = {
|
||||
node: { fs: 'empty' },
|
||||
mode: 'production',
|
||||
entry: {
|
||||
app: './src/index.js'
|
||||
app: './src/index.tsx',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
test: /\.(j|t)sx?$/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: ['@babel/preset-env', '@babel/preset-react'],
|
||||
plugins: [
|
||||
'@babel/transform-runtime',
|
||||
'@babel/plugin-proposal-object-rest-spread',
|
||||
'@babel/plugin-proposal-optional-chaining',
|
||||
'@babel/plugin-proposal-class-properties'
|
||||
]
|
||||
}
|
||||
loader: 'ts-loader',
|
||||
},
|
||||
exclude: /node_modules/
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
test: /\.css$/i,
|
||||
use: [
|
||||
// Creates `style` nodes from JS strings
|
||||
'style-loader',
|
||||
// Translates CSS into CommonJS
|
||||
'css-loader',
|
||||
// Compiles Sass to CSS
|
||||
'sass-loader'
|
||||
]
|
||||
}
|
||||
]
|
||||
'sass-loader',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.ts', '.tsx']
|
||||
extensions: ['.js', '.ts', '.tsx'],
|
||||
},
|
||||
devtool: 'source-map',
|
||||
plugins: [
|
||||
new CleanWebpackPlugin()
|
||||
],
|
||||
plugins: [new CleanWebpackPlugin()],
|
||||
output: {
|
||||
filename: (pathData) => {
|
||||
return pathData.chunk.name === 'app' ? 'index.[contenthash].js' : '[name].js';
|
||||
return pathData.chunk.name === 'app'
|
||||
? 'index.[contenthash].js'
|
||||
: '[name].js';
|
||||
},
|
||||
path: path.resolve(__dirname, `../../arvo/app/btc-wallet/js/bundle`),
|
||||
publicPath: '/',
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
usedExports: true
|
||||
}
|
||||
usedExports: true,
|
||||
},
|
||||
};
|
||||
|
228
pkg/btc-wallet/package-lock.json
generated
228
pkg/btc-wallet/package-lock.json
generated
@ -1430,6 +1430,22 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/history": {
|
||||
"version": "4.7.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz",
|
||||
"integrity": "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/hoist-non-react-statics": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
|
||||
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"hoist-non-react-statics": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"@types/html-minifier-terser": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
|
||||
@ -1441,6 +1457,12 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
|
||||
"integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA=="
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.171",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.171.tgz",
|
||||
"integrity": "sha512-7eQ2xYLLI/LsicL2nejW9Wyko3lcpN6O/z0ZLHrEQsg280zIdCv1t/0m6UtBjUHokCGBQ3gYTbHzDkZ1xOBwwg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz",
|
||||
@ -1459,12 +1481,76 @@
|
||||
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/prop-types": {
|
||||
"version": "15.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
|
||||
"integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/react": {
|
||||
"version": "17.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.15.tgz",
|
||||
"integrity": "sha512-uTKHDK9STXFHLaKv6IMnwp52fm0hwU+N89w/p9grdUqcFA6WuqDyPhaWopbNyE1k/VhgzmHl8pu1L4wITtmlLw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/prop-types": "*",
|
||||
"@types/scheduler": "*",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"version": "17.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz",
|
||||
"integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-router": {
|
||||
"version": "5.1.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.16.tgz",
|
||||
"integrity": "sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/history": "*",
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-router-dom": {
|
||||
"version": "5.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.8.tgz",
|
||||
"integrity": "sha512-03xHyncBzG0PmDmf8pf3rehtjY0NpUj7TIN46FrT5n1ZWHPZvXz32gUyNboJ+xsL8cpg8bQVLcllptcQHvocrw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/history": "*",
|
||||
"@types/react": "*",
|
||||
"@types/react-router": "*"
|
||||
}
|
||||
},
|
||||
"@types/scheduler": {
|
||||
"version": "0.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
|
||||
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/source-list-map": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
|
||||
"integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/styled-components": {
|
||||
"version": "5.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.11.tgz",
|
||||
"integrity": "sha512-u8g3bSw9KUiZY+S++gh+LlURGraqBe3MC5I5dygrNjGDHWWQfsmZZRTJ9K9oHU2CqWtxChWmJkDI/gp+TZPQMw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/hoist-non-react-statics": "*",
|
||||
"@types/react": "*",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"@types/tapable": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.7.tgz",
|
||||
@ -1499,6 +1585,12 @@
|
||||
"source-map": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"@types/webpack-env": {
|
||||
"version": "1.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.16.2.tgz",
|
||||
"integrity": "sha512-vKx7WNQNZDyJveYcHAm9ZxhqSGLYwoyLhrHjLBOkw3a7cT76sTdjgtwyijhk1MaHyRIuSztcVwrUOO/NEu68Dw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/webpack-sources": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz",
|
||||
@ -3472,6 +3564,12 @@
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
|
||||
},
|
||||
"csstype": {
|
||||
"version": "3.0.8",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz",
|
||||
"integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==",
|
||||
"dev": true
|
||||
},
|
||||
"cycle": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",
|
||||
@ -10240,6 +10338,130 @@
|
||||
"resolved": "https://registry.npmjs.org/transformation-matrix/-/transformation-matrix-2.1.1.tgz",
|
||||
"integrity": "sha512-74MoNHhwLVuzwaPDcAecFjSkOA9vwWqyOdkeB0Be8Jc/IWSS5SNZKapFllqzkTliqZptkvqX5CZnVeDvfhN8cw=="
|
||||
},
|
||||
"ts-loader": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.2.0.tgz",
|
||||
"integrity": "sha512-ebXBFrNyMSmbWgjnb3WBloUBK+VSx1xckaXsMXxlZRDqce/OPdYBVN5efB0W3V0defq0Gcy4YuzvPGqRgjj85A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^4.1.0",
|
||||
"enhanced-resolve": "^4.0.0",
|
||||
"loader-utils": "^2.0.0",
|
||||
"micromatch": "^4.0.0",
|
||||
"semver": "^7.3.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"json5": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
|
||||
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"micromatch": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
|
||||
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"braces": "^3.0.1",
|
||||
"picomatch": "^2.2.3"
|
||||
}
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
|
||||
@ -10293,9 +10515,9 @@
|
||||
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
|
||||
"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
|
||||
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
|
||||
"dev": true
|
||||
},
|
||||
"unbox-primitive": {
|
||||
|
@ -20,6 +20,11 @@
|
||||
"@babel/preset-env": "^7.9.5",
|
||||
"@babel/preset-react": "^7.9.4",
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"@types/lodash": "^4.14.171",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"@types/react-router-dom": "^5.1.8",
|
||||
"@types/styled-components": "^5.1.11",
|
||||
"@types/webpack-env": "^1.16.2",
|
||||
"@welldone-software/why-did-you-render": "^6.1.1",
|
||||
"babel-loader": "^8.1.0",
|
||||
"babel-plugin-root-import": "^6.5.0",
|
||||
@ -36,7 +41,8 @@
|
||||
"react-hot-loader": "^4.12.21",
|
||||
"sass": "^1.26.5",
|
||||
"sass-loader": "^8.0.2",
|
||||
"typescript": "^4.2.3",
|
||||
"ts-loader": "8.2.0",
|
||||
"typescript": "^4.3.5",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.10.3"
|
||||
|
@ -3,11 +3,11 @@ import { BrowserRouter } from 'react-router-dom';
|
||||
import { ThemeProvider } from 'styled-components';
|
||||
import light from './themes/light';
|
||||
import { Box, Reset } from '@tlon/indigo-react';
|
||||
import StartupModal from './lib/startupModal.js';
|
||||
import Body from './lib/body.js';
|
||||
import { useSettings } from '../hooks/useSettings.js';
|
||||
import StartupModal from './components/StartupModal';
|
||||
import { useSettings } from './hooks/useSettings';
|
||||
import Body from './components/Body';
|
||||
|
||||
const Root = () => {
|
||||
const App: React.FC = () => {
|
||||
const { loaded, wallet, provider, scanProgress } = useSettings();
|
||||
const scanning = scanProgress?.main !== null || scanProgress?.change !== null;
|
||||
const blur = !loaded || scanning ? false : !(wallet && provider);
|
||||
@ -37,4 +37,4 @@ const Root = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default Root;
|
||||
export default App;
|
@ -1,10 +1,10 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Row, Text, Button, Col } from '@tlon/indigo-react';
|
||||
import Send from './send.js';
|
||||
import CurrencyPicker from './currencyPicker.js';
|
||||
import { copyToClipboard, satsToCurrency } from '../../lib/util.js';
|
||||
import { useSettings } from '../../hooks/useSettings.js';
|
||||
import { api } from '../../api';
|
||||
import Send from './Send/Send';
|
||||
import CurrencyPicker from './CurrencyPicker';
|
||||
import { copyToClipboard, satsToCurrency } from '../lib/util';
|
||||
import { useSettings } from '../hooks/useSettings';
|
||||
import { api } from '../lib/api';
|
||||
|
||||
const Balance = () => {
|
||||
const {
|
||||
@ -23,7 +23,7 @@ const Balance = () => {
|
||||
const [copiedString, setCopiedString] = useState(false);
|
||||
const scanning = scanProgress?.main !== null || scanProgress?.change !== null;
|
||||
|
||||
const copyAddress = async (arg) => {
|
||||
const copyAddress = async (arg: 'string' | 'button') => {
|
||||
await copyToClipboard(address);
|
||||
api.btcWalletCommand({ 'gen-new-address': null });
|
||||
|
@ -1,14 +1,14 @@
|
||||
import React from 'react';
|
||||
import { Box, LoadingSpinner, Col } from '@tlon/indigo-react';
|
||||
import { Switch, Route } from 'react-router-dom';
|
||||
import Balance from './balance.js';
|
||||
import Transactions from './transactions.js';
|
||||
import Warning from './warning.js';
|
||||
import Header from './header.js';
|
||||
import Settings from './settings.js';
|
||||
import { useSettings } from '../../hooks/useSettings.js';
|
||||
import Balance from './Balance';
|
||||
import Transactions from './Transactions/Transactions';
|
||||
import Warning from './Warning';
|
||||
import Header from './Header';
|
||||
import Settings from './Settings';
|
||||
import { useSettings } from '../hooks/useSettings';
|
||||
|
||||
const Body = () => {
|
||||
const Body: React.FC = () => {
|
||||
const { loaded, showWarning: warning } = useSettings();
|
||||
const cardWidth = window.innerWidth <= 475 ? '350px' : '400px';
|
||||
return !loaded ? (
|
||||
@ -19,12 +19,7 @@ const Body = () => {
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
>
|
||||
<LoadingSpinner
|
||||
width={7}
|
||||
height={7}
|
||||
background="midOrange"
|
||||
foreground="orange"
|
||||
/>
|
||||
<LoadingSpinner background="midOrange" foreground="orange" />
|
||||
</Box>
|
||||
) : (
|
||||
<Switch>
|
@ -1,19 +1,20 @@
|
||||
import React from 'react';
|
||||
import { Icon, Row, Text } from '@tlon/indigo-react';
|
||||
import { api } from '../../api';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
import { api } from '../lib/api';
|
||||
import { useSettings } from '../hooks/useSettings';
|
||||
|
||||
const CurrencyPicker = () => {
|
||||
const { denomination, currencyRates } = useSettings();
|
||||
const switchCurrency = () => {
|
||||
let newCurrency;
|
||||
if (denomination === 'BTC') {
|
||||
if (currencyRates['USD']) {
|
||||
if ((currencyRates as any)['USD']) {
|
||||
newCurrency = 'USD';
|
||||
}
|
||||
} else if (denomination === 'USD') {
|
||||
newCurrency = 'BTC';
|
||||
}
|
||||
console.log({ newCurrency, denomination });
|
||||
let setCurrency = {
|
||||
'put-entry': {
|
||||
value: newCurrency,
|
32
pkg/btc-wallet/src/components/Error.tsx
Normal file
32
pkg/btc-wallet/src/components/Error.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
import { Text } from '@tlon/indigo-react';
|
||||
|
||||
enum ErrorTypes {
|
||||
'cant-pay-ourselves' = 'Cannot pay ourselves',
|
||||
'no-comets' = 'Cannot pay comets',
|
||||
'no-dust' = 'Cannot send dust',
|
||||
'tx-being-signed' = 'Cannot pay when transaction is being signed',
|
||||
'insufficient-balance' = 'Insufficient confirmed balance',
|
||||
'broadcast-fail' = 'Transaction broadcast failed',
|
||||
'invalid-master-ticker' = 'Invalid master ticket',
|
||||
'invalid-signed' = 'Invalid signed bitcoin transaction',
|
||||
}
|
||||
|
||||
const Error = ({
|
||||
error,
|
||||
fontSize,
|
||||
...rest
|
||||
}: {
|
||||
error: string;
|
||||
fontSize?: string;
|
||||
}) => (
|
||||
<Text color="red" style={{ fontSize }} {...rest}>
|
||||
{
|
||||
(ErrorTypes as any)[
|
||||
Object.keys(ErrorTypes).filter((et) => et === error)[0]
|
||||
]
|
||||
}
|
||||
</Text>
|
||||
);
|
||||
|
||||
export default Error;
|
@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import { Box, Icon, Row, Text } from '@tlon/indigo-react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
import { useSettings } from '../hooks/useSettings';
|
||||
|
||||
const Header = ({ settings }) => {
|
||||
const Header = ({ settings }: { settings: boolean }) => {
|
||||
const { provider } = useSettings();
|
||||
let icon = settings ? 'X' : 'Adjust';
|
||||
let iconColor = settings ? 'black' : 'orange';
|
@ -9,15 +9,15 @@ import {
|
||||
LoadingSpinner,
|
||||
} from '@tlon/indigo-react';
|
||||
import { isValidPatp } from 'urbit-ob';
|
||||
import { api } from '../../api';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
import { api } from '../lib/api';
|
||||
import { useSettings } from '../hooks/useSettings';
|
||||
|
||||
const providerStatuses = {
|
||||
checking: 'checking',
|
||||
failed: 'failed',
|
||||
ready: 'ready',
|
||||
initial: '',
|
||||
};
|
||||
enum providerStatuses {
|
||||
checking,
|
||||
failed,
|
||||
ready,
|
||||
initial = '',
|
||||
}
|
||||
|
||||
const ProviderModal = () => {
|
||||
const { providerPerms } = useSettings();
|
||||
@ -28,7 +28,7 @@ const ProviderModal = () => {
|
||||
const [provider, setProvider] = useState(null);
|
||||
const [connecting, setConnecting] = useState(false);
|
||||
|
||||
const checkProvider = (e) => {
|
||||
const checkProvider = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// TODO: loading states
|
||||
setProviderStatus(providerStatuses.initial);
|
||||
let givenProvider = e.target.value;
|
||||
@ -103,7 +103,7 @@ const ProviderModal = () => {
|
||||
to set a provider node. A provider node is an urbit which maintains a
|
||||
synced Bitcoin ledger.
|
||||
<a
|
||||
fontSize="14px"
|
||||
style={{ fontSize: '14px' }}
|
||||
target="_blank"
|
||||
href="https://urbit.org/bitcoin-wallet"
|
||||
rel="noreferrer"
|
||||
@ -132,7 +132,9 @@ const ProviderModal = () => {
|
||||
backgroundColor={workingBg}
|
||||
color={workingColor}
|
||||
borderColor={workingColor}
|
||||
onChange={(e) => checkProvider(e)}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
checkProvider(e)
|
||||
}
|
||||
/>
|
||||
{providerStatus === providerStatuses.checking ? (
|
||||
<LoadingSpinner />
|
||||
@ -150,7 +152,7 @@ const ProviderModal = () => {
|
||||
providerStatus === providerStatuses.ready ? 'pointer' : 'default',
|
||||
}}
|
||||
onClick={() => {
|
||||
submitProvider(provider);
|
||||
submitProvider();
|
||||
}}
|
||||
>
|
||||
Set Peer Node
|
@ -9,16 +9,22 @@ import {
|
||||
Col,
|
||||
LoadingSpinner,
|
||||
} from '@tlon/indigo-react';
|
||||
import { Sigil } from './sigil.js';
|
||||
import Sigil from '../Sigil';
|
||||
import * as bitcoin from 'bitcoinjs-lib';
|
||||
import { isValidPatp } from 'urbit-ob';
|
||||
import Sent from './sent.js';
|
||||
import Error from './error.js';
|
||||
import { satsToCurrency } from '../../lib/util.js';
|
||||
import { useSettings } from '../../hooks/useSettings.js';
|
||||
import { api } from '../../api';
|
||||
import Sent from './Sent';
|
||||
import Error from '../Error';
|
||||
import { satsToCurrency } from '../../lib/util';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
import { api } from '../../lib/api';
|
||||
|
||||
const BridgeInvoice = ({ payee, stopSending, satsAmount }) => {
|
||||
type Props = {
|
||||
payee: string;
|
||||
stopSending: () => void;
|
||||
satsAmount: number;
|
||||
};
|
||||
|
||||
const BridgeInvoice: React.FC<Props> = ({ payee, stopSending, satsAmount }) => {
|
||||
const { error, currencyRates, fee, broadcastSuccess, denomination, psbt } =
|
||||
useSettings();
|
||||
const [txHex, setTxHex] = useState('');
|
||||
@ -40,14 +46,14 @@ const BridgeInvoice = ({ payee, stopSending, satsAmount }) => {
|
||||
window.open('https://bridge.urbit.org/?kind=btc&utx=' + psbt);
|
||||
});
|
||||
|
||||
const broadCastTx = (hex) => {
|
||||
const broadCastTx = (hex: string) => {
|
||||
let command = {
|
||||
'broadcast-tx': hex,
|
||||
};
|
||||
return api.btcWalletCommand(command);
|
||||
};
|
||||
|
||||
const sendBitcoin = (hex) => {
|
||||
const sendBitcoin = (hex: string) => {
|
||||
try {
|
||||
bitcoin.Transaction.fromHex(hex);
|
||||
broadCastTx(hex);
|
||||
@ -58,7 +64,7 @@ const BridgeInvoice = ({ payee, stopSending, satsAmount }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const checkTxHex = (e) => {
|
||||
const checkTxHex = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setTxHex(e.target.value);
|
||||
setReady(txHex.length > 0);
|
||||
setLocalError('');
|
||||
@ -169,11 +175,11 @@ const BridgeInvoice = ({ payee, stopSending, satsAmount }) => {
|
||||
backgroundColor={inputBg}
|
||||
borderColor={inputBorder}
|
||||
style={{ lineHeight: '4' }}
|
||||
onChange={(e) => checkTxHex(e)}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => checkTxHex(e)}
|
||||
/>
|
||||
{localError !== '' && (
|
||||
<Row>
|
||||
<Error error={localError} fontSize="14px" mt={2} />
|
||||
<Error error={localError} fontSize="14px" />
|
||||
</Row>
|
||||
)}
|
||||
<Row flexDirection="row-reverse" mt={4} alignItems="center">
|
||||
@ -200,7 +206,10 @@ const BridgeInvoice = ({ payee, stopSending, satsAmount }) => {
|
||||
>
|
||||
Send BTC
|
||||
</Button>
|
||||
{broadcasting ? <LoadingSpinner mr={3} /> : null}
|
||||
{
|
||||
// @ts-ignore
|
||||
broadcasting ? <LoadingSpinner mr={3} /> : null
|
||||
}
|
||||
</Row>
|
||||
</Col>
|
||||
)}
|
@ -9,16 +9,26 @@ import {
|
||||
Col,
|
||||
LoadingSpinner,
|
||||
} from '@tlon/indigo-react';
|
||||
import { Sigil } from './sigil.js';
|
||||
import Sigil from '../Sigil';
|
||||
import * as bitcoin from 'bitcoinjs-lib';
|
||||
import { isValidPatp } from 'urbit-ob';
|
||||
import Sent from './sent.js';
|
||||
import Error from './error.js';
|
||||
import Error from '../Error';
|
||||
import { copyToClipboard, satsToCurrency } from '../../lib/util.js';
|
||||
import { useSettings } from '../../hooks/useSettings.js';
|
||||
import { api } from '../../api';
|
||||
import { api } from '../../lib/api';
|
||||
|
||||
const ExternalInvoice = ({ payee, stopSending, satsAmount }) => {
|
||||
type Props = {
|
||||
payee: string;
|
||||
stopSending: () => void;
|
||||
satsAmount: number;
|
||||
};
|
||||
|
||||
const ExternalInvoice: React.FC<Props> = ({
|
||||
payee,
|
||||
stopSending,
|
||||
satsAmount,
|
||||
}) => {
|
||||
const { error, currencyRates, fee, broadcastSuccess, denomination, psbt } =
|
||||
useSettings();
|
||||
const [txHex, setTxHex] = useState('');
|
||||
@ -36,14 +46,14 @@ const ExternalInvoice = ({ payee, stopSending, satsAmount }) => {
|
||||
}
|
||||
}, [error, broadcasting, setBroadcasting]);
|
||||
|
||||
const broadCastTx = (hex) => {
|
||||
const broadCastTx = (hex: string) => {
|
||||
let command = {
|
||||
'broadcast-tx': hex,
|
||||
};
|
||||
return api.btcWalletCommand(command);
|
||||
};
|
||||
|
||||
const sendBitcoin = (hex) => {
|
||||
const sendBitcoin = (hex: string) => {
|
||||
try {
|
||||
bitcoin.Transaction.fromHex(hex);
|
||||
broadCastTx(hex);
|
||||
@ -54,7 +64,7 @@ const ExternalInvoice = ({ payee, stopSending, satsAmount }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const checkTxHex = (e) => {
|
||||
const checkTxHex = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setTxHex(e.target.value);
|
||||
setReady(txHex.length > 0);
|
||||
setLocalError('');
|
||||
@ -211,11 +221,13 @@ const ExternalInvoice = ({ payee, stopSending, satsAmount }) => {
|
||||
backgroundColor={inputBg}
|
||||
borderColor={inputBorder}
|
||||
style={{ lineHeight: '4' }}
|
||||
onChange={(e) => checkTxHex(e)}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
checkTxHex(e)
|
||||
}
|
||||
/>
|
||||
{localError !== '' && (
|
||||
<Row>
|
||||
<Error error={localError} fontSize="14px" mt={2} />
|
||||
<Error error={localError} fontSize="14px" />
|
||||
</Row>
|
||||
)}
|
||||
</Row>
|
||||
@ -249,7 +261,7 @@ const ExternalInvoice = ({ payee, stopSending, satsAmount }) => {
|
||||
>
|
||||
Send BTC
|
||||
</Button>
|
||||
{broadcasting ? <LoadingSpinner mr={3} /> : null}
|
||||
{broadcasting ? <LoadingSpinner /> : null}
|
||||
</Row>
|
||||
</Col>
|
||||
)}
|
84
pkg/btc-wallet/src/components/Send/FeePicker.tsx
Normal file
84
pkg/btc-wallet/src/components/Send/FeePicker.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Text,
|
||||
Col,
|
||||
StatelessRadioButtonField as RadioButton,
|
||||
Label,
|
||||
} from '@tlon/indigo-react';
|
||||
import { FeeChoices, feeLevels } from './Send';
|
||||
|
||||
type Props = {
|
||||
feeChoices: FeeChoices;
|
||||
feeValue: number;
|
||||
setFeeValue: React.Dispatch<feeLevels>;
|
||||
feeDismiss: () => void;
|
||||
};
|
||||
|
||||
const FeePicker: React.FC<Props> = ({
|
||||
feeChoices,
|
||||
feeValue,
|
||||
setFeeValue,
|
||||
feeDismiss,
|
||||
}) => (
|
||||
<Box
|
||||
position="absolute"
|
||||
p={4}
|
||||
border="1px solid green"
|
||||
zIndex={10}
|
||||
backgroundColor="white"
|
||||
borderRadius={3}
|
||||
>
|
||||
<Text fontSize={1} color="black" fontWeight="bold" mb={4}>
|
||||
Transaction Speed
|
||||
</Text>
|
||||
<Col mt={4}>
|
||||
<RadioButton
|
||||
name="feeRadio"
|
||||
selected={feeValue === feeLevels.low}
|
||||
p="2"
|
||||
onChange={() => {
|
||||
setFeeValue(feeLevels.low);
|
||||
feeDismiss();
|
||||
}}
|
||||
>
|
||||
<Label fontSize="14px">
|
||||
Slow: {feeChoices[feeLevels.low][1]} sats/vbyte ~
|
||||
{feeChoices[feeLevels.low][0]}m
|
||||
</Label>
|
||||
</RadioButton>
|
||||
|
||||
<RadioButton
|
||||
name="feeRadio"
|
||||
selected={feeValue === feeLevels.mid}
|
||||
p="2"
|
||||
onChange={() => {
|
||||
setFeeValue(feeLevels.mid);
|
||||
feeDismiss();
|
||||
}}
|
||||
>
|
||||
<Label fontSize="14px">
|
||||
Normal: {feeChoices[feeLevels.mid][1]} sats/vbyte ~
|
||||
{feeChoices[feeLevels.mid][0]}m
|
||||
</Label>
|
||||
</RadioButton>
|
||||
|
||||
<RadioButton
|
||||
name="feeRadio"
|
||||
selected={feeValue === feeLevels.high}
|
||||
p="2"
|
||||
onChange={() => {
|
||||
setFeeValue(feeLevels.high);
|
||||
feeDismiss();
|
||||
}}
|
||||
>
|
||||
<Label fontSize="14px">
|
||||
Fast: {feeChoices[feeLevels.high][1]} sats/vbyte ~
|
||||
{feeChoices[feeLevels.high][0]}m
|
||||
</Label>
|
||||
</RadioButton>
|
||||
</Col>
|
||||
</Box>
|
||||
);
|
||||
|
||||
export default FeePicker;
|
@ -9,15 +9,16 @@ import {
|
||||
Col,
|
||||
LoadingSpinner,
|
||||
} from '@tlon/indigo-react';
|
||||
import { Sigil } from './sigil.js';
|
||||
import * as bitcoin from 'bitcoinjs-lib';
|
||||
import * as kg from 'urbit-key-generation';
|
||||
import Sent from './sent.js';
|
||||
import { patp2dec, isValidPatq, isValidPatp } from 'urbit-ob';
|
||||
import { satsToCurrency } from '../../lib/util.js';
|
||||
import Error from './error.js';
|
||||
import { useSettings } from '../../hooks/useSettings.js';
|
||||
import { api } from '../../api';
|
||||
import * as bitcoin from 'bitcoinjs-lib';
|
||||
import Sigil from '../Sigil';
|
||||
import Sent from './Sent';
|
||||
import { satsToCurrency } from '../../lib/util';
|
||||
import Error from '../Error';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
import { api } from '../../lib/api';
|
||||
import { UrbitWallet } from '../../types';
|
||||
|
||||
const BITCOIN_MAINNET_INFO = {
|
||||
messagePrefix: '\x18Bitcoin Signed Message:\n',
|
||||
@ -43,7 +44,13 @@ const BITCOIN_TESTNET_INFO = {
|
||||
wif: 0xef,
|
||||
};
|
||||
|
||||
const Invoice = ({ stopSending, payee, satsAmount }) => {
|
||||
type Props = {
|
||||
stopSending: () => void;
|
||||
payee: string;
|
||||
satsAmount: number;
|
||||
};
|
||||
|
||||
const Invoice: React.FC<Props> = ({ stopSending, payee, satsAmount }) => {
|
||||
const {
|
||||
error,
|
||||
currencyRates,
|
||||
@ -64,20 +71,20 @@ const Invoice = ({ stopSending, payee, satsAmount }) => {
|
||||
}
|
||||
}, [error, broadcasting, setBroadcasting]);
|
||||
|
||||
const broadCastTx = (psbtHex) => {
|
||||
const broadCastTx = (psbtHex: string) => {
|
||||
let command = {
|
||||
'broadcast-tx': psbtHex,
|
||||
};
|
||||
return api.btcWalletCommand(command);
|
||||
};
|
||||
|
||||
const sendBitcoin = (ticket, psbt) => {
|
||||
const sendBitcoin = (ticket: string, psbt: string) => {
|
||||
const newPsbt = bitcoin.Psbt.fromBase64(psbt);
|
||||
setBroadcasting(true);
|
||||
kg.generateWallet({
|
||||
ticket,
|
||||
ship: parseInt(patp2dec('~' + window.ship)),
|
||||
}).then((urbitWallet) => {
|
||||
ship: parseInt(patp2dec('~' + (window as any).ship)),
|
||||
}).then((urbitWallet: UrbitWallet) => {
|
||||
// this wasn't being used, not clear why it was pulled out.
|
||||
// const { xpub } =
|
||||
// network === 'testnet'
|
||||
@ -116,7 +123,9 @@ const Invoice = ({ stopSending, payee, satsAmount }) => {
|
||||
});
|
||||
};
|
||||
|
||||
const checkTicket = ({ target: { value } }) => {
|
||||
const checkTicket = ({
|
||||
target: { value },
|
||||
}: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// TODO: port over bridge ticket validation logic
|
||||
setMasterTicket(value);
|
||||
setReady(isValidPatq(value));
|
||||
@ -216,19 +225,21 @@ const Invoice = ({ stopSending, payee, satsAmount }) => {
|
||||
fontSize="14px"
|
||||
type="password"
|
||||
name="masterTicket"
|
||||
obscure={(value) => value.replace(/[^~-]+/g, '••••••')}
|
||||
obscure={(value: string) => value.replace(/[^~-]+/g, '••••••')}
|
||||
placeholder="••••••-••••••-••••••-••••••"
|
||||
autoCapitalize="none"
|
||||
autoCorrect="off"
|
||||
color={inputColor}
|
||||
backgroundColor={inputBg}
|
||||
borderColor={inputBorder}
|
||||
onChange={(e) => checkTicket(e)}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
checkTicket(e)
|
||||
}
|
||||
/>
|
||||
</Row>
|
||||
{error !== '' && (
|
||||
<Row>
|
||||
<Error fontSize="14px" color="red" error={error} mt={2} />
|
||||
<Error fontSize="14px" error={error} />
|
||||
</Row>
|
||||
)}
|
||||
<Row flexDirection="row-reverse" mt={4} alignItems="center">
|
||||
@ -252,7 +263,10 @@ const Invoice = ({ stopSending, payee, satsAmount }) => {
|
||||
>
|
||||
Send BTC
|
||||
</Button>
|
||||
{broadcasting ? <LoadingSpinner mr={3} /> : null}
|
||||
{
|
||||
// @ts-ignore
|
||||
broadcasting ? <LoadingSpinner mr={3} /> : null
|
||||
}
|
||||
</Row>
|
||||
</Col>
|
||||
)}
|
@ -9,81 +9,99 @@ import {
|
||||
Col,
|
||||
LoadingSpinner,
|
||||
} from '@tlon/indigo-react';
|
||||
import Invoice from './invoice.js';
|
||||
import BridgeInvoice from './bridgeInvoice.js';
|
||||
import FeePicker from './feePicker.js';
|
||||
import Error from './error.js';
|
||||
import Signer from './signer.js';
|
||||
import Invoice from './Invoice';
|
||||
import BridgeInvoice from './BridgeInvoice';
|
||||
import ExternalInvoice from './ExternalInvoice';
|
||||
import FeePicker from './FeePicker';
|
||||
import Error from '../Error';
|
||||
import Signer from './Signer';
|
||||
import { validate } from 'bitcoin-address-validation';
|
||||
import * as ob from 'urbit-ob';
|
||||
import { useSettings } from '../../hooks/useSettings.js';
|
||||
import { api } from '../../api';
|
||||
import { deSig } from '../../lib/util.js';
|
||||
import ExternalInvoice from './externalInvoice.js';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
import { api } from '../../lib/api';
|
||||
import { deSig } from '../../lib/util';
|
||||
|
||||
const focusFields = {
|
||||
empty: '',
|
||||
payee: 'payee',
|
||||
currency: 'currency',
|
||||
sats: 'sats',
|
||||
note: 'note',
|
||||
enum focusFields {
|
||||
payee,
|
||||
currency,
|
||||
sats,
|
||||
note,
|
||||
empty = '',
|
||||
}
|
||||
|
||||
export enum feeLevels {
|
||||
low,
|
||||
mid,
|
||||
high,
|
||||
}
|
||||
|
||||
export enum signMethods {
|
||||
bridge,
|
||||
masterTicket,
|
||||
external,
|
||||
}
|
||||
|
||||
enum payeeTypes {
|
||||
ship,
|
||||
address,
|
||||
initial = '',
|
||||
}
|
||||
|
||||
export type FeeChoices = {
|
||||
[feeLevels.low]: [number, number];
|
||||
[feeLevels.mid]: [number, number];
|
||||
[feeLevels.high]: [number, number];
|
||||
};
|
||||
|
||||
export const feeLevels = {
|
||||
low: 'low',
|
||||
mid: 'mid',
|
||||
high: 'high',
|
||||
type Props = {
|
||||
stopSending: () => void;
|
||||
value: string;
|
||||
conversion: number;
|
||||
};
|
||||
|
||||
export const signMethods = {
|
||||
bridge: 'bridge',
|
||||
masterTicket: 'masterTicket',
|
||||
external: 'external',
|
||||
};
|
||||
|
||||
const Send = ({ stopSending, value, conversion }) => {
|
||||
const Send: React.FC<Props> = ({ stopSending, value, conversion }) => {
|
||||
const { error, setError, network, psbt, denomination, shipWallets } =
|
||||
useSettings();
|
||||
const [signing, setSigning] = useState(false);
|
||||
const [denomAmount, setDenomAmount] = useState('0.00');
|
||||
const [satsAmount, setSatsAmount] = useState('0');
|
||||
const [denomAmount, setDenomAmount] = useState(0.0);
|
||||
const [satsAmount, setSatsAmount] = useState(0);
|
||||
const [payee, setPayee] = useState('');
|
||||
const [checkingPatp, setCheckingPatp] = useState(false);
|
||||
const [payeeType, setPayeeType] = useState('');
|
||||
const [payeeType, setPayeeType] = useState<payeeTypes>(payeeTypes.initial);
|
||||
const [ready, setReady] = useState(false);
|
||||
const [validPayee, setValidPayee] = useState(false);
|
||||
const [focusedField, setFocusedField] = useState(focusFields.empty);
|
||||
const [feeChoices, setFeeChoices] = useState({
|
||||
low: [10, 1],
|
||||
mid: [10, 1],
|
||||
high: [10, 1],
|
||||
const [feeChoices, setFeeChoices] = useState<FeeChoices>({
|
||||
[feeLevels.low]: [10, 1],
|
||||
[feeLevels.mid]: [10, 1],
|
||||
[feeLevels.high]: [10, 1],
|
||||
});
|
||||
const [feeValue, setFeeValue] = useState(feeLevels.mid);
|
||||
const [showFeePicker, setShowFeePicker] = useState(false);
|
||||
const [note, setNote] = useState('');
|
||||
const [choosingSignMethod, setChoosingSignMethod] = useState(false);
|
||||
const [signMethod, setSignMethod] = useState(signMethods.bridge);
|
||||
const [signMethod, setSignMethod] = useState<signMethods>(signMethods.bridge);
|
||||
|
||||
const feeDismiss = () => {
|
||||
setShowFeePicker(false);
|
||||
};
|
||||
|
||||
const handleSetSignMethod = (signMethod) => {
|
||||
const handleSetSignMethod = (signMethod: signMethods) => {
|
||||
setSignMethod(signMethod);
|
||||
setChoosingSignMethod(false);
|
||||
};
|
||||
|
||||
const checkPayee = (e) => {
|
||||
const checkPayee = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setError('');
|
||||
|
||||
const validPatPCommand = (validPatP) => {
|
||||
const validPatPCommand = (validPatP: string) => {
|
||||
let command = { 'check-payee': validPatP };
|
||||
api.btcWalletCommand(command);
|
||||
setTimeout(() => {
|
||||
setCheckingPatp(false);
|
||||
}, 5000);
|
||||
setCheckingPatp(true);
|
||||
setPayeeType('ship');
|
||||
setPayeeType(payeeTypes.ship);
|
||||
setPayee(validPatP);
|
||||
};
|
||||
|
||||
@ -96,13 +114,13 @@ const Send = ({ stopSending, value, conversion }) => {
|
||||
setPayee(payeeReceived);
|
||||
setReady(true);
|
||||
setCheckingPatp(false);
|
||||
setPayeeType('address');
|
||||
setPayeeType(payeeTypes.address);
|
||||
setValidPayee(true);
|
||||
} else {
|
||||
setPayee(payeeReceived);
|
||||
setReady(false);
|
||||
setCheckingPatp(false);
|
||||
setPayeeType('');
|
||||
setPayeeType(payeeTypes.initial);
|
||||
setValidPayee(false);
|
||||
}
|
||||
};
|
||||
@ -112,22 +130,22 @@ const Send = ({ stopSending, value, conversion }) => {
|
||||
};
|
||||
|
||||
const initPayment = () => {
|
||||
if (payeeType === 'ship') {
|
||||
if (payeeType === payeeTypes.ship) {
|
||||
let command = {
|
||||
'init-payment': {
|
||||
payee,
|
||||
value: parseInt(satsAmount),
|
||||
value: satsAmount,
|
||||
feyb: feeChoices[feeValue][1],
|
||||
note: note || null,
|
||||
},
|
||||
};
|
||||
|
||||
api.btcWalletCommand(command).then(() => setSigning(true));
|
||||
} else if (payeeType === 'address') {
|
||||
} else if (payeeType === payeeTypes.address) {
|
||||
let command = {
|
||||
'init-payment-external': {
|
||||
address: payee,
|
||||
value: parseInt(satsAmount),
|
||||
value: satsAmount,
|
||||
feyb: 1,
|
||||
note: note || null,
|
||||
},
|
||||
@ -146,9 +164,9 @@ const Send = ({ stopSending, value, conversion }) => {
|
||||
// let mid = Math.floor(estimates.length / 2);
|
||||
// let high = estimates.length - 1;
|
||||
setFeeChoices({
|
||||
high: [30, n.estimates[30]['sat_per_vbyte']],
|
||||
mid: [180, n.estimates[180]['sat_per_vbyte']],
|
||||
low: [360, n.estimates[360]['sat_per_vbyte']],
|
||||
[feeLevels.high]: [30, n.estimates[30]['sat_per_vbyte']],
|
||||
[feeLevels.mid]: [180, n.estimates[180]['sat_per_vbyte']],
|
||||
[feeLevels.low]: [360, n.estimates[360]['sat_per_vbyte']],
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -175,7 +193,7 @@ const Send = ({ stopSending, value, conversion }) => {
|
||||
payeeColor = 'green';
|
||||
payeeBorder = 'green';
|
||||
payeeBg = 'veryLightGreen';
|
||||
} else if (!focusedField === focusFields.payee && validPayee) {
|
||||
} else if (focusedField !== focusFields.payee && validPayee) {
|
||||
payeeColor = 'blue';
|
||||
payeeBorder = 'white';
|
||||
payeeBg = 'white';
|
||||
@ -184,17 +202,17 @@ const Send = ({ stopSending, value, conversion }) => {
|
||||
payeeBorder = 'red';
|
||||
payeeBg = 'veryLightRed';
|
||||
} else if (
|
||||
focusedField === 'payee' &&
|
||||
focusedField === focusFields.payee &&
|
||||
!validPayee &&
|
||||
!checkingPatp &&
|
||||
payeeType === 'ship'
|
||||
payeeType === payeeTypes.ship
|
||||
) {
|
||||
payeeColor = 'red';
|
||||
payeeBorder = 'red';
|
||||
payeeBg = 'veryLightRed';
|
||||
}
|
||||
|
||||
const signReady = ready && parseInt(satsAmount) > 0 && !signing;
|
||||
const signReady = ready && satsAmount > 0 && !signing;
|
||||
|
||||
let invoice = null;
|
||||
|
||||
@ -286,20 +304,16 @@ const Send = ({ stopSending, value, conversion }) => {
|
||||
value={payee}
|
||||
fontFamily="mono"
|
||||
disabled={signing}
|
||||
onChange={(e) => checkPayee(e)}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
checkPayee(e)
|
||||
}
|
||||
/>
|
||||
</Row>
|
||||
{error && (
|
||||
<Row alignItems="center" justifyContent="space-between">
|
||||
{/* yes this is a hack */}
|
||||
<Box width="calc(40% - 30px)" />
|
||||
<Error
|
||||
error={error}
|
||||
fontSize="14px"
|
||||
ml={2}
|
||||
mt={2}
|
||||
width="100%"
|
||||
/>
|
||||
<Error error={error} fontSize="14px" />
|
||||
</Row>
|
||||
)}
|
||||
<Row alignItems="center" mt={4} justifyContent="space-between">
|
||||
@ -321,8 +335,8 @@ const Send = ({ stopSending, value, conversion }) => {
|
||||
}
|
||||
disabled={signing}
|
||||
value={denomAmount}
|
||||
onChange={(e) => {
|
||||
setDenomAmount(e.target.value);
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setDenomAmount(parseFloat(e.target.value));
|
||||
setSatsAmount(
|
||||
Math.round(
|
||||
(parseFloat(e.target.value) / conversion) * 100000000
|
||||
@ -352,11 +366,11 @@ const Send = ({ stopSending, value, conversion }) => {
|
||||
}
|
||||
disabled={signing}
|
||||
value={satsAmount}
|
||||
onChange={(e) => {
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setDenomAmount(
|
||||
parseFloat(e.target.value) * (conversion / 100000000)
|
||||
);
|
||||
setSatsAmount(e.target.value);
|
||||
setSatsAmount(parseInt(e.target.value, 10));
|
||||
}}
|
||||
/>
|
||||
<Text color="lightGray" fontSize={1} ml={3}>
|
||||
@ -431,7 +445,7 @@ const Send = ({ stopSending, value, conversion }) => {
|
||||
}
|
||||
disabled={signing}
|
||||
value={note}
|
||||
onChange={(e) => {
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setNote(e.target.value);
|
||||
}}
|
||||
/>
|
||||
@ -444,11 +458,7 @@ const Send = ({ stopSending, value, conversion }) => {
|
||||
justifyContent="flex-end"
|
||||
>
|
||||
{!(signing && !error) ? null : (
|
||||
<LoadingSpinner
|
||||
mr={2}
|
||||
background="midOrange"
|
||||
foreground="orange"
|
||||
/>
|
||||
<LoadingSpinner background="midOrange" foreground="orange" />
|
||||
)}
|
||||
<Signer
|
||||
signReady={signReady}
|
||||
@ -464,7 +474,7 @@ const Send = ({ stopSending, value, conversion }) => {
|
||||
fontWeight="bold"
|
||||
borderRadius="24px"
|
||||
height="48px"
|
||||
onClick={() => toggleSignMethod(choosingSignMethod)}
|
||||
onClick={() => toggleSignMethod()}
|
||||
color={signReady ? 'white' : 'lighterGray'}
|
||||
backgroundColor={
|
||||
signReady ? 'rgba(33, 157, 255, 0.2)' : 'veryLightGray'
|
||||
@ -479,7 +489,7 @@ const Send = ({ stopSending, value, conversion }) => {
|
||||
/>
|
||||
</Button>
|
||||
</Row>
|
||||
{signMethod === signMethod.masterTicket && (
|
||||
{signMethod === signMethods.masterTicket && (
|
||||
<Row mt={4} alignItems="center">
|
||||
<Icon icon="Info" color="yellow" height={4} width={4} />
|
||||
<Text fontSize="14px" fontWeight="regular" color="gray" ml={2}>
|
@ -1,9 +1,15 @@
|
||||
import React from 'react';
|
||||
import { Icon, Row, Col, Center, Text } from '@tlon/indigo-react';
|
||||
import { satsToCurrency } from '../../lib/util.js';
|
||||
import { satsToCurrency } from '../../lib/util';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
|
||||
const Sent = ({ payee, stopSending, satsAmount }) => {
|
||||
type Props = {
|
||||
payee: string;
|
||||
stopSending: () => void;
|
||||
satsAmount: number;
|
||||
};
|
||||
|
||||
const Sent: React.FC<Props> = ({ payee, stopSending, satsAmount }) => {
|
||||
const { denomination, currencyRates } = useSettings();
|
||||
return (
|
||||
<Col
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Box, Button, Icon, Row } from '@tlon/indigo-react';
|
||||
import { signMethods } from './send';
|
||||
import { signMethods } from './Send';
|
||||
|
||||
const signMethodLabels = {
|
||||
bridge: 'Sign with Bridge',
|
||||
@ -8,7 +8,15 @@ const signMethodLabels = {
|
||||
external: 'Sign Externally (PSBT)',
|
||||
};
|
||||
|
||||
const Signer = ({
|
||||
type Props = {
|
||||
signReady: boolean;
|
||||
initPayment: () => void;
|
||||
choosingSignMethod: boolean;
|
||||
signMethod: signMethods;
|
||||
setSignMethod: (arg: signMethods) => void;
|
||||
};
|
||||
|
||||
const Signer: React.FC<Props> = ({
|
||||
signReady,
|
||||
initPayment,
|
||||
choosingSignMethod,
|
||||
@ -24,13 +32,15 @@ const Signer = ({
|
||||
backgroundColor="transparent"
|
||||
fontWeight="bold"
|
||||
cursor="pointer"
|
||||
color={signMethod === signMethods[method] ? 'blue' : 'lightBlue'}
|
||||
color={
|
||||
signMethod === (signMethods as any)[method] ? 'blue' : 'lightBlue'
|
||||
}
|
||||
height="48px"
|
||||
onClick={() => setSignMethod(signMethods[method])}
|
||||
onClick={() => setSignMethod((signMethods as any)[method])}
|
||||
>
|
||||
{signMethodLabels[method]}
|
||||
{(signMethodLabels as any)[method]}
|
||||
</Button>
|
||||
{signMethod === signMethods[method] && (
|
||||
{signMethod === (signMethods as any)[method] && (
|
||||
<Button
|
||||
borderRadius="24px"
|
||||
width="24px"
|
||||
@ -61,7 +71,7 @@ const Signer = ({
|
||||
border="none"
|
||||
style={{ cursor: signReady ? 'pointer' : 'default' }}
|
||||
>
|
||||
{signMethodLabels[signMethod]}
|
||||
{(signMethodLabels as any)[signMethod]}
|
||||
</Button>
|
||||
);
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Row, Text, Button, Col } from '@tlon/indigo-react';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
import { api } from '../../api';
|
||||
import { useSettings } from '../hooks/useSettings';
|
||||
import { api } from '../lib/api';
|
||||
|
||||
const Settings = () => {
|
||||
const { wallet, provider } = useSettings();
|
@ -2,11 +2,11 @@ import React, { memo } from 'react';
|
||||
import { sigil, reactRenderer } from '@tlon/sigil-js';
|
||||
import { Box } from '@tlon/indigo-react';
|
||||
|
||||
export const foregroundFromBackground = (background) => {
|
||||
export const foregroundFromBackground = (background: string) => {
|
||||
const rgb = {
|
||||
r: parseInt(background.slice(1, 3), 16),
|
||||
g: parseInt(background.slice(3, 5), 16),
|
||||
b: parseInt(background.slice(5, 7), 16)
|
||||
b: parseInt(background.slice(5, 7), 16),
|
||||
};
|
||||
const brightness = (299 * rgb.r + 587 * rgb.g + 114 * rgb.b) / 1000;
|
||||
const whiteBrightness = 255;
|
||||
@ -14,7 +14,19 @@ export const foregroundFromBackground = (background) => {
|
||||
return whiteBrightness - brightness < 50 ? 'black' : 'white';
|
||||
};
|
||||
|
||||
export const Sigil = memo(
|
||||
type Props = {
|
||||
classes?: string;
|
||||
color: string;
|
||||
foreground?: string;
|
||||
ship: string;
|
||||
size: number;
|
||||
svgClass?: string;
|
||||
icon?: boolean;
|
||||
padding?: number;
|
||||
display?: string;
|
||||
};
|
||||
|
||||
const Sigil: React.FC<Props> = memo(
|
||||
({
|
||||
classes = '',
|
||||
color,
|
||||
@ -24,7 +36,7 @@ export const Sigil = memo(
|
||||
svgClass = '',
|
||||
icon = false,
|
||||
padding = 0,
|
||||
display = 'inline-block'
|
||||
display = 'inline-block',
|
||||
}) => {
|
||||
const innerSize = Number(size) - 2 * padding;
|
||||
const paddingPx = `${padding}px`;
|
||||
@ -55,7 +67,7 @@ export const Sigil = memo(
|
||||
size: innerSize,
|
||||
icon,
|
||||
colors: [color, foregroundColor],
|
||||
class: svgClass
|
||||
class: svgClass,
|
||||
})}
|
||||
</Box>
|
||||
);
|
@ -1,10 +1,10 @@
|
||||
import React from 'react';
|
||||
import { Box } from '@tlon/indigo-react';
|
||||
import WalletModal from './walletModal.js';
|
||||
import ProviderModal from './providerModal.js';
|
||||
import { useSettings } from '../../hooks/useSettings.js';
|
||||
import WalletModal from './WalletModal';
|
||||
import ProviderModal from './ProviderModal';
|
||||
import { useSettings } from '../hooks/useSettings';
|
||||
|
||||
const StartupModal = () => {
|
||||
const StartupModal: React.FC = () => {
|
||||
const { wallet, provider } = useSettings();
|
||||
let modal = null;
|
||||
|
@ -1,23 +1,28 @@
|
||||
import React from 'react';
|
||||
import { Box, Row, Text, Col } from '@tlon/indigo-react';
|
||||
import _ from 'lodash';
|
||||
import TxAction from './tx-action.js';
|
||||
import TxCounterparty from './tx-counterparty.js';
|
||||
import { satsToCurrency } from '../../lib/util.js';
|
||||
import { useSettings } from '../../hooks/useSettings.js';
|
||||
import TxAction from './TxAction';
|
||||
import TxCounterparty from './TxCounterparty';
|
||||
import { satsToCurrency } from '../../lib/util';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
import { Transaction as TransactionType } from '../../types';
|
||||
|
||||
const Transaction = ({ tx }) => {
|
||||
const Transaction = ({ tx }: { tx: TransactionType }) => {
|
||||
const { denomination, currencyRates } = useSettings();
|
||||
const pending = !tx.recvd;
|
||||
|
||||
let weSent = _.find(tx.inputs, (input) => {
|
||||
return input.ship === window.ship;
|
||||
return input.ship === (window as any).ship;
|
||||
});
|
||||
let weRecv = tx.outputs.every((output) => {
|
||||
return output.ship === window.ship;
|
||||
return output.ship === (window as any).ship;
|
||||
});
|
||||
|
||||
let action = weRecv ? 'recv' : weSent ? 'sent' : 'recv';
|
||||
let action: 'sent' | 'recv' | 'fail' = weRecv
|
||||
? 'recv'
|
||||
: weSent
|
||||
? 'sent'
|
||||
: 'recv';
|
||||
|
||||
let counterShip = null;
|
||||
let counterAddress = null;
|
||||
@ -26,7 +31,7 @@ const Transaction = ({ tx }) => {
|
||||
|
||||
if (action === 'sent') {
|
||||
let counter = _.find(tx.outputs, (output) => {
|
||||
return output.ship !== window.ship;
|
||||
return output.ship !== (window as any).ship;
|
||||
});
|
||||
counterShip = _.get(counter, 'ship', null);
|
||||
counterAddress = _.get(counter, 'val.address', null);
|
||||
@ -36,7 +41,7 @@ const Transaction = ({ tx }) => {
|
||||
value = _.reduce(
|
||||
tx.outputs,
|
||||
(sum, output) => {
|
||||
if (output.ship === window.ship) {
|
||||
if (output.ship === (window as any).ship) {
|
||||
return sum + output.val.value;
|
||||
} else {
|
||||
return sum;
|
||||
@ -48,14 +53,14 @@ const Transaction = ({ tx }) => {
|
||||
if (weSent && weRecv) {
|
||||
counterAddress = _.get(
|
||||
_.find(tx.inputs, (input) => {
|
||||
return input.ship === window.ship;
|
||||
return input.ship === (window as any).ship;
|
||||
}),
|
||||
'val.address',
|
||||
null
|
||||
);
|
||||
} else {
|
||||
let counter = _.find(tx.inputs, (input) => {
|
||||
return input.ship !== window.ship;
|
||||
return input.ship !== (window as any).ship;
|
||||
});
|
||||
counterShip = _.get(counter, 'ship', null);
|
||||
counterAddress = _.get(counter, 'val.address', null);
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Box, Text, Col } from '@tlon/indigo-react';
|
||||
import Transaction from './transaction.js';
|
||||
import { useSettings } from '../../hooks/useSettings.js';
|
||||
import Transaction from './Transaction';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
|
||||
const Transactions = () => {
|
||||
const { history } = useSettings();
|
@ -2,7 +2,13 @@ import React from 'react';
|
||||
import { Box, Icon, Row, Text, LoadingSpinner } from '@tlon/indigo-react';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
|
||||
const TxAction = ({ action, pending, txid }) => {
|
||||
type Props = {
|
||||
action: 'sent' | 'recv' | 'fail';
|
||||
pending: boolean;
|
||||
txid: string;
|
||||
};
|
||||
|
||||
const TxAction: React.FC<Props> = ({ action, pending, txid }) => {
|
||||
const { network } = useSettings();
|
||||
const leftIcon =
|
||||
action === 'sent'
|
@ -1,8 +1,13 @@
|
||||
import React from 'react';
|
||||
import { Box, Icon, Row, Text } from '@tlon/indigo-react';
|
||||
import { Sigil } from './sigil.js';
|
||||
import Sigil from '../Sigil';
|
||||
|
||||
const TxCounterparty = ({ ship, address }) => {
|
||||
type Props = {
|
||||
ship: string;
|
||||
address: string;
|
||||
};
|
||||
|
||||
const TxCounterparty: React.FC<Props> = ({ ship, address }) => {
|
||||
const icon = ship ? (
|
||||
<Sigil ship={ship} size={24} color="black" classes={''} icon padding={5} />
|
||||
) : (
|
@ -10,10 +10,11 @@ import {
|
||||
} from '@tlon/indigo-react';
|
||||
import { patp2dec, isValidPatq } from 'urbit-ob';
|
||||
import * as kg from 'urbit-key-generation';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
import { api } from '../../api';
|
||||
import { useSettings } from '../hooks/useSettings';
|
||||
import { api } from '../lib/api';
|
||||
import { UrbitWallet } from '../types';
|
||||
|
||||
const WalletModal = () => {
|
||||
const WalletModal: React.FC = () => {
|
||||
const { network } = useSettings();
|
||||
const [mode, setMode] = useState('xpub');
|
||||
const [masterTicket, setMasterTicket] = useState('');
|
||||
@ -24,7 +25,9 @@ const WalletModal = () => {
|
||||
const [confirmingMasterTicket, setConfirmingMasterTicket] = useState(false);
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
const checkTicket = ({ target: { value } }) => {
|
||||
const checkTicket = ({
|
||||
target: { value },
|
||||
}: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// TODO: port over bridge ticket validation logic
|
||||
if (confirmingMasterTicket) {
|
||||
setConfirmedMasterTicket(value);
|
||||
@ -35,13 +38,24 @@ const WalletModal = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const checkXPub = ({ target: { value: xpubGiven } }) => {
|
||||
const checkXPub = ({
|
||||
target: { value: xpubGiven },
|
||||
}: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setXpub(xpubGiven);
|
||||
setReadyToSubmit(xpubGiven.length > 0);
|
||||
};
|
||||
|
||||
const submitXPub = (givenXpub) => {
|
||||
const command = {
|
||||
const submitXPub = (givenXpub: string) => {
|
||||
type AddWalletCommand = {
|
||||
'add-wallet': {
|
||||
xpub: string;
|
||||
fprint: number[];
|
||||
'scan-to': number | null;
|
||||
'max-gap': number;
|
||||
confs: number;
|
||||
};
|
||||
};
|
||||
const command: AddWalletCommand = {
|
||||
'add-wallet': {
|
||||
xpub: givenXpub,
|
||||
fprint: [4, 0],
|
||||
@ -54,12 +68,12 @@ const WalletModal = () => {
|
||||
setProcessingSubmission(true);
|
||||
};
|
||||
|
||||
const submitMasterTicket = (ticket) => {
|
||||
const submitMasterTicket = (ticket: string) => {
|
||||
setProcessingSubmission(true);
|
||||
kg.generateWallet({
|
||||
ticket,
|
||||
ship: parseInt(patp2dec('~' + window.ship)),
|
||||
}).then((urbitWallet) => {
|
||||
ship: parseInt(patp2dec('~' + (window as any).ship)),
|
||||
}).then((urbitWallet: UrbitWallet) => {
|
||||
const { xpub: xpubFromWallet } =
|
||||
network === 'testnet'
|
||||
? urbitWallet.bitcoinTestnet.keys
|
||||
@ -117,11 +131,13 @@ const WalletModal = () => {
|
||||
fontSize="14px"
|
||||
type="password"
|
||||
name="masterTicket"
|
||||
obscure={(value) => value.replace(/[^~-]+/g, '••••••')}
|
||||
obscure={(value: string) => value.replace(/[^~-]+/g, '••••••')}
|
||||
placeholder="••••••-••••••-••••••-••••••"
|
||||
autoCapitalize="none"
|
||||
autoCorrect="off"
|
||||
onChange={(e) => checkTicket(e)}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
checkTicket(e)
|
||||
}
|
||||
/>
|
||||
{!inputDisabled ? null : <LoadingSpinner />}
|
||||
</Row>
|
||||
@ -210,7 +226,7 @@ const WalletModal = () => {
|
||||
name="xpub"
|
||||
autoCapitalize="none"
|
||||
autoCorrect="off"
|
||||
onChange={(e) => checkXPub(e)}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => checkXPub(e)}
|
||||
mr={1}
|
||||
/>
|
||||
{!inputDisabled ? null : <LoadingSpinner />}
|
@ -1,12 +1,12 @@
|
||||
import React from 'react';
|
||||
import { Box, Text, Button, Col, Anchor } from '@tlon/indigo-react';
|
||||
import { api } from '../../api';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
import { api } from '../lib/api';
|
||||
import { useSettings } from '../hooks/useSettings';
|
||||
|
||||
const Warning = () => {
|
||||
const { setWarning } = useSettings();
|
||||
const { setShowWarning } = useSettings();
|
||||
const understand = () => {
|
||||
setWarning(false);
|
||||
setShowWarning(false);
|
||||
let removeWarning = {
|
||||
'put-entry': {
|
||||
value: false,
|
@ -1,19 +1,76 @@
|
||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||
import _ from 'lodash';
|
||||
import { api } from '../api';
|
||||
import { api } from '../lib/api';
|
||||
import { mapDenominationToSymbol, reduceHistory } from '../lib/util';
|
||||
import {
|
||||
CurrencyRate,
|
||||
Denomination,
|
||||
Network,
|
||||
Provider,
|
||||
ProviderPerms,
|
||||
ScanProgress,
|
||||
ShipWallets,
|
||||
Transaction,
|
||||
TxidType,
|
||||
} from '../types';
|
||||
|
||||
export const SettingsContext = createContext({
|
||||
type SettingsContextType = {
|
||||
network: Network;
|
||||
setNetwork: React.Dispatch<React.SetStateAction<Network>>;
|
||||
loadedBtc: boolean;
|
||||
setLoadedBtc: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
loadedSettings: boolean;
|
||||
setLoadedSettings: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
loaded: boolean;
|
||||
setLoaded: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
providerPerms: ProviderPerms;
|
||||
setProviderPerms: React.Dispatch<React.SetStateAction<ProviderPerms>>;
|
||||
shipWallets: ShipWallets;
|
||||
setShipWallets: React.Dispatch<React.SetStateAction<ShipWallets>>;
|
||||
provider: Provider;
|
||||
setProvider: React.Dispatch<React.SetStateAction<string | null>>;
|
||||
wallet: string | null;
|
||||
setWallet: React.Dispatch<React.SetStateAction<string | null>>;
|
||||
confirmedBalance: number;
|
||||
setConfirmedBalance: React.Dispatch<React.SetStateAction<number>>;
|
||||
unconfirmedBalance: number;
|
||||
setUnconfirmedBalance: React.Dispatch<React.SetStateAction<number>>;
|
||||
btcState: any;
|
||||
setBtcState: React.Dispatch<React.SetStateAction<any>>;
|
||||
history: Transaction[];
|
||||
setHistory: React.Dispatch<React.SetStateAction<Transaction[]>>;
|
||||
fee: number;
|
||||
setFee: React.Dispatch<React.SetStateAction<number>>;
|
||||
psbt: string;
|
||||
setPsbt: React.Dispatch<React.SetStateAction<string>>;
|
||||
address: string | null;
|
||||
setAddress: React.Dispatch<React.SetStateAction<string | null>>;
|
||||
currencyRates: CurrencyRate;
|
||||
setCurrencyRates: React.Dispatch<React.SetStateAction<{}>>;
|
||||
denomination: Denomination;
|
||||
setDenomination: React.Dispatch<React.SetStateAction<Denomination>>;
|
||||
showWarning: boolean;
|
||||
setShowWarning: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
error: string;
|
||||
setError: React.Dispatch<React.SetStateAction<string>>;
|
||||
broadcastSuccess: boolean;
|
||||
setBroadcastSuccess: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
scanProgress: ScanProgress;
|
||||
setScanProgress: React.Dispatch<React.SetStateAction<ScanProgress>>;
|
||||
};
|
||||
|
||||
export const SettingsContext = createContext<SettingsContextType>({
|
||||
network: 'bitcoin',
|
||||
setNetwork: () => {},
|
||||
loadedBtc: false,
|
||||
setLoadedBtc: () => {},
|
||||
loadedSettings: false,
|
||||
setLoadedSettings: () => {},
|
||||
loaded: false,
|
||||
setLoaded: () => {},
|
||||
providerPerms: {},
|
||||
providerPerms: { provider: '', permitted: false },
|
||||
setProviderPerms: () => {},
|
||||
shipWallets: {},
|
||||
shipWallets: { payee: '', hasWallet: false },
|
||||
setShipWallets: () => {},
|
||||
provider: null,
|
||||
setProvider: () => {},
|
||||
@ -36,7 +93,9 @@ export const SettingsContext = createContext({
|
||||
currencyRates: {
|
||||
BTC: { last: 1, symbol: 'BTC' },
|
||||
},
|
||||
setCurrencyRates: () => {},
|
||||
denomination: 'BTC',
|
||||
setDenomination: () => {},
|
||||
showWarning: true,
|
||||
setShowWarning: () => {},
|
||||
error: '',
|
||||
@ -47,14 +106,24 @@ export const SettingsContext = createContext({
|
||||
setScanProgress: () => {},
|
||||
});
|
||||
|
||||
export const SettingsProvider = ({ channel, children }) => {
|
||||
const [network, setNetwork] = useState('bitcoin');
|
||||
type Props = {
|
||||
channel: { setOnChannelError: (arg: () => void) => void };
|
||||
};
|
||||
|
||||
export const SettingsProvider: React.FC<Props> = ({ channel, children }) => {
|
||||
const [network, setNetwork] = useState<Network>('bitcoin');
|
||||
const [channelData, setChannelData] = useState(null);
|
||||
const [loadedBtc, setLoadedBtc] = useState(false);
|
||||
const [loadedSettings, setLoadedSettings] = useState(false);
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [providerPerms, setProviderPerms] = useState({});
|
||||
const [shipWallets, setShipWallets] = useState({});
|
||||
const [providerPerms, setProviderPerms] = useState<ProviderPerms>({
|
||||
provider: '',
|
||||
permitted: false,
|
||||
});
|
||||
const [shipWallets, setShipWallets] = useState<ShipWallets>({
|
||||
payee: '',
|
||||
hasWallet: false,
|
||||
});
|
||||
const [provider, setProvider] = useState(null);
|
||||
const [wallet, setWallet] = useState(null);
|
||||
const [confirmedBalance, setConfirmedBalance] = useState(0);
|
||||
@ -67,7 +136,7 @@ export const SettingsProvider = ({ channel, children }) => {
|
||||
const [currencyRates, setCurrencyRates] = useState({
|
||||
BTC: { last: 1, symbol: 'BTC' },
|
||||
});
|
||||
const [denomination, setDenomination] = useState('BTC');
|
||||
const [denomination, setDenomination] = useState<Denomination>('BTC');
|
||||
const [showWarning, setShowWarning] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const [broadcastSuccess, setBroadcastSuccess] = useState(false);
|
||||
@ -78,11 +147,11 @@ export const SettingsProvider = ({ channel, children }) => {
|
||||
|
||||
const { Provider } = SettingsContext;
|
||||
|
||||
const success = (event) => {
|
||||
const success = (event: any) => {
|
||||
console.log({ event });
|
||||
setChannelData(event);
|
||||
};
|
||||
const fail = (error) => console.log({ error });
|
||||
const fail = (error: any) => console.log({ error });
|
||||
|
||||
const initializeBtcWallet = () => {
|
||||
api.bind('/all', 'PUT', api.ship, 'btc-wallet', success, fail);
|
||||
@ -123,7 +192,7 @@ export const SettingsProvider = ({ channel, children }) => {
|
||||
fetch('https://blockchain.info/ticker')
|
||||
.then((res) => res.json())
|
||||
.then((n) => {
|
||||
const newCurrencyRates = currencyRates;
|
||||
const newCurrencyRates: any = currencyRates;
|
||||
for (let c in n) {
|
||||
newCurrencyRates[c] = n[c];
|
||||
newCurrencyRates[c].symbol = mapDenominationToSymbol(c);
|
||||
@ -141,13 +210,13 @@ export const SettingsProvider = ({ channel, children }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleNewTx = (newTx) => {
|
||||
const handleNewTx = (newTx: Transaction) => {
|
||||
const { txid, recvd } = newTx;
|
||||
let old = _.findIndex(history, (h) => {
|
||||
let old = _.findIndex(history, (h: Transaction) => {
|
||||
return h.txid.dat === txid.dat && h.txid.wid === txid.wid;
|
||||
});
|
||||
if (old !== -1) {
|
||||
const newHistory = history.filter((o, i) => i !== old);
|
||||
const newHistory = history.filter((_, i) => i !== old);
|
||||
setHistory(newHistory);
|
||||
}
|
||||
if (recvd === null && old === -1) {
|
||||
@ -156,7 +225,7 @@ export const SettingsProvider = ({ channel, children }) => {
|
||||
} else if (recvd !== null && old === -1) {
|
||||
// we expect history to have null recvd values first, and the rest in
|
||||
// descending order
|
||||
let insertionIndex = _.findIndex(history, (h) => {
|
||||
let insertionIndex = _.findIndex(history, (h: Transaction) => {
|
||||
return h.recvd < recvd && h.recvd !== null;
|
||||
});
|
||||
const newHistory = history.map((o, i) =>
|
||||
@ -166,8 +235,8 @@ export const SettingsProvider = ({ channel, children }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancelTx = ({ wid, dat }) => {
|
||||
let entryIndex = _.findIndex(history, (h) => {
|
||||
const handleCancelTx = ({ wid, dat }: TxidType) => {
|
||||
let entryIndex = _.findIndex(history, (h: Transaction) => {
|
||||
return wid === h.txid.wid && dat === h.txid.dat;
|
||||
});
|
||||
if (entryIndex > -1) {
|
||||
@ -221,14 +290,14 @@ export const SettingsProvider = ({ channel, children }) => {
|
||||
handleNewTx(newTx);
|
||||
}
|
||||
if (providerStatus) {
|
||||
let newProviderPerms = providerPerms;
|
||||
let newProviderPerms: any = providerPerms;
|
||||
for (let c in providerStatus) {
|
||||
newProviderPerms[c] = providerStatus[c];
|
||||
}
|
||||
setProviderPerms(newProviderPerms);
|
||||
}
|
||||
if (checkPayee) {
|
||||
let newShipWallets = shipWallets;
|
||||
let newShipWallets: any = shipWallets;
|
||||
|
||||
for (let c in checkPayee) {
|
||||
newShipWallets[c] = checkPayee[c];
|
@ -1,17 +1,15 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Root from './js/components/root.js';
|
||||
import { api } from './js/api.js';
|
||||
import { SettingsProvider } from './js/hooks/useSettings';
|
||||
import { api } from './lib/api';
|
||||
import { SettingsProvider } from './hooks/useSettings';
|
||||
import App from './App';
|
||||
|
||||
import './css/indigo-static.css';
|
||||
import './css/fonts.css';
|
||||
import './css/custom.css';
|
||||
|
||||
// rebuild x3
|
||||
|
||||
const channel = new window.channel();
|
||||
api.setChannel(window.ship, channel);
|
||||
const channel = new (window as any).channel();
|
||||
api.setChannel((window as any).ship, channel);
|
||||
|
||||
if (module.hot) {
|
||||
module.hot.accept();
|
||||
@ -19,7 +17,7 @@ if (module.hot) {
|
||||
|
||||
ReactDOM.render(
|
||||
<SettingsProvider channel={channel}>
|
||||
<Root />
|
||||
<App />
|
||||
</SettingsProvider>,
|
||||
document.querySelectorAll('#root')[0]
|
||||
);
|
@ -1,37 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Text } from '@tlon/indigo-react';
|
||||
|
||||
const errorToString = (error) => {
|
||||
if (error === 'cant-pay-ourselves') {
|
||||
return 'Cannot pay ourselves';
|
||||
}
|
||||
if (error === 'no-comets') {
|
||||
return 'Cannot pay comets';
|
||||
}
|
||||
if (error === 'no-dust') {
|
||||
return 'Cannot send dust';
|
||||
}
|
||||
if (error === 'tx-being-signed') {
|
||||
return 'Cannot pay when transaction is being signed';
|
||||
}
|
||||
if (error === 'insufficient-balance') {
|
||||
return 'Insufficient confirmed balance';
|
||||
}
|
||||
if (error === 'broadcast-fail') {
|
||||
return 'Transaction broadcast failed';
|
||||
}
|
||||
if (error === 'invalid-master-ticket') {
|
||||
return 'Invalid master ticket';
|
||||
}
|
||||
if (error === 'invalid-signed') {
|
||||
return 'Invalid signed bitcoin transaction';
|
||||
}
|
||||
};
|
||||
|
||||
const Error = ({ error, ...rest }) => (
|
||||
<Text color="red" {...rest}>
|
||||
{errorToString(error)}
|
||||
</Text>
|
||||
);
|
||||
|
||||
export default Error;
|
@ -1,73 +0,0 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Text,
|
||||
Col,
|
||||
StatelessRadioButtonField as RadioButton,
|
||||
Label,
|
||||
} from '@tlon/indigo-react';
|
||||
import { feeLevels } from './send';
|
||||
|
||||
const FeePicker = ({ feeChoices, feeValue, setFeeValue, feeDismiss }) => {
|
||||
const select = (which) => {
|
||||
setFeeValue(feeLevels[which]);
|
||||
feeDismiss();
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
position="absolute"
|
||||
p={4}
|
||||
border="1px solid green"
|
||||
zIndex={10}
|
||||
backgroundColor="white"
|
||||
borderRadius={3}
|
||||
>
|
||||
<Text fontSize={1} color="black" fontWeight="bold" mb={4}>
|
||||
Transaction Speed
|
||||
</Text>
|
||||
<Col mt={4}>
|
||||
<RadioButton
|
||||
name="feeRadio"
|
||||
selected={feeValue === feeLevels.low}
|
||||
p="2"
|
||||
onChange={() => {
|
||||
select(feeLevels.low);
|
||||
}}
|
||||
>
|
||||
<Label fontSize="14px">
|
||||
Slow: {feeChoices.low[1]} sats/vbyte ~{feeChoices.low[0]}m
|
||||
</Label>
|
||||
</RadioButton>
|
||||
|
||||
<RadioButton
|
||||
name="feeRadio"
|
||||
selected={feeValue === feeLevels.mid}
|
||||
p="2"
|
||||
onChange={() => {
|
||||
select(feeLevels.low);
|
||||
}}
|
||||
>
|
||||
<Label fontSize="14px">
|
||||
Normal: {feeChoices.mid[1]} sats/vbyte ~{feeChoices.mid[0]}m
|
||||
</Label>
|
||||
</RadioButton>
|
||||
|
||||
<RadioButton
|
||||
name="feeRadio"
|
||||
selected={feeValue === feeLevels.high}
|
||||
p="2"
|
||||
onChange={() => {
|
||||
select(feeLevels.high);
|
||||
}}
|
||||
>
|
||||
<Label fontSize="14px">
|
||||
Fast: {feeChoices.high[1]} sats/vbyte ~{feeChoices.high[0]}m
|
||||
</Label>
|
||||
</RadioButton>
|
||||
</Col>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeePicker;
|
@ -1,183 +0,0 @@
|
||||
import baseStyled from "styled-components";
|
||||
|
||||
const base = {
|
||||
white: "rgba(255,255,255,1)",
|
||||
black: "rgba(0,0,0,1)",
|
||||
red: "rgba(255,65,54,1)",
|
||||
yellow: "rgba(255,199,0,1)",
|
||||
green: "rgba(0,159,101,1)",
|
||||
blue: "rgba(0,142,255,1)",
|
||||
};
|
||||
|
||||
const scales = {
|
||||
white05: "rgba(255,255,255,0.05)",
|
||||
white10: "rgba(255,255,255,0.1)",
|
||||
white20: "rgba(255,255,255,0.2)",
|
||||
white30: "rgba(255,255,255,0.3)",
|
||||
white40: "rgba(255,255,255,0.4)",
|
||||
white50: "rgba(255,255,255,0.5)",
|
||||
white60: "rgba(255,255,255,0.6)",
|
||||
white70: "rgba(255,255,255,0.7)",
|
||||
white80: "rgba(255,255,255,0.8)",
|
||||
white90: "rgba(255,255,255,0.9)",
|
||||
white100: "rgba(255,255,255,1)",
|
||||
black05: "rgba(0,0,0,0.05)",
|
||||
black10: "rgba(0,0,0,0.1)",
|
||||
black20: "rgba(0,0,0,0.2)",
|
||||
black30: "rgba(0,0,0,0.3)",
|
||||
black40: "rgba(0,0,0,0.4)",
|
||||
black50: "rgba(0,0,0,0.5)",
|
||||
black60: "rgba(0,0,0,0.6)",
|
||||
black70: "rgba(0,0,0,0.7)",
|
||||
black80: "rgba(0,0,0,0.8)",
|
||||
black90: "rgba(0,0,0,0.9)",
|
||||
black100: "rgba(0,0,0,1)",
|
||||
red05: "rgba(255,65,54,0.05)",
|
||||
red10: "rgba(255,65,54,0.1)",
|
||||
red20: "rgba(255,65,54,0.2)",
|
||||
red30: "rgba(255,65,54,0.3)",
|
||||
red40: "rgba(255,65,54,0.4)",
|
||||
red50: "rgba(255,65,54,0.5)",
|
||||
red60: "rgba(255,65,54,0.6)",
|
||||
red70: "rgba(255,65,54,0.7)",
|
||||
red80: "rgba(255,65,54,0.8)",
|
||||
red90: "rgba(255,65,54,0.9)",
|
||||
red100: "rgba(255,65,54,1)",
|
||||
yellow05: "rgba(255,199,0,0.05)",
|
||||
yellow10: "rgba(255,199,0,0.1)",
|
||||
yellow20: "rgba(255,199,0,0.2)",
|
||||
yellow30: "rgba(255,199,0,0.3)",
|
||||
yellow40: "rgba(255,199,0,0.4)",
|
||||
yellow50: "rgba(255,199,0,0.5)",
|
||||
yellow60: "rgba(255,199,0,0.6)",
|
||||
yellow70: "rgba(255,199,0,0.7)",
|
||||
yellow80: "rgba(255,199,0,0.8)",
|
||||
yellow90: "rgba(255,199,0,0.9)",
|
||||
yellow100: "rgba(255,199,0,1)",
|
||||
green05: "rgba(0,159,101,0.05)",
|
||||
green10: "rgba(0,159,101,0.1)",
|
||||
green20: "rgba(0,159,101,0.2)",
|
||||
green30: "rgba(0,159,101,0.3)",
|
||||
green40: "rgba(0,159,101,0.4)",
|
||||
green50: "rgba(0,159,101,0.5)",
|
||||
green60: "rgba(0,159,101,0.6)",
|
||||
green70: "rgba(0,159,101,0.7)",
|
||||
green80: "rgba(0,159,101,0.8)",
|
||||
green90: "rgba(0,159,101,0.9)",
|
||||
green100: "rgba(0,159,101,1)",
|
||||
blue05: "rgba(0,142,255,0.05)",
|
||||
blue10: "rgba(0,142,255,0.1)",
|
||||
blue20: "rgba(0,142,255,0.2)",
|
||||
blue30: "rgba(0,142,255,0.3)",
|
||||
blue40: "rgba(0,142,255,0.4)",
|
||||
blue50: "rgba(0,142,255,0.5)",
|
||||
blue60: "rgba(0,142,255,0.6)",
|
||||
blue70: "rgba(0,142,255,0.7)",
|
||||
blue80: "rgba(0,142,255,0.8)",
|
||||
blue90: "rgba(0,142,255,0.9)",
|
||||
blue100: "rgba(0,142,255,1)",
|
||||
};
|
||||
|
||||
const util = {
|
||||
cyan: "#00FFFF",
|
||||
magenta: "#FF00FF",
|
||||
yellow: "#FFFF00",
|
||||
black: "#000000",
|
||||
gray0: "#333333"
|
||||
};
|
||||
|
||||
const theme = {
|
||||
colors: {
|
||||
white: util.gray0,
|
||||
black: base.white,
|
||||
|
||||
gray: scales.white60,
|
||||
lightGray: scales.white30,
|
||||
washedGray: scales.white05,
|
||||
|
||||
red: base.red,
|
||||
lightRed: scales.red30,
|
||||
washedRed: scales.red05,
|
||||
|
||||
yellow: base.yellow,
|
||||
lightYellow: scales.yellow30,
|
||||
washedYellow: scales.yellow10,
|
||||
|
||||
green: base.green,
|
||||
lightGreen: scales.green30,
|
||||
washedGreen: scales.green10,
|
||||
|
||||
blue: base.blue,
|
||||
lightBlue: scales.blue30,
|
||||
washedBlue: scales.blue10,
|
||||
|
||||
none: "rgba(0,0,0,0)",
|
||||
|
||||
scales: scales,
|
||||
util: util,
|
||||
},
|
||||
fonts: {
|
||||
sans: `"Inter", "Inter UI", -apple-system, BlinkMacSystemFont, 'San Francisco', 'Helvetica Neue', Arial, sans-serif`,
|
||||
mono: `"Source Code Pro", "Roboto mono", "Courier New", monospace`,
|
||||
},
|
||||
// font-size
|
||||
fontSizes: [
|
||||
12, // 0
|
||||
16, // 1
|
||||
24, // 2
|
||||
32, // 3
|
||||
48, // 4
|
||||
64, // 5
|
||||
],
|
||||
// font-weight
|
||||
fontWeights: {
|
||||
thin: 300,
|
||||
regular: 400,
|
||||
bold: 600,
|
||||
},
|
||||
// line-height
|
||||
lineHeights: {
|
||||
min: 1.2,
|
||||
short: 1.333333,
|
||||
regular: 1.5,
|
||||
tall: 1.666666,
|
||||
},
|
||||
// border, border-top, border-right, border-bottom, border-left
|
||||
borders: ["none", "1px solid"],
|
||||
// margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, grid-gap, grid-column-gap, grid-row-gap
|
||||
space: [
|
||||
0, // 0
|
||||
4, // 1
|
||||
8, // 2
|
||||
16, // 3
|
||||
24, // 4
|
||||
32, // 5
|
||||
48, // 6
|
||||
64, // 7
|
||||
96, // 8
|
||||
],
|
||||
// border-radius
|
||||
radii: [
|
||||
0, // 0
|
||||
2, // 1
|
||||
4, // 2
|
||||
8, // 3
|
||||
],
|
||||
// width, height, min-width, max-width, min-height, max-height
|
||||
sizes: [
|
||||
0, // 0
|
||||
4, // 1
|
||||
8, // 2
|
||||
16, // 3
|
||||
24, // 4
|
||||
32, // 5
|
||||
48, // 6
|
||||
64, // 7
|
||||
96, // 8
|
||||
],
|
||||
// z-index
|
||||
zIndices: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
breakpoints: ["550px", "750px", "960px"],
|
||||
};
|
||||
export const styled = baseStyled;
|
||||
export default theme;
|
@ -1,184 +0,0 @@
|
||||
import baseStyled from "styled-components";
|
||||
|
||||
const base = {
|
||||
white: "rgba(255,255,255,1)",
|
||||
black: "rgba(0,0,0,1)",
|
||||
red: "rgba(255,65,54,1)",
|
||||
yellow: "rgba(255,199,0,1)",
|
||||
green: "rgba(0,159,101,1)",
|
||||
blue: "rgba(0,142,255,1)",
|
||||
none: "rgba(0,0,0,0)",
|
||||
};
|
||||
|
||||
const scales = {
|
||||
white10: "rgba(255,255,255,0.1)",
|
||||
white20: "rgba(255,255,255,0.2)",
|
||||
white30: "rgba(255,255,255,0.3)",
|
||||
white40: "rgba(255,255,255,0.4)",
|
||||
white50: "rgba(255,255,255,0.5)",
|
||||
white60: "rgba(255,255,255,0.6)",
|
||||
white70: "rgba(255,255,255,0.7)",
|
||||
white80: "rgba(255,255,255,0.8)",
|
||||
white90: "rgba(255,255,255,0.9)",
|
||||
white100: "rgba(255,255,255,1)",
|
||||
black04: "rgba(0,0,0,0.04)",
|
||||
black10: "rgba(0,0,0,0.1)",
|
||||
black20: "rgba(0,0,0,0.2)",
|
||||
black30: "rgba(0,0,0,0.3)",
|
||||
black40: "rgba(0,0,0,0.4)",
|
||||
black50: "rgba(0,0,0,0.5)",
|
||||
black60: "rgba(0,0,0,0.6)",
|
||||
black70: "rgba(0,0,0,0.7)",
|
||||
black80: "rgba(0,0,0,0.8)",
|
||||
black90: "rgba(0,0,0,0.9)",
|
||||
black100: "rgba(0,0,0,1)",
|
||||
red05: "rgba(255,65,54,0.05)",
|
||||
red10: "rgba(255,65,54,0.1)",
|
||||
red20: "rgba(255,65,54,0.2)",
|
||||
red30: "rgba(255,65,54,0.3)",
|
||||
red40: "rgba(255,65,54,0.4)",
|
||||
red50: "rgba(255,65,54,0.5)",
|
||||
red60: "rgba(255,65,54,0.6)",
|
||||
red70: "rgba(255,65,54,0.7)",
|
||||
red80: "rgba(255,65,54,0.8)",
|
||||
red90: "rgba(255,65,54,0.9)",
|
||||
red100: "rgba(255,65,54,1)",
|
||||
yellow10: "rgba(255,199,0,0.1)",
|
||||
yellow20: "rgba(255,199,0,0.2)",
|
||||
yellow30: "rgba(255,199,0,0.3)",
|
||||
yellow40: "rgba(255,199,0,0.4)",
|
||||
yellow50: "rgba(255,199,0,0.5)",
|
||||
yellow60: "rgba(255,199,0,0.6)",
|
||||
yellow70: "rgba(255,199,0,0.7)",
|
||||
yellow80: "rgba(255,199,0,0.8)",
|
||||
yellow90: "rgba(255,199,0,0.9)",
|
||||
yellow100: "rgba(255,199,0,1)",
|
||||
green05: "rgba(0,159,101,0.05)",
|
||||
green10: "rgba(0,159,101,0.1)",
|
||||
green20: "rgba(0,159,101,0.2)",
|
||||
green30: "rgba(0,159,101,0.3)",
|
||||
green40: "rgba(0,159,101,0.4)",
|
||||
green50: "rgba(0,159,101,0.5)",
|
||||
green60: "rgba(0,159,101,0.6)",
|
||||
green70: "rgba(0,159,101,0.7)",
|
||||
green80: "rgba(0,159,101,0.8)",
|
||||
green90: "rgba(0,159,101,0.9)",
|
||||
green100: "rgba(0,159,101,1)",
|
||||
blue10: "rgba(0,142,255,0.1)",
|
||||
blue20: "rgba(0,142,255,0.2)",
|
||||
blue30: "rgba(0,142,255,0.3)",
|
||||
blue40: "rgba(0,142,255,0.4)",
|
||||
blue50: "rgba(0,142,255,0.5)",
|
||||
blue60: "rgba(0,142,255,0.6)",
|
||||
blue70: "rgba(0,142,255,0.7)",
|
||||
blue80: "rgba(0,142,255,0.8)",
|
||||
blue90: "rgba(0,142,255,0.9)",
|
||||
blue100: "rgba(0,142,255,1)",
|
||||
};
|
||||
|
||||
const theme = {
|
||||
colors: {
|
||||
white: base.white,
|
||||
black: base.black,
|
||||
|
||||
gray: scales.black60,
|
||||
lighterGray: scales.black20,
|
||||
lightGray: scales.black30,
|
||||
washedGray: scales.black10,
|
||||
veryLightGray: scales.black04,
|
||||
|
||||
red: base.red,
|
||||
lightRed: scales.red30,
|
||||
washedRed: scales.red10,
|
||||
veryLightRed: scales.red05,
|
||||
|
||||
yellow: base.yellow,
|
||||
lightYellow: scales.yellow30,
|
||||
washedYellow: scales.yellow10,
|
||||
|
||||
green: base.green,
|
||||
lightGreen: scales.green30,
|
||||
midGreen: scales.green60,
|
||||
washedGreen: scales.green10,
|
||||
veryLightGreen: scales.green05,
|
||||
|
||||
blue: base.blue,
|
||||
lightBlue: scales.blue30,
|
||||
washedBlue: scales.blue10,
|
||||
|
||||
none: "rgba(0,0,0,0)",
|
||||
scales: scales,
|
||||
|
||||
orange: "rgba(255, 153, 0, 1)",
|
||||
midOrange: "rgba(255, 153, 0, 0.2)",
|
||||
lightOrange: "rgba(255, 153, 0, 0.08)",
|
||||
|
||||
sentBlue: "rgba(33,157,255,1)",
|
||||
recvGreen: "rgba(0,159,101,1)",
|
||||
},
|
||||
fonts: {
|
||||
sans: `"Inter", "Inter UI", -apple-system, BlinkMacSystemFont, 'San Francisco', 'Helvetica Neue', Arial, sans-serif`,
|
||||
mono: `"Source Code Pro", "Roboto mono", "Courier New", monospace`,
|
||||
},
|
||||
// font-size
|
||||
fontSizes: [
|
||||
12, // 0
|
||||
16, // 1
|
||||
24, // 2
|
||||
32, // 3
|
||||
48, // 4
|
||||
64, // 5
|
||||
],
|
||||
// font-weight
|
||||
fontWeights: {
|
||||
thin: 300,
|
||||
regular: 400,
|
||||
bold: 600,
|
||||
},
|
||||
// line-height
|
||||
lineHeights: {
|
||||
min: 1.2,
|
||||
short: 1.333333,
|
||||
regular: 1.5,
|
||||
tall: 1.666666,
|
||||
},
|
||||
// border, border-top, border-right, border-bottom, border-left
|
||||
borders: ["none", "1px solid"],
|
||||
// margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, grid-gap, grid-column-gap, grid-row-gap
|
||||
space: [
|
||||
0, // 0
|
||||
4, // 1
|
||||
8, // 2
|
||||
16, // 3
|
||||
24, // 4
|
||||
32, // 5
|
||||
48, // 6
|
||||
64, // 7
|
||||
96, // 8
|
||||
],
|
||||
// border-radius
|
||||
radii: [
|
||||
0, // 0
|
||||
2, // 1
|
||||
4, // 2
|
||||
8, // 3
|
||||
16, // 4
|
||||
],
|
||||
// width, height, min-width, max-width, min-height, max-height
|
||||
sizes: [
|
||||
0, // 0
|
||||
4, // 1
|
||||
8, // 2
|
||||
16, // 3
|
||||
24, // 4
|
||||
32, // 5
|
||||
48, // 6
|
||||
64, // 7
|
||||
96, // 8
|
||||
],
|
||||
// z-index
|
||||
zIndices: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
breakpoints: ["550px", "750px", "960px"],
|
||||
};
|
||||
export const styled = baseStyled;
|
||||
export default theme;
|
@ -1,55 +0,0 @@
|
||||
import { api } from './api';
|
||||
import { store } from './store';
|
||||
|
||||
export class Subscription {
|
||||
start() {
|
||||
if (api.ship) {
|
||||
this.initializeBtcWallet();
|
||||
this.initializeSettings();
|
||||
this.initializeCurrencyPoll();
|
||||
} else {
|
||||
console.error("~~~ ERROR: Must set api.authTokens before operation ~~~");
|
||||
}
|
||||
}
|
||||
|
||||
initializeBtcWallet() {
|
||||
api.bind('/all', 'PUT', api.ship, 'btc-wallet',
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this));
|
||||
}
|
||||
|
||||
initializeSettings() {
|
||||
let app = 'settings-store';
|
||||
let path = '/bucket/btc-wallet';
|
||||
|
||||
fetch(`/~/scry/${app}${path}.json`).then(res => res.json())
|
||||
.then(n => {
|
||||
this.handleEvent({data: n});
|
||||
});
|
||||
|
||||
api.bind(path, 'PUT', api.ship, app,
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this));
|
||||
}
|
||||
|
||||
initializeCurrencyPoll() {
|
||||
fetch('https://blockchain.info/ticker')
|
||||
.then(res => res.json())
|
||||
.then(n => {
|
||||
store.handleEvent({data: {currencyRates: n}})
|
||||
setTimeout(this.initializeCurrencyPoll, 1000 * 60 * 15);
|
||||
});
|
||||
}
|
||||
|
||||
handleEvent(diff) {
|
||||
store.handleEvent(diff);
|
||||
}
|
||||
|
||||
handleError(err) {
|
||||
console.error(err);
|
||||
this.initializeBtcWallet();
|
||||
this.initializeSettings();
|
||||
}
|
||||
}
|
||||
|
||||
export let subscription = new Subscription();
|
@ -1,16 +1,44 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
type Channel = {
|
||||
poke: (
|
||||
ship: string,
|
||||
appl: string,
|
||||
mark: string,
|
||||
data: any,
|
||||
postDataHandler: (json: any) => void,
|
||||
errorHandler: (err: string) => void
|
||||
) => void;
|
||||
subscribe: (
|
||||
ship: string,
|
||||
appl: string,
|
||||
path: string,
|
||||
errorHandler: (err: string) => void,
|
||||
eventHandler: (event: any) => void
|
||||
) => void;
|
||||
};
|
||||
|
||||
class UrbitApi {
|
||||
setChannel(ship, channel) {
|
||||
ship: string;
|
||||
channel: Channel;
|
||||
bindPaths: string[];
|
||||
setChannel(ship: string, channel: Channel) {
|
||||
this.ship = ship;
|
||||
this.channel = channel;
|
||||
this.bindPaths = [];
|
||||
}
|
||||
|
||||
bind(path, method, ship = this.ship, appl = 'btc-wallet', success, fail) {
|
||||
bind(
|
||||
path: string,
|
||||
method: string,
|
||||
ship = this.ship,
|
||||
appl = 'btc-wallet',
|
||||
success: any,
|
||||
fail: any
|
||||
) {
|
||||
this.bindPaths = _.uniq([...this.bindPaths, path]);
|
||||
|
||||
window.subscriptionId = this.channel.subscribe(
|
||||
(window as any).subscriptionId = this.channel.subscribe(
|
||||
ship,
|
||||
appl,
|
||||
path,
|
||||
@ -25,22 +53,19 @@ class UrbitApi {
|
||||
path,
|
||||
},
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
fail(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
btcWalletCommand(data) {
|
||||
btcWalletCommand(data: any) {
|
||||
return this.action('btc-wallet', 'btc-wallet-command', data);
|
||||
}
|
||||
|
||||
settingsEvent(data) {
|
||||
settingsEvent(data: any) {
|
||||
return this.action('settings-store', 'settings-event', data);
|
||||
}
|
||||
|
||||
action(appl, mark, data) {
|
||||
action(appl: string, mark: string, data: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.channel.poke(
|
||||
this.ship,
|
||||
@ -58,4 +83,4 @@ class UrbitApi {
|
||||
}
|
||||
}
|
||||
export let api = new UrbitApi();
|
||||
window.api = api;
|
||||
(window as any).api = api;
|
@ -1,3 +1,5 @@
|
||||
import { CurrencyRate, Denomination, Transaction } from '../types';
|
||||
|
||||
export function uuid() {
|
||||
let str = '0v';
|
||||
str += Math.ceil(Math.random() * 8) + '.';
|
||||
@ -10,7 +12,7 @@ export function uuid() {
|
||||
return str.slice(0, -1);
|
||||
}
|
||||
|
||||
export function isPatTa(str) {
|
||||
export function isPatTa(str: string) {
|
||||
const r = /^[a-z,0-9,\-,.,_,~]+$/.exec(str);
|
||||
return !!r;
|
||||
}
|
||||
@ -21,8 +23,8 @@ export function isPatTa(str) {
|
||||
To:
|
||||
(javascript Date object)
|
||||
*/
|
||||
export function daToDate(st) {
|
||||
var dub = function (n) {
|
||||
export function daToDate(st: string) {
|
||||
var dub = function (n: string) {
|
||||
return parseInt(n) < 10 ? '0' + parseInt(n) : n.toString();
|
||||
};
|
||||
var da = st.split('..');
|
||||
@ -41,8 +43,8 @@ export function daToDate(st) {
|
||||
~2018.7.17..23.15.09..5be5 // urbit @da
|
||||
*/
|
||||
|
||||
export function dateToDa(d, mil) {
|
||||
var fil = function (n) {
|
||||
export function dateToDa(d: Date, mil: boolean) {
|
||||
var fil = function (n: number) {
|
||||
return n >= 10 ? n : '0' + n;
|
||||
};
|
||||
return (
|
||||
@ -56,12 +58,12 @@ export function dateToDa(d, mil) {
|
||||
);
|
||||
}
|
||||
|
||||
export function deSig(ship) {
|
||||
export function deSig(ship: string) {
|
||||
return ship.replace('~', '');
|
||||
}
|
||||
|
||||
// trim patps to match dojo, chat-cli
|
||||
export function cite(ship) {
|
||||
export function cite(ship: string) {
|
||||
let patp = ship,
|
||||
shortened = '';
|
||||
if (patp.startsWith('~')) {
|
||||
@ -80,7 +82,11 @@ export function cite(ship) {
|
||||
return `~${patp}`;
|
||||
}
|
||||
|
||||
export function satsToCurrency(sats, denomination, rates) {
|
||||
export function satsToCurrency(
|
||||
sats: number,
|
||||
denomination: Denomination,
|
||||
rates: CurrencyRate
|
||||
) {
|
||||
if (!rates) {
|
||||
throw 'nonexistent currency table';
|
||||
}
|
||||
@ -99,27 +105,7 @@ export function satsToCurrency(sats, denomination, rates) {
|
||||
return text;
|
||||
}
|
||||
|
||||
export function currencyToSats(val, denomination, rates) {
|
||||
if (!rates) {
|
||||
throw 'nonexistent currency table';
|
||||
}
|
||||
if (!rates[denomination]) {
|
||||
throw 'currency not in table';
|
||||
}
|
||||
let rate = rates[denomination];
|
||||
let sats = (parseFloat(val) / rate.last) * 100000000;
|
||||
return sats;
|
||||
}
|
||||
|
||||
export function reduceHistory(history) {
|
||||
return Object.values(history).sort((hest1, hest2) => {
|
||||
if (hest1.recvd === null) return -1;
|
||||
if (hest2.recvd === null) return +1;
|
||||
return hest2.recvd - hest1.recvd;
|
||||
});
|
||||
}
|
||||
|
||||
export function mapDenominationToSymbol(denomination) {
|
||||
export function mapDenominationToSymbol(denomination: string) {
|
||||
switch (denomination) {
|
||||
case 'USD':
|
||||
return '$';
|
||||
@ -128,7 +114,15 @@ export function mapDenominationToSymbol(denomination) {
|
||||
}
|
||||
}
|
||||
|
||||
export function copyToClipboard(textToCopy) {
|
||||
export function reduceHistory(history: Transaction[]) {
|
||||
return Object.values(history).sort((hest1, hest2) => {
|
||||
if (hest1.recvd === null) return -1;
|
||||
if (hest2.recvd === null) return +1;
|
||||
return hest2.recvd - hest1.recvd;
|
||||
});
|
||||
}
|
||||
|
||||
export function copyToClipboard(textToCopy: string) {
|
||||
// navigator clipboard api needs a secure context (https or localhost)
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
return navigator.clipboard.writeText(textToCopy);
|
||||
@ -141,7 +135,7 @@ export function copyToClipboard(textToCopy) {
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
return new Promise((res, rej) => {
|
||||
return new Promise<void>((res, rej) => {
|
||||
document.execCommand('copy') ? res() : rej();
|
||||
textArea.remove();
|
||||
});
|
183
pkg/btc-wallet/src/themes/dark.js
Normal file
183
pkg/btc-wallet/src/themes/dark.js
Normal file
@ -0,0 +1,183 @@
|
||||
import baseStyled from 'styled-components';
|
||||
|
||||
const base = {
|
||||
white: 'rgba(255,255,255,1)',
|
||||
black: 'rgba(0,0,0,1)',
|
||||
red: 'rgba(255,65,54,1)',
|
||||
yellow: 'rgba(255,199,0,1)',
|
||||
green: 'rgba(0,159,101,1)',
|
||||
blue: 'rgba(0,142,255,1)',
|
||||
};
|
||||
|
||||
const scales = {
|
||||
white05: 'rgba(255,255,255,0.05)',
|
||||
white10: 'rgba(255,255,255,0.1)',
|
||||
white20: 'rgba(255,255,255,0.2)',
|
||||
white30: 'rgba(255,255,255,0.3)',
|
||||
white40: 'rgba(255,255,255,0.4)',
|
||||
white50: 'rgba(255,255,255,0.5)',
|
||||
white60: 'rgba(255,255,255,0.6)',
|
||||
white70: 'rgba(255,255,255,0.7)',
|
||||
white80: 'rgba(255,255,255,0.8)',
|
||||
white90: 'rgba(255,255,255,0.9)',
|
||||
white100: 'rgba(255,255,255,1)',
|
||||
black05: 'rgba(0,0,0,0.05)',
|
||||
black10: 'rgba(0,0,0,0.1)',
|
||||
black20: 'rgba(0,0,0,0.2)',
|
||||
black30: 'rgba(0,0,0,0.3)',
|
||||
black40: 'rgba(0,0,0,0.4)',
|
||||
black50: 'rgba(0,0,0,0.5)',
|
||||
black60: 'rgba(0,0,0,0.6)',
|
||||
black70: 'rgba(0,0,0,0.7)',
|
||||
black80: 'rgba(0,0,0,0.8)',
|
||||
black90: 'rgba(0,0,0,0.9)',
|
||||
black100: 'rgba(0,0,0,1)',
|
||||
red05: 'rgba(255,65,54,0.05)',
|
||||
red10: 'rgba(255,65,54,0.1)',
|
||||
red20: 'rgba(255,65,54,0.2)',
|
||||
red30: 'rgba(255,65,54,0.3)',
|
||||
red40: 'rgba(255,65,54,0.4)',
|
||||
red50: 'rgba(255,65,54,0.5)',
|
||||
red60: 'rgba(255,65,54,0.6)',
|
||||
red70: 'rgba(255,65,54,0.7)',
|
||||
red80: 'rgba(255,65,54,0.8)',
|
||||
red90: 'rgba(255,65,54,0.9)',
|
||||
red100: 'rgba(255,65,54,1)',
|
||||
yellow05: 'rgba(255,199,0,0.05)',
|
||||
yellow10: 'rgba(255,199,0,0.1)',
|
||||
yellow20: 'rgba(255,199,0,0.2)',
|
||||
yellow30: 'rgba(255,199,0,0.3)',
|
||||
yellow40: 'rgba(255,199,0,0.4)',
|
||||
yellow50: 'rgba(255,199,0,0.5)',
|
||||
yellow60: 'rgba(255,199,0,0.6)',
|
||||
yellow70: 'rgba(255,199,0,0.7)',
|
||||
yellow80: 'rgba(255,199,0,0.8)',
|
||||
yellow90: 'rgba(255,199,0,0.9)',
|
||||
yellow100: 'rgba(255,199,0,1)',
|
||||
green05: 'rgba(0,159,101,0.05)',
|
||||
green10: 'rgba(0,159,101,0.1)',
|
||||
green20: 'rgba(0,159,101,0.2)',
|
||||
green30: 'rgba(0,159,101,0.3)',
|
||||
green40: 'rgba(0,159,101,0.4)',
|
||||
green50: 'rgba(0,159,101,0.5)',
|
||||
green60: 'rgba(0,159,101,0.6)',
|
||||
green70: 'rgba(0,159,101,0.7)',
|
||||
green80: 'rgba(0,159,101,0.8)',
|
||||
green90: 'rgba(0,159,101,0.9)',
|
||||
green100: 'rgba(0,159,101,1)',
|
||||
blue05: 'rgba(0,142,255,0.05)',
|
||||
blue10: 'rgba(0,142,255,0.1)',
|
||||
blue20: 'rgba(0,142,255,0.2)',
|
||||
blue30: 'rgba(0,142,255,0.3)',
|
||||
blue40: 'rgba(0,142,255,0.4)',
|
||||
blue50: 'rgba(0,142,255,0.5)',
|
||||
blue60: 'rgba(0,142,255,0.6)',
|
||||
blue70: 'rgba(0,142,255,0.7)',
|
||||
blue80: 'rgba(0,142,255,0.8)',
|
||||
blue90: 'rgba(0,142,255,0.9)',
|
||||
blue100: 'rgba(0,142,255,1)',
|
||||
};
|
||||
|
||||
const util = {
|
||||
cyan: '#00FFFF',
|
||||
magenta: '#FF00FF',
|
||||
yellow: '#FFFF00',
|
||||
black: '#000000',
|
||||
gray0: '#333333',
|
||||
};
|
||||
|
||||
const theme = {
|
||||
colors: {
|
||||
white: util.gray0,
|
||||
black: base.white,
|
||||
|
||||
gray: scales.white60,
|
||||
lightGray: scales.white30,
|
||||
washedGray: scales.white05,
|
||||
|
||||
red: base.red,
|
||||
lightRed: scales.red30,
|
||||
washedRed: scales.red05,
|
||||
|
||||
yellow: base.yellow,
|
||||
lightYellow: scales.yellow30,
|
||||
washedYellow: scales.yellow10,
|
||||
|
||||
green: base.green,
|
||||
lightGreen: scales.green30,
|
||||
washedGreen: scales.green10,
|
||||
|
||||
blue: base.blue,
|
||||
lightBlue: scales.blue30,
|
||||
washedBlue: scales.blue10,
|
||||
|
||||
none: 'rgba(0,0,0,0)',
|
||||
|
||||
scales: scales,
|
||||
util: util,
|
||||
},
|
||||
fonts: {
|
||||
sans: `"Inter", "Inter UI", -apple-system, BlinkMacSystemFont, 'San Francisco', 'Helvetica Neue', Arial, sans-serif`,
|
||||
mono: `"Source Code Pro", "Roboto mono", "Courier New", monospace`,
|
||||
},
|
||||
// font-size
|
||||
fontSizes: [
|
||||
12, // 0
|
||||
16, // 1
|
||||
24, // 2
|
||||
32, // 3
|
||||
48, // 4
|
||||
64, // 5
|
||||
],
|
||||
// font-weight
|
||||
fontWeights: {
|
||||
thin: 300,
|
||||
regular: 400,
|
||||
bold: 600,
|
||||
},
|
||||
// line-height
|
||||
lineHeights: {
|
||||
min: 1.2,
|
||||
short: 1.333333,
|
||||
regular: 1.5,
|
||||
tall: 1.666666,
|
||||
},
|
||||
// border, border-top, border-right, border-bottom, border-left
|
||||
borders: ['none', '1px solid'],
|
||||
// margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, grid-gap, grid-column-gap, grid-row-gap
|
||||
space: [
|
||||
0, // 0
|
||||
4, // 1
|
||||
8, // 2
|
||||
16, // 3
|
||||
24, // 4
|
||||
32, // 5
|
||||
48, // 6
|
||||
64, // 7
|
||||
96, // 8
|
||||
],
|
||||
// border-radius
|
||||
radii: [
|
||||
0, // 0
|
||||
2, // 1
|
||||
4, // 2
|
||||
8, // 3
|
||||
],
|
||||
// width, height, min-width, max-width, min-height, max-height
|
||||
sizes: [
|
||||
0, // 0
|
||||
4, // 1
|
||||
8, // 2
|
||||
16, // 3
|
||||
24, // 4
|
||||
32, // 5
|
||||
48, // 6
|
||||
64, // 7
|
||||
96, // 8
|
||||
],
|
||||
// z-index
|
||||
zIndices: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
breakpoints: ['550px', '750px', '960px'],
|
||||
};
|
||||
export const styled = baseStyled;
|
||||
export default theme;
|
184
pkg/btc-wallet/src/themes/light.js
Normal file
184
pkg/btc-wallet/src/themes/light.js
Normal file
@ -0,0 +1,184 @@
|
||||
import baseStyled from 'styled-components';
|
||||
|
||||
const base = {
|
||||
white: 'rgba(255,255,255,1)',
|
||||
black: 'rgba(0,0,0,1)',
|
||||
red: 'rgba(255,65,54,1)',
|
||||
yellow: 'rgba(255,199,0,1)',
|
||||
green: 'rgba(0,159,101,1)',
|
||||
blue: 'rgba(0,142,255,1)',
|
||||
none: 'rgba(0,0,0,0)',
|
||||
};
|
||||
|
||||
const scales = {
|
||||
white10: 'rgba(255,255,255,0.1)',
|
||||
white20: 'rgba(255,255,255,0.2)',
|
||||
white30: 'rgba(255,255,255,0.3)',
|
||||
white40: 'rgba(255,255,255,0.4)',
|
||||
white50: 'rgba(255,255,255,0.5)',
|
||||
white60: 'rgba(255,255,255,0.6)',
|
||||
white70: 'rgba(255,255,255,0.7)',
|
||||
white80: 'rgba(255,255,255,0.8)',
|
||||
white90: 'rgba(255,255,255,0.9)',
|
||||
white100: 'rgba(255,255,255,1)',
|
||||
black04: 'rgba(0,0,0,0.04)',
|
||||
black10: 'rgba(0,0,0,0.1)',
|
||||
black20: 'rgba(0,0,0,0.2)',
|
||||
black30: 'rgba(0,0,0,0.3)',
|
||||
black40: 'rgba(0,0,0,0.4)',
|
||||
black50: 'rgba(0,0,0,0.5)',
|
||||
black60: 'rgba(0,0,0,0.6)',
|
||||
black70: 'rgba(0,0,0,0.7)',
|
||||
black80: 'rgba(0,0,0,0.8)',
|
||||
black90: 'rgba(0,0,0,0.9)',
|
||||
black100: 'rgba(0,0,0,1)',
|
||||
red05: 'rgba(255,65,54,0.05)',
|
||||
red10: 'rgba(255,65,54,0.1)',
|
||||
red20: 'rgba(255,65,54,0.2)',
|
||||
red30: 'rgba(255,65,54,0.3)',
|
||||
red40: 'rgba(255,65,54,0.4)',
|
||||
red50: 'rgba(255,65,54,0.5)',
|
||||
red60: 'rgba(255,65,54,0.6)',
|
||||
red70: 'rgba(255,65,54,0.7)',
|
||||
red80: 'rgba(255,65,54,0.8)',
|
||||
red90: 'rgba(255,65,54,0.9)',
|
||||
red100: 'rgba(255,65,54,1)',
|
||||
yellow10: 'rgba(255,199,0,0.1)',
|
||||
yellow20: 'rgba(255,199,0,0.2)',
|
||||
yellow30: 'rgba(255,199,0,0.3)',
|
||||
yellow40: 'rgba(255,199,0,0.4)',
|
||||
yellow50: 'rgba(255,199,0,0.5)',
|
||||
yellow60: 'rgba(255,199,0,0.6)',
|
||||
yellow70: 'rgba(255,199,0,0.7)',
|
||||
yellow80: 'rgba(255,199,0,0.8)',
|
||||
yellow90: 'rgba(255,199,0,0.9)',
|
||||
yellow100: 'rgba(255,199,0,1)',
|
||||
green05: 'rgba(0,159,101,0.05)',
|
||||
green10: 'rgba(0,159,101,0.1)',
|
||||
green20: 'rgba(0,159,101,0.2)',
|
||||
green30: 'rgba(0,159,101,0.3)',
|
||||
green40: 'rgba(0,159,101,0.4)',
|
||||
green50: 'rgba(0,159,101,0.5)',
|
||||
green60: 'rgba(0,159,101,0.6)',
|
||||
green70: 'rgba(0,159,101,0.7)',
|
||||
green80: 'rgba(0,159,101,0.8)',
|
||||
green90: 'rgba(0,159,101,0.9)',
|
||||
green100: 'rgba(0,159,101,1)',
|
||||
blue10: 'rgba(0,142,255,0.1)',
|
||||
blue20: 'rgba(0,142,255,0.2)',
|
||||
blue30: 'rgba(0,142,255,0.3)',
|
||||
blue40: 'rgba(0,142,255,0.4)',
|
||||
blue50: 'rgba(0,142,255,0.5)',
|
||||
blue60: 'rgba(0,142,255,0.6)',
|
||||
blue70: 'rgba(0,142,255,0.7)',
|
||||
blue80: 'rgba(0,142,255,0.8)',
|
||||
blue90: 'rgba(0,142,255,0.9)',
|
||||
blue100: 'rgba(0,142,255,1)',
|
||||
};
|
||||
|
||||
const theme = {
|
||||
colors: {
|
||||
white: base.white,
|
||||
black: base.black,
|
||||
|
||||
gray: scales.black60,
|
||||
lighterGray: scales.black20,
|
||||
lightGray: scales.black30,
|
||||
washedGray: scales.black10,
|
||||
veryLightGray: scales.black04,
|
||||
|
||||
red: base.red,
|
||||
lightRed: scales.red30,
|
||||
washedRed: scales.red10,
|
||||
veryLightRed: scales.red05,
|
||||
|
||||
yellow: base.yellow,
|
||||
lightYellow: scales.yellow30,
|
||||
washedYellow: scales.yellow10,
|
||||
|
||||
green: base.green,
|
||||
lightGreen: scales.green30,
|
||||
midGreen: scales.green60,
|
||||
washedGreen: scales.green10,
|
||||
veryLightGreen: scales.green05,
|
||||
|
||||
blue: base.blue,
|
||||
lightBlue: scales.blue30,
|
||||
washedBlue: scales.blue10,
|
||||
|
||||
none: 'rgba(0,0,0,0)',
|
||||
scales: scales,
|
||||
|
||||
orange: 'rgba(255, 153, 0, 1)',
|
||||
midOrange: 'rgba(255, 153, 0, 0.2)',
|
||||
lightOrange: 'rgba(255, 153, 0, 0.08)',
|
||||
|
||||
sentBlue: 'rgba(33,157,255,1)',
|
||||
recvGreen: 'rgba(0,159,101,1)',
|
||||
},
|
||||
fonts: {
|
||||
sans: `"Inter", "Inter UI", -apple-system, BlinkMacSystemFont, 'San Francisco', 'Helvetica Neue', Arial, sans-serif`,
|
||||
mono: `"Source Code Pro", "Roboto mono", "Courier New", monospace`,
|
||||
},
|
||||
// font-size
|
||||
fontSizes: [
|
||||
12, // 0
|
||||
16, // 1
|
||||
24, // 2
|
||||
32, // 3
|
||||
48, // 4
|
||||
64, // 5
|
||||
],
|
||||
// font-weight
|
||||
fontWeights: {
|
||||
thin: 300,
|
||||
regular: 400,
|
||||
bold: 600,
|
||||
},
|
||||
// line-height
|
||||
lineHeights: {
|
||||
min: 1.2,
|
||||
short: 1.333333,
|
||||
regular: 1.5,
|
||||
tall: 1.666666,
|
||||
},
|
||||
// border, border-top, border-right, border-bottom, border-left
|
||||
borders: ['none', '1px solid'],
|
||||
// margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, grid-gap, grid-column-gap, grid-row-gap
|
||||
space: [
|
||||
0, // 0
|
||||
4, // 1
|
||||
8, // 2
|
||||
16, // 3
|
||||
24, // 4
|
||||
32, // 5
|
||||
48, // 6
|
||||
64, // 7
|
||||
96, // 8
|
||||
],
|
||||
// border-radius
|
||||
radii: [
|
||||
0, // 0
|
||||
2, // 1
|
||||
4, // 2
|
||||
8, // 3
|
||||
16, // 4
|
||||
],
|
||||
// width, height, min-width, max-width, min-height, max-height
|
||||
sizes: [
|
||||
0, // 0
|
||||
4, // 1
|
||||
8, // 2
|
||||
16, // 3
|
||||
24, // 4
|
||||
32, // 5
|
||||
48, // 6
|
||||
64, // 7
|
||||
96, // 8
|
||||
],
|
||||
// z-index
|
||||
zIndices: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
breakpoints: ['550px', '750px', '960px'],
|
||||
};
|
||||
export const styled = baseStyled;
|
||||
export default theme;
|
45
pkg/btc-wallet/src/types.ts
Normal file
45
pkg/btc-wallet/src/types.ts
Normal file
@ -0,0 +1,45 @@
|
||||
export type ProviderPerms = {
|
||||
provider: string;
|
||||
permitted: boolean;
|
||||
};
|
||||
|
||||
export type ShipWallets = {
|
||||
payee: string;
|
||||
hasWallet: boolean;
|
||||
};
|
||||
|
||||
export type Transaction = {
|
||||
txid: TxidType;
|
||||
recvd: number;
|
||||
outputs: [{ ship: string; val: { value: number } }];
|
||||
inputs: [{ ship: string }];
|
||||
failure: string;
|
||||
};
|
||||
|
||||
export type TxidType = {
|
||||
dat: string;
|
||||
wid: string;
|
||||
};
|
||||
|
||||
export type ScanProgress = {
|
||||
main: null | number;
|
||||
change: null | number;
|
||||
};
|
||||
|
||||
export type Network = 'bitcoin' | 'testnet';
|
||||
|
||||
export type Denomination = 'BTC' | 'USD';
|
||||
|
||||
export type UrbitWallet = {
|
||||
bitcoinTestnet: { keys: { xpub: string; xprv: string } };
|
||||
bitcoinMainnet: { keys: { xpub: string; xprv: string } };
|
||||
};
|
||||
|
||||
export type CurrencyRate = {
|
||||
[Denomination: string]: { last: number; symbol: string };
|
||||
};
|
||||
|
||||
export type Provider = {
|
||||
host: string;
|
||||
connected: boolean;
|
||||
};
|
1
pkg/btc-wallet/src/urbit-key-generation.d.ts
vendored
Normal file
1
pkg/btc-wallet/src/urbit-key-generation.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
declare module 'urbit-key-generation';
|
1
pkg/btc-wallet/src/urbit-ob.d.ts
vendored
Normal file
1
pkg/btc-wallet/src/urbit-ob.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
declare module 'urbit-ob';
|
13
pkg/btc-wallet/tsconfig.json
Normal file
13
pkg/btc-wallet/tsconfig.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"noImplicitAny": true,
|
||||
"module": "es6",
|
||||
"target": "es5",
|
||||
"jsx": "react",
|
||||
"allowJs": true,
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"lib": ["ESNext", "DOM"]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user