v1.8.0-beta2
node v14 fix publish printversion fix version fix win icon
This commit is contained in:
parent
16b9c39c89
commit
e9191729b6
|
@ -21,10 +21,10 @@ jobs:
|
|||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Use Node.js 12.x
|
||||
- name: Use Node.js 14.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
node-version: 14.x
|
||||
- name: yarn install
|
||||
run: |
|
||||
yarn install
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "dev",
|
||||
"script": "electron:start",
|
||||
"group": { "kind": "build", "isDefault": true },
|
||||
"problemMatcher": []
|
||||
},
|
||||
|
|
|
@ -14,13 +14,13 @@ Head over to the releases page and grab the latest installers or binary. https:/
|
|||
If you are on Debian/Ubuntu, please download the '.AppImage' package and just run it.
|
||||
|
||||
```
|
||||
./Zecwallet.Fullnode-1.8.0-beta1.AppImage
|
||||
./Zecwallet.Fullnode-1.8.0-beta2.AppImage
|
||||
```
|
||||
|
||||
If you prefer to install a `.deb` package, that is also available.
|
||||
|
||||
```
|
||||
sudo apt install -f ./zecwallet_1.8.0-beta1_amd64.deb
|
||||
sudo apt install -f ./zecwallet_1.8.0-beta2_amd64.deb
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
echo "VERSION=1.8.0-beta2" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
VERSION="1.8.0-beta2"
|
||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
|
@ -0,0 +1,47 @@
|
|||
#!/bin/bash
|
||||
# Accept the variables as command line arguments as well
|
||||
POSITIONAL=()
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
key="$1"
|
||||
|
||||
case $key in
|
||||
-v|--version)
|
||||
APP_VERSION="$2"
|
||||
shift # past argument
|
||||
shift # past value
|
||||
;;
|
||||
*) # unknown option
|
||||
POSITIONAL+=("$1") # save it in an array for later
|
||||
shift # past argument
|
||||
;;
|
||||
esac
|
||||
done
|
||||
set -- "${POSITIONAL[@]}" # restore positional parameters
|
||||
|
||||
if [ -z $APP_VERSION ]; then echo "APP_VERSION is not set"; exit 1; fi
|
||||
|
||||
# Store the hash and signatures here
|
||||
cd release
|
||||
rm -rf signatures
|
||||
mkdir signatures
|
||||
|
||||
# Remove previous signatures/hashes
|
||||
rm -f sha256sum-$APP_VERSION.txt
|
||||
rm -f signatures-$APP_VERSION.zip
|
||||
|
||||
# sha256sum the binaries
|
||||
sha256sum Zecwallet*$APP_VERSION* > sha256sum-$APP_VERSION.txt
|
||||
|
||||
OIFS="$IFS"
|
||||
IFS=$'\n'
|
||||
|
||||
for i in `find ./ -iname "Zecwallet*$APP_VERSION*" -o -iname "sha256sum-$APP_VERSION.txt"`; do
|
||||
echo "Signing" "$i"
|
||||
gpg --batch --output "signatures/$i.sig" --detach-sig "$i"
|
||||
done
|
||||
|
||||
cp sha256sum-$APP_VERSION.txt signatures/
|
||||
cp ../configs/SIGNATURES_README signatures/
|
||||
|
||||
zip -r signatures-$APP_VERSION.zip signatures/
|
18
package.json
18
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "zecwallet",
|
||||
"productName": "Zecwallet Fullnode",
|
||||
"version": "1.8.0-beta1",
|
||||
"version": "1.8.0-beta2",
|
||||
"description": "Zecwallet Fullnode (Electron version)",
|
||||
"private": true,
|
||||
"main": "./public/electron.js",
|
||||
|
@ -41,9 +41,9 @@
|
|||
"eject": "react-scripts eject",
|
||||
"electron:prod": "yarn build && cross-env NODE_ENV=production && electron build/electron.js",
|
||||
"electron:start": "concurrently -k \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && electronmon .\"",
|
||||
"package-mac": "yarn build && electron-builder -m -c.extraMetadata.main=build/electron.js",
|
||||
"package-win": "yarn build && electron-builder -w -c.extraMetadata.main=build/electron.js",
|
||||
"package-linux": "yarn build && electron-builder -l -c.extraMetadata.main=build/electron.js"
|
||||
"package-mac": "yarn build && electron-builder -m -c.extraMetadata.main=build/electron.js --publish never",
|
||||
"package-win": "yarn build && electron-builder -w -c.extraMetadata.main=build/electron.js --publish never",
|
||||
"package-linux": "yarn build && electron-builder -l -c.extraMetadata.main=build/electron.js --publish never"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
|
@ -115,6 +115,16 @@
|
|||
]
|
||||
},
|
||||
"win": {
|
||||
"icon": "./resources/icon.ico",
|
||||
"extraFiles": [
|
||||
{
|
||||
"from": "bin/win",
|
||||
"to": "resources/bin/win",
|
||||
"filter": [
|
||||
"**/**"
|
||||
]
|
||||
}
|
||||
],
|
||||
"target": [
|
||||
"zip",
|
||||
"msi"
|
||||
|
|
|
@ -32,16 +32,21 @@ ipcMain.handle("doRPC_IPC", async (_, config, method, params) => {
|
|||
})
|
||||
.then((r) => resolve(r.data))
|
||||
.catch((err) => {
|
||||
const e = { ...err };
|
||||
const e = { ...err };
|
||||
|
||||
console.log(`Error calling ${method} with ${JSON.stringify(params)}`);
|
||||
|
||||
if (e.response && e.response.data && e.response.data.error) {
|
||||
console.log(JSON.stringify(e.response.data.error));
|
||||
}
|
||||
console.log(
|
||||
`Caught error: ${e.response} - ${
|
||||
e.response ? e.response.data : ""
|
||||
e.response ? e.response.data.error : ""
|
||||
}`
|
||||
);
|
||||
|
||||
if (e.response && e.response.data) {
|
||||
reject(e.response.data.toString());
|
||||
|
||||
if (e.response && e.response.data && e.response.data.error) {
|
||||
reject(JSON.stringify(e.response.data.error));
|
||||
} else {
|
||||
reject("NO_CONNECTION");
|
||||
}
|
||||
|
@ -49,7 +54,7 @@ ipcMain.handle("doRPC_IPC", async (_, config, method, params) => {
|
|||
});
|
||||
|
||||
return response;
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.handle("getZecPrice_IPC", async () => {
|
||||
const response = await new Promise((resolve, reject) => {
|
||||
|
@ -82,8 +87,10 @@ ipcMain.handle("readfile_IPC", async (_, filename) => {
|
|||
|
||||
// Create the native browser window.
|
||||
function createWindow() {
|
||||
const width = app.isPackaged ? 1200 : 2400;
|
||||
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 2400,
|
||||
width: width,
|
||||
height: 800,
|
||||
// Set the path of an additional "preload" script that can be used to
|
||||
// communicate between node-land and browser-land.
|
||||
|
@ -106,12 +113,11 @@ function createWindow() {
|
|||
|
||||
// Automatically open Chrome's DevTools in development mode.
|
||||
// if (!app.isPackaged) {
|
||||
mainWindow.webContents.openDevTools();
|
||||
mainWindow.webContents.openDevTools();
|
||||
// }
|
||||
|
||||
const menuBuilder = new MenuBuilder(mainWindow);
|
||||
menuBuilder.buildMenu();
|
||||
|
||||
}
|
||||
|
||||
// Setup a local proxy to adjust the paths of requested files when loading
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
content="Zecwallet Fullnode"
|
||||
/>
|
||||
|
||||
<meta
|
||||
|
@ -30,7 +30,7 @@
|
|||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<title>Zecwallet Fullnode</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"short_name": "ZecwalletFullNode",
|
||||
"name": "Zecwallet Fullnode",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
|
|
|
@ -51,13 +51,6 @@ const loadZcashConf = async () => {
|
|||
rpcConfig.username = confValues.rpcuser;
|
||||
rpcConfig.password = confValues.rpcpassword;
|
||||
|
||||
if (!rpcConfig.username || !rpcConfig.password) {
|
||||
console.log(
|
||||
"Your zcash.conf is missing a "rpcuser" or "rpcpassword""
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const isTestnet = (confValues.testnet && confValues.testnet === "1") || false;
|
||||
const server = confValues.rpcbind || "127.0.0.1";
|
||||
const port = confValues.rpcport || (isTestnet ? "18232" : "8232");
|
||||
|
|
|
@ -23,6 +23,7 @@ import AppState, {
|
|||
ReceivePageState,
|
||||
AddressBookEntry,
|
||||
AddressType,
|
||||
AddressDetail,
|
||||
} from "./components/AppState";
|
||||
import RPC from "./rpc";
|
||||
import Utils from "./utils/utils";
|
||||
|
@ -147,7 +148,7 @@ export default class RouteApp extends React.Component<Props, AppState> {
|
|||
this.setState({ transactions });
|
||||
};
|
||||
|
||||
setAllAddresses = (addresses: string[]) => {
|
||||
setAllAddresses = (addresses: AddressDetail[]) => {
|
||||
this.setState({ addresses });
|
||||
};
|
||||
|
||||
|
@ -231,6 +232,45 @@ export default class RouteApp extends React.Component<Props, AppState> {
|
|||
this.setState({ sendPageState: newSendPageState });
|
||||
};
|
||||
|
||||
getSendManyJSON = (): any[] => {
|
||||
const { sendPageState, info, addresses } = this.state;
|
||||
|
||||
const json = [];
|
||||
|
||||
if (sendPageState.fromaddr.startsWith("UA")) {
|
||||
// Find an address with the account number
|
||||
const fromaddr = addresses.find(
|
||||
(ad) =>
|
||||
ad.type === AddressType.unified &&
|
||||
ad.account === Utils.UAAccountfromString(sendPageState.fromaddr)
|
||||
);
|
||||
json.push(fromaddr?.address);
|
||||
} else {
|
||||
json.push(sendPageState.fromaddr);
|
||||
}
|
||||
|
||||
json.push(
|
||||
sendPageState.toaddrs.map((to) => {
|
||||
const textEncoder = new TextEncoder();
|
||||
const memo = to.memo
|
||||
? Utils.bytesToHexString(textEncoder.encode(to.memo))
|
||||
: "";
|
||||
if (memo === "") {
|
||||
return { address: to.to, amount: to.amount };
|
||||
} else {
|
||||
return { address: to.to, amount: to.amount, memo };
|
||||
}
|
||||
})
|
||||
);
|
||||
json.push(1); // minconf = 1
|
||||
json.push(Utils.getDefaultFee(info.latestBlock)); // Control the default fee as well.
|
||||
json.push(sendPageState.privacyLevel);
|
||||
|
||||
console.log("Sending:");
|
||||
console.log(json);
|
||||
return json;
|
||||
};
|
||||
|
||||
setRPCConfig = (rpcConfig?: RPCConfig) => {
|
||||
if (rpcConfig) {
|
||||
this.setState({ rpcConfig });
|
||||
|
@ -340,7 +380,7 @@ export default class RouteApp extends React.Component<Props, AppState> {
|
|||
|
||||
createNewAddress = async (type: AddressType) => {
|
||||
if (!this.rpc) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a new address
|
||||
|
@ -360,10 +400,15 @@ export default class RouteApp extends React.Component<Props, AppState> {
|
|||
|
||||
this.setState({ receivePageState: newReceivePageState });
|
||||
} catch (e) {
|
||||
this.openErrorModal("Failed to Create Address", <div>
|
||||
Couldn't create a new address. Please make sure your wallet has been initialized by running<br/>
|
||||
"zcashd-wallet-tool"
|
||||
</div>)
|
||||
this.openErrorModal(
|
||||
"Failed to Create Address",
|
||||
<div>
|
||||
Couldn't create a new address. Please make sure your wallet has been
|
||||
initialized by running
|
||||
<br />
|
||||
"zcashd-wallet-tool"
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -405,7 +450,7 @@ export default class RouteApp extends React.Component<Props, AppState> {
|
|||
/>
|
||||
|
||||
<div style={{ overflow: "hidden" }}>
|
||||
{(info && info.version > 0) && (
|
||||
{info && info.version > 0 && (
|
||||
<div className={cstyles.sidebarcontainer}>
|
||||
<Sidebar
|
||||
getPrivKeyAsString={this.getPrivKeyAsString}
|
||||
|
@ -423,6 +468,7 @@ export default class RouteApp extends React.Component<Props, AppState> {
|
|||
element={
|
||||
<Send
|
||||
addressesWithBalance={addressesWithBalance}
|
||||
getSendManyJSON={this.getSendManyJSON}
|
||||
sendTransaction={this.sendTransaction}
|
||||
sendPageState={sendPageState}
|
||||
setSendPageState={this.setSendPageState}
|
||||
|
|
|
@ -179,6 +179,25 @@ export class Info {
|
|||
}
|
||||
}
|
||||
|
||||
export class AddressDetail {
|
||||
address: string;
|
||||
type: AddressType;
|
||||
account?: number;
|
||||
diversifier?: number;
|
||||
|
||||
constructor(
|
||||
address: string,
|
||||
type: AddressType,
|
||||
account?: number,
|
||||
diversifier?: number
|
||||
) {
|
||||
this.address = address;
|
||||
this.type = type;
|
||||
this.account = account;
|
||||
this.diversifier = diversifier;
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-classes-per-file
|
||||
export default class AppState {
|
||||
// The total confirmed and unconfirmed balance in this wallet
|
||||
|
@ -191,12 +210,11 @@ export default class AppState {
|
|||
// A map type that contains address -> privatekey/viewkey mapping, for display on the receive page
|
||||
// This mapping is ephemeral, and will disappear when the user navigates away.
|
||||
addressPrivateKeys: Map<string, string>;
|
||||
|
||||
addressViewKeys: Map<string, string>;
|
||||
|
||||
// List of all addresses in the wallet, including change addresses and addresses
|
||||
// that don't have any balance or are unused
|
||||
addresses: string[];
|
||||
addresses: AddressDetail[];
|
||||
|
||||
// List of Address / Label pairs
|
||||
addressBook: AddressBookEntry[];
|
||||
|
|
|
@ -198,6 +198,10 @@
|
|||
background-color: rgba(100, 100, 100, 0.5);
|
||||
}
|
||||
|
||||
.accordionHeader {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.accordionHeader:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ const AddressBalanceItem = ({
|
|||
<AccordionItem
|
||||
key={item.address}
|
||||
className={[cstyles.well, cstyles.margintopsmall].join(" ")}
|
||||
uuid={item.address}
|
||||
uuid={item.address.replaceAll(" ", "_")}
|
||||
>
|
||||
<AccordionItemHeading>
|
||||
<AccordionItemButton className={cstyles.accordionHeader}>
|
||||
|
|
|
@ -17,10 +17,12 @@ import {
|
|||
ReceivePageState,
|
||||
AddressBookEntry,
|
||||
AddressType,
|
||||
AddressDetail,
|
||||
} from "./AppState";
|
||||
import ScrollPane from "./ScrollPane";
|
||||
|
||||
type AddressBlockProps = {
|
||||
addresses: AddressDetail[];
|
||||
addressBalance: AddressBalance;
|
||||
label?: string;
|
||||
currencyName: string;
|
||||
|
@ -32,6 +34,7 @@ type AddressBlockProps = {
|
|||
};
|
||||
|
||||
const AddressBlock = ({
|
||||
addresses,
|
||||
addressBalance,
|
||||
label,
|
||||
currencyName,
|
||||
|
@ -89,6 +92,26 @@ const AddressBlock = ({
|
|||
</div>
|
||||
)}
|
||||
|
||||
{Utils.isUnified(address) && (
|
||||
<>
|
||||
<div
|
||||
className={[cstyles.sublight, cstyles.margintoplarge].join(
|
||||
" "
|
||||
)}
|
||||
>
|
||||
Details
|
||||
</div>
|
||||
<div className={[cstyles.padtopsmall].join(" ")}>
|
||||
Account Number:{" "}
|
||||
{addresses.find((ad) => ad.address === address)?.account}
|
||||
</div>
|
||||
<div className={[cstyles.padtopsmall].join(" ")}>
|
||||
Diversifier Index:{" "}
|
||||
{addresses.find((ad) => ad.address === address)?.diversifier}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div
|
||||
className={[cstyles.sublight, cstyles.margintoplarge].join(" ")}
|
||||
>
|
||||
|
@ -216,7 +239,7 @@ const AddressBlock = ({
|
|||
};
|
||||
|
||||
type Props = {
|
||||
addresses: string[];
|
||||
addresses: AddressDetail[];
|
||||
addressesWithBalance: AddressBalance[];
|
||||
addressBook: AddressBookEntry[];
|
||||
info: Info;
|
||||
|
@ -253,9 +276,11 @@ export default class Receive extends Component<Props> {
|
|||
}, new Map<string, number>());
|
||||
|
||||
const uaddrs = addresses
|
||||
.filter((a) => Utils.isUnified(a))
|
||||
.filter((a) => a.type === AddressType.unified)
|
||||
.slice(0, 100)
|
||||
.map((a) => new AddressBalance(a, addressMap.get(a) || 0));
|
||||
.map(
|
||||
(a) => new AddressBalance(a.address, addressMap.get(a.address) || 0)
|
||||
);
|
||||
let defaultUaddr = uaddrs.length ? uaddrs[0].address : "";
|
||||
if (receivePageState && Utils.isUnified(receivePageState.newAddress)) {
|
||||
defaultUaddr = receivePageState.newAddress;
|
||||
|
@ -271,9 +296,11 @@ export default class Receive extends Component<Props> {
|
|||
}
|
||||
|
||||
const zaddrs = addresses
|
||||
.filter((a) => Utils.isSapling(a))
|
||||
.filter((a) => a.type === AddressType.sapling)
|
||||
.slice(0, 100)
|
||||
.map((a) => new AddressBalance(a, addressMap.get(a) || 0));
|
||||
.map(
|
||||
(a) => new AddressBalance(a.address, addressMap.get(a.address) || 0)
|
||||
);
|
||||
|
||||
let defaultZaddr = zaddrs.length ? zaddrs[0].address : "";
|
||||
if (receivePageState && Utils.isSapling(receivePageState.newAddress)) {
|
||||
|
@ -290,9 +317,11 @@ export default class Receive extends Component<Props> {
|
|||
}
|
||||
|
||||
const taddrs = addresses
|
||||
.filter((a) => Utils.isTransparent(a))
|
||||
.filter((a) => a.type === AddressType.transparent)
|
||||
.slice(0, 100)
|
||||
.map((a) => new AddressBalance(a, addressMap.get(a) || 0));
|
||||
.map(
|
||||
(a) => new AddressBalance(a.address, addressMap.get(a.address) || 0)
|
||||
);
|
||||
|
||||
let defaultTaddr = taddrs.length ? taddrs[0].address : "";
|
||||
if (receivePageState && Utils.isTransparent(receivePageState.newAddress)) {
|
||||
|
@ -329,6 +358,7 @@ export default class Receive extends Component<Props> {
|
|||
{uaddrs.map((a) => (
|
||||
<AddressBlock
|
||||
key={a.address}
|
||||
addresses={addresses}
|
||||
addressBalance={a}
|
||||
currencyName={info.currencyName}
|
||||
label={addressBookMap.get(a.address)}
|
||||
|
@ -360,6 +390,7 @@ export default class Receive extends Component<Props> {
|
|||
{zaddrs.map((a) => (
|
||||
<AddressBlock
|
||||
key={a.address}
|
||||
addresses={addresses}
|
||||
addressBalance={a}
|
||||
currencyName={info.currencyName}
|
||||
label={addressBookMap.get(a.address)}
|
||||
|
@ -393,6 +424,7 @@ export default class Receive extends Component<Props> {
|
|||
{taddrs.map((a) => (
|
||||
<AddressBlock
|
||||
key={a.address}
|
||||
addresses={addresses}
|
||||
addressBalance={a}
|
||||
currencyName={info.currencyName}
|
||||
zecPrice={info.zecPrice}
|
||||
|
|
|
@ -141,7 +141,7 @@ const ToAddrBox = ({
|
|||
</div>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Z or T address"
|
||||
placeholder="U | Z | T address"
|
||||
className={cstyles.inputbox}
|
||||
value={toaddr.to}
|
||||
onChange={(e) => updateToField(toaddr.id, e, null, null)}
|
||||
|
@ -214,31 +214,6 @@ const ToAddrBox = ({
|
|||
);
|
||||
};
|
||||
|
||||
function getSendManyJSON(sendPageState: SendPageState, info: Info): any[] {
|
||||
const json = [];
|
||||
json.push(sendPageState.fromaddr);
|
||||
json.push(
|
||||
sendPageState.toaddrs.map((to) => {
|
||||
const textEncoder = new TextEncoder();
|
||||
const memo = to.memo
|
||||
? Utils.bytesToHexString(textEncoder.encode(to.memo))
|
||||
: "";
|
||||
if (memo === "") {
|
||||
return { address: to.to, amount: to.amount };
|
||||
} else {
|
||||
return { address: to.to, amount: to.amount, memo };
|
||||
}
|
||||
})
|
||||
);
|
||||
json.push(1); // minconf = 1
|
||||
json.push(Utils.getDefaultFee(info.latestBlock)); // Control the default fee as well.
|
||||
json.push(sendPageState.privacyLevel);
|
||||
|
||||
console.log("Sending:");
|
||||
console.log(json);
|
||||
return json;
|
||||
}
|
||||
|
||||
type ConfirmModalToAddrProps = { toaddr: ToAddr; info: Info };
|
||||
const ConfirmModalToAddr = ({ toaddr, info }: ConfirmModalToAddrProps) => {
|
||||
const { bigPart, smallPart } = Utils.splitZecAmountIntoBigSmall(
|
||||
|
@ -279,6 +254,7 @@ const ConfirmModalToAddr = ({ toaddr, info }: ConfirmModalToAddrProps) => {
|
|||
type ConfirmModalProps = {
|
||||
sendPageState: SendPageState;
|
||||
info: Info;
|
||||
getSendManyJSON: () => any[];
|
||||
sendTransaction: (
|
||||
sendJson: any[],
|
||||
fnOpenSendErrorModal: (title: string, msg: string) => void
|
||||
|
@ -291,6 +267,7 @@ type ConfirmModalProps = {
|
|||
const ConfirmModal = ({
|
||||
sendPageState,
|
||||
info,
|
||||
getSendManyJSON,
|
||||
sendTransaction,
|
||||
clearToAddrs,
|
||||
closeModal,
|
||||
|
@ -317,7 +294,7 @@ const ConfirmModal = ({
|
|||
|
||||
// Then send the Tx async
|
||||
(async () => {
|
||||
const sendJson = getSendManyJSON(sendPageState, info);
|
||||
const sendJson = getSendManyJSON();
|
||||
let success = false;
|
||||
|
||||
try {
|
||||
|
@ -441,6 +418,7 @@ type Props = {
|
|||
openErrorModal: (title: string, body: string) => void;
|
||||
closeErrorModal: () => void;
|
||||
info: Info;
|
||||
getSendManyJSON: () => any[];
|
||||
};
|
||||
|
||||
class SendState {
|
||||
|
@ -628,7 +606,13 @@ export default class Send extends PureComponent<Props, SendState> {
|
|||
errorModalBody,
|
||||
sendButtonEnabled,
|
||||
} = this.state;
|
||||
const { sendPageState, info, openErrorModal, closeErrorModal } = this.props;
|
||||
const {
|
||||
sendPageState,
|
||||
info,
|
||||
openErrorModal,
|
||||
closeErrorModal,
|
||||
getSendManyJSON,
|
||||
} = this.props;
|
||||
|
||||
const customStyles = {
|
||||
option: (provided: any, state: any) => ({
|
||||
|
@ -779,6 +763,7 @@ export default class Send extends PureComponent<Props, SendState> {
|
|||
|
||||
<ConfirmModal
|
||||
sendPageState={sendPageState}
|
||||
getSendManyJSON={getSendManyJSON}
|
||||
info={info}
|
||||
sendTransaction={sendTransaction}
|
||||
openErrorModal={openErrorModal}
|
||||
|
|
|
@ -276,7 +276,7 @@ class Sidebar extends PureComponent<Props, State> {
|
|||
"Zecwallet Fullnode",
|
||||
<div className={cstyles.verticalflex}>
|
||||
<div className={cstyles.margintoplarge}>
|
||||
Zecwallet Fullnode v1.8.0-beta1
|
||||
Zecwallet Fullnode v1.8.0-beta2
|
||||
</div>
|
||||
<div className={cstyles.margintoplarge}>
|
||||
Built with Electron. Copyright (c) 2018-2021, Aditya Kulkarni.
|
||||
|
|
90
src/rpc.ts
90
src/rpc.ts
|
@ -8,6 +8,7 @@ import {
|
|||
TxDetail,
|
||||
Info,
|
||||
AddressType,
|
||||
AddressDetail,
|
||||
} from "./components/AppState";
|
||||
import Utils from "./utils/utils";
|
||||
import SentTxStore from "./utils/SentTxStore";
|
||||
|
@ -46,7 +47,7 @@ export default class RPC {
|
|||
fnSetTotalBalance: (totalBalance: TotalBalance) => void;
|
||||
fnSetAddressesWithBalance: (ab: AddressBalance[]) => void;
|
||||
fnSetTransactionsList: (txns: Transaction[]) => void;
|
||||
fnSetAllAddresses: (allAddresses: string[]) => void;
|
||||
fnSetAllAddresses: (allAddresses: AddressDetail[]) => void;
|
||||
fnSetZecPrice: (price: number) => void;
|
||||
fnSetDisconnected: (msg: string) => void;
|
||||
|
||||
|
@ -61,7 +62,7 @@ export default class RPC {
|
|||
fnSetTotalBalance: (totalBalance: TotalBalance) => void,
|
||||
fnSetAddressesWithBalance: (ab: AddressBalance[]) => void,
|
||||
fnSetTransactionsList: (txns: Transaction[]) => void,
|
||||
fnSetAllAddresses: (allAddresses: string[]) => void,
|
||||
fnSetAllAddresses: (allAddresses: AddressDetail[]) => void,
|
||||
fnSetZecPrice: (price: number) => void,
|
||||
fnSetDisconnected: (msg: string) => void
|
||||
) {
|
||||
|
@ -268,7 +269,7 @@ export default class RPC {
|
|||
}
|
||||
|
||||
async createNewAddress(type: AddressType): Promise<string> {
|
||||
if (type === AddressType.unified) {
|
||||
if (type === AddressType.unified) {
|
||||
// First make sure that at least one account has been created.
|
||||
const accounts = await RPC.doRPC("z_listaccounts", [], this.rpcConfig);
|
||||
if (accounts.result.length === 0) {
|
||||
|
@ -330,24 +331,22 @@ export default class RPC {
|
|||
async fetchTandZAddressesWithBalances() {
|
||||
const zresponse = RPC.doRPC("z_listunspent", [0], this.rpcConfig);
|
||||
const tresponse = RPC.doRPC("listunspent", [0], this.rpcConfig);
|
||||
const uresponse = RPC.doRPC("z_getbalanceforaccount", [0], this.rpcConfig);
|
||||
|
||||
// Do the Z addresses
|
||||
// response.result has all the unspent notes.
|
||||
const unspentNotes = (await zresponse).result;
|
||||
const zgroups = _.groupBy(unspentNotes, "address");
|
||||
const zaddresses = Object.keys(zgroups).map((address) => {
|
||||
const balance = zgroups[address].reduce(
|
||||
(prev, obj) => prev + obj.amount,
|
||||
0
|
||||
);
|
||||
const zaddresses = Object.keys(zgroups)
|
||||
.filter((address) => Utils.isSapling(address))
|
||||
.map((address) => {
|
||||
const balance = zgroups[address].reduce(
|
||||
(prev, obj) => prev + obj.amount,
|
||||
0
|
||||
);
|
||||
|
||||
// Orchard change notes mysteriously don't have an address
|
||||
if (!address || address === "undefined") {
|
||||
address = "(change)";
|
||||
}
|
||||
|
||||
return new AddressBalance(address, Number(balance.toFixed(8)));
|
||||
});
|
||||
return new AddressBalance(address, Number(balance.toFixed(8)));
|
||||
});
|
||||
|
||||
// Do the T addresses
|
||||
const unspentTXOs = (await tresponse).result;
|
||||
|
@ -360,7 +359,16 @@ export default class RPC {
|
|||
return new AddressBalance(address, Number(balance.toFixed(8)));
|
||||
});
|
||||
|
||||
const addresses = zaddresses.concat(taddresses);
|
||||
// Do the U addresses
|
||||
const ubalances = (await uresponse).result;
|
||||
const uaddresses = new AddressBalance(
|
||||
Utils.UAStringfromAccount(0),
|
||||
ubalances.pools.orchard
|
||||
? Utils.zatToZec(ubalances.pools.orchard.valueZat)
|
||||
: 0
|
||||
);
|
||||
|
||||
const addresses = zaddresses.concat(taddresses).concat(uaddresses);
|
||||
|
||||
this.fnSetAddressesWithBalance(addresses);
|
||||
}
|
||||
|
@ -389,7 +397,8 @@ export default class RPC {
|
|||
|
||||
// Now get Z txns
|
||||
const zaddresses = (await zaddressesPromise).filter(
|
||||
(addr) => Utils.isSapling(addr) || Utils.isUnified(addr)
|
||||
(addr) =>
|
||||
addr.type === AddressType.sapling || addr.type === AddressType.unified
|
||||
);
|
||||
|
||||
const alltxns = new Array<any>();
|
||||
|
@ -399,14 +408,14 @@ export default class RPC {
|
|||
// For each zaddr, get the list of incoming transactions
|
||||
const incomingTxns: any = await RPC.doRPC(
|
||||
"z_listreceivedbyaddress",
|
||||
[zaddr, 0],
|
||||
[zaddr.address, 0],
|
||||
this.rpcConfig
|
||||
);
|
||||
const txns = incomingTxns.result
|
||||
.filter((itx: any) => !itx.change)
|
||||
.map((incomingTx: any) => {
|
||||
return {
|
||||
address: zaddr,
|
||||
address: zaddr.address,
|
||||
txid: incomingTx.txid,
|
||||
memo: parseMemo(incomingTx.memo),
|
||||
amount: incomingTx.amount,
|
||||
|
@ -470,25 +479,35 @@ export default class RPC {
|
|||
}
|
||||
|
||||
// Get all Addresses, including T and Z addresses
|
||||
async getAllAddresses(): Promise<string[]> {
|
||||
async getAllAddresses(): Promise<AddressDetail[]> {
|
||||
const allAddresses = await RPC.doRPC("listaddresses", [], this.rpcConfig);
|
||||
|
||||
// This returns multiple objects, each has transparent, sapling and unified addresses
|
||||
let allT: string[] = [];
|
||||
let allZ: string[] = [];
|
||||
let allU: string[] = [];
|
||||
let allT: AddressDetail[] = [];
|
||||
let allZ: AddressDetail[] = [];
|
||||
let allU: AddressDetail[] = [];
|
||||
|
||||
allAddresses.result.forEach((addressSet: any) => {
|
||||
const transparent: any = addressSet["transparent"];
|
||||
if (transparent) {
|
||||
const tAddrs: string[] = transparent["addresses"];
|
||||
const tAddrs = transparent["addresses"];
|
||||
if (tAddrs) {
|
||||
allT = allT.concat(tAddrs);
|
||||
allT = allT.concat(
|
||||
tAddrs.map(
|
||||
(taddr: string) =>
|
||||
new AddressDetail(taddr, AddressType.transparent)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const changeTaddrs: string[] = transparent["changeAddresses"];
|
||||
const changeTaddrs = transparent["changeAddresses"];
|
||||
if (changeTaddrs) {
|
||||
allT = allT.concat(changeTaddrs);
|
||||
allT = allT.concat(
|
||||
changeTaddrs.map(
|
||||
(taddr: string) =>
|
||||
new AddressDetail(taddr, AddressType.transparent)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -497,7 +516,11 @@ export default class RPC {
|
|||
saplingAddrs.forEach((saplingA) => {
|
||||
const zAddrs: string[] = saplingA["addresses"];
|
||||
if (zAddrs) {
|
||||
allZ = allZ.concat(zAddrs);
|
||||
allZ = allZ.concat(
|
||||
zAddrs.map(
|
||||
(zaddr: string) => new AddressDetail(zaddr, AddressType.sapling)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -505,12 +528,21 @@ export default class RPC {
|
|||
const unifiedAddrs: any[] = addressSet["unified"];
|
||||
if (unifiedAddrs) {
|
||||
unifiedAddrs.forEach((uaSet) => {
|
||||
const account = uaSet["account"];
|
||||
const uAddrs: any[] = uaSet["addresses"];
|
||||
if (uAddrs) {
|
||||
uAddrs.forEach((uaddr) => {
|
||||
const diversifier = uaddr["diversifier_index"];
|
||||
const ua = uaddr["address"];
|
||||
if (ua) {
|
||||
allU = allU.concat([ua]);
|
||||
allU = allU.concat([
|
||||
new AddressDetail(
|
||||
ua,
|
||||
AddressType.unified,
|
||||
account,
|
||||
diversifier
|
||||
),
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,6 +4,19 @@
|
|||
export const NO_CONNECTION: string = "Could not connect to zcashd";
|
||||
|
||||
export default class Utils {
|
||||
static UAStringfromAccount(account: number): string {
|
||||
return `UA account ${account}`;
|
||||
}
|
||||
|
||||
static UAAccountfromString(account_str: string): number {
|
||||
const matches = account_str.match(new RegExp("^UA account ([0-9]+)$"));
|
||||
if (matches && matches.length === 2) {
|
||||
return parseInt(matches[1]);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static isUnified(addr: string): boolean {
|
||||
if (!addr) return false;
|
||||
return addr.startsWith("u");
|
||||
|
@ -39,6 +52,14 @@ export default class Utils {
|
|||
);
|
||||
}
|
||||
|
||||
static zatToZec(amount: number): number {
|
||||
if (amount && amount > 0) {
|
||||
return amount / 10 ** 8;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to max 8 decimal places, and remove trailing zeros
|
||||
static maxPrecision(v: number): string {
|
||||
return v.toFixed(8);
|
||||
|
|
Loading…
Reference in New Issue