Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24,722 changes: 166 additions & 24,556 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
"@types/node": "^16.11.33",
"@types/react": "^18.0.8",
"@types/react-dom": "^18.0.3",
"bignumber.js": "^9.1.0",
"conseiljs": "^5.1.0",
"conseiljs-softsigner": "^5.0.4-1",
"electron-is-dev": "^2.0.0",
"is-electron": "^2.2.1",
"js-logger": "^1.6.1",
Expand Down
63 changes: 58 additions & 5 deletions src/components/AddressBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export function AddressBar() {
newApiKey: globalState.apiKey,
newNetwork: globalState.network,
newDerivationPath: globalState.derivationPath,
newAddress: updateAddress
newAddress: updateAddress,
isBeaconConnected: false
}
dispatch(action);
}
Expand Down Expand Up @@ -54,14 +55,31 @@ export function AddressBar() {
const activeAccount = await dAppClient.getActiveAccount();
if (activeAccount) {
setAddress(activeAccount.address)
}
else
{
} else {
console.log("Requesting permissions...");
const permissions = await dAppClient.requestPermissions();
console.log("Got permissions:", permissions);
setAddress(permissions.address)
}
const action = {
type: ActionTypes.UpdateBeaconStatus,
isBeaconConnected: true
}
dispatch(action);
} else {
throw ReferenceError("Beacon client not defined!")
}
}

const onDisconnectBeacon = async () => {
const dAppClient = globalState.beaconClient
if(dAppClient) {
await dAppClient.clearActiveAccount();
const action = {
type: ActionTypes.UpdateBeaconStatus,
isBeaconConnected: false
}
dispatch(action);
}
else {
throw ReferenceError("Beacon client not defined!")
Expand All @@ -81,6 +99,24 @@ export function AddressBar() {
setAddress(globalState.address)
}, [globalState])

useEffect( () => {
const onCheckBeaconStatus = async () => {
const dAppClient = globalState.beaconClient
if(dAppClient) {
const activeAccount = await dAppClient.getActiveAccount();
if (activeAccount) {
const action = {
type: ActionTypes.UpdateBeaconStatus,
isBeaconConnected: true
}
dispatch(action);
}
}
}
onCheckBeaconStatus();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

return (
<div>
<input
Expand All @@ -93,7 +129,24 @@ export function AddressBar() {
Update
</button>
<button onClick={() => getAddressFromLedger()}>Get from Ledger</button>
<button className="beacon-button" disabled={isElectron()===true} onClick={() => getAddressFromBeacon()}>Get from Beacon</button>
{!globalState.isBeaconConnected &&
<button
className="beacon-button"
disabled={isElectron()===true}
onClick={() => getAddressFromBeacon()}
>
Connect Beacon
</button>
}
{globalState.isBeaconConnected &&
<button
className="beacon-button"
disabled={isElectron()===true}
onClick={() => onDisconnectBeacon()}
>
Disconnect Beacon
</button>
}
</div>
);
}
3 changes: 3 additions & 0 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export function Navbar() {
<li>
<Link to="/settings">Settings</Link>
</li>
<li>
<Link to="/operations">Operations</Link>
</li>
</ul>
</nav>
)
Expand Down
103 changes: 103 additions & 0 deletions src/components/Operations.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React, {useState, useEffect} from "react";
import {useContext} from "react";
import {GlobalContext} from "../context/GlobalState";
import {OperationKindType, TezosConseilClient} from "conseiljs";
import { tezToUtez } from '../utils/currency';
import { TezosOperationType } from "@airgap/beacon-sdk";


interface AverageFees {
low: number;
medium: number;
high: number;
}

const AVERAGEFEES: AverageFees = {
low: 1420,
medium: 2840,
high: 5680
};

export default function Operations() {
const {globalState } = useContext(GlobalContext);
const [val, setVal] = useState('');
const [address, setAddress] = useState('');
const [delegateAddress, setDelAddress] = useState('');
const [fee, setFee] = useState(AVERAGEFEES.high);

useEffect(() => {
const fetchFee = async () => {
const serverFees = await TezosConseilClient.getFeeStatistics(
{ url: globalState.conseilUrl, apiKey: globalState.apiKey, network: globalState.network }, globalState.network, OperationKindType.Transaction
).catch(() => [
AVERAGEFEES,
]);

console.log('feeee', serverFees);

setFee(serverFees[0].high);
}

fetchFee();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const onChangeVal = (e: React.ChangeEvent<HTMLInputElement>) => {
setVal(e.target.value)
}

const onBeaconSend = async () => {
if(val && address && globalState.isBeaconConnected) {
const parsedAmount = tezToUtez(val);
// const parsedFee = tezToUtez(val);
const response = await globalState.beaconClient?.requestOperation({
operationDetails: [
{
kind: TezosOperationType.TRANSACTION,
destination: address,
amount: String(parsedAmount),
},
],
});
console.log("Operation Hash: ", response?.transactionHash);
}
}

const onBeaconDelegate = async () => {
if(delegateAddress && globalState.isBeaconConnected) {
const response = await globalState.beaconClient?.requestOperation({
operationDetails: [
{
kind: TezosOperationType.DELEGATION,
delegate: delegateAddress,
fee: String(fee)
},
],
});
console.log("Operation Hash: ", response?.transactionHash);
}

}
return (
<div className="operations">
<h1>Operations</h1>
<div className="label-container">
<div className="operation-address">Recipient Address</div>
<div className="operation-amount">Amount</div>
</div>
<div className="operation-container">
<input className="operation-address" value={address} onChange={e => setAddress(e.target.value)} />
<input className="operation-amount" type='number' value={val} onChange={onChangeVal} />
<button className="operation-btn" disabled={!globalState.isBeaconConnected} onClick={() => onBeaconSend()}>Send</button>
</div>
<div className="label-container">
<div className="operation-address">Baker Address</div>
</div>
<div className="operation-container">
<input className="operation-address" value={delegateAddress} onChange={e => setDelAddress(e.target.value)} />
<button className="operation-delegate-btn" disabled={!globalState.isBeaconConnected} onClick={() => onBeaconDelegate()}>Delegate</button>
</div>

</div>
);
}
3 changes: 2 additions & 1 deletion src/components/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export function Settings() {
newApiKey: apiKey,
newNetwork: network,
newAddress: address,
newDerivationPath: derivationPath
newDerivationPath: derivationPath,
isBeaconConnected: false
}
dispatch(action);
}
Expand Down
2 changes: 2 additions & 0 deletions src/components/Tezori3.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {Gallery} from "./Gallery";
import {Navbar} from "./Navbar";
import Logger from "js-logger";
import {Navigate, Route, Routes} from 'react-router-dom';
import Operations from "./Operations";

export function Tezori3() {

Expand All @@ -22,6 +23,7 @@ export function Tezori3() {
<Route path="/gallery" element={<Gallery />} />
<Route path="/wallet" element={<Wallet />} />
<Route path="/settings" element={<Settings />} />
<Route path="/operations" element={<Operations />} />
<Route path="*" element={<Navigate to="/gallery" replace />} />
</Routes>
</main>
Expand Down
13 changes: 11 additions & 2 deletions src/context/AppReducer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ export type Action = {
newTezosServer: string,
newApiKey: string,
newNetwork: string,
newDerivationPath: string
newDerivationPath: string,
isBeaconConnected: boolean
}

export enum ActionTypes {
UpdateAddress,
UpdateSettings
UpdateSettings,
UpdateBeaconStatus
}

function reducer(state: IAppContext, action: Action): IAppContext {
Expand All @@ -36,6 +38,13 @@ function reducer(state: IAppContext, action: Action): IAppContext {
derivationPath: action.newDerivationPath,
}
}
case ActionTypes.UpdateBeaconStatus: {
Logger.info("Reducer processed UpdateBeaconStatus action.")
return {
...state,
isBeaconConnected: action.isBeaconConnected
}
}
default: {
Logger.warn("Reducer encountered an unknown state")
return state;
Expand Down
12 changes: 8 additions & 4 deletions src/context/GlobalState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,22 @@ export type IAppContext = {
apiKey: string;
beaconClient: DAppClient | null;
children: ReactElement | null;
isAddressInitialized: boolean
isAddressInitialized: boolean;
conseilUrl: string;
isBeaconConnected: boolean;
}

// mainnet
const initialContext: IAppContext = {
address: "tz1Z2Ne4ZHxNPuCJeCcoykHVXTqhVdLMD9gV",
derivationPath: "44'/1729'/0'/0'/1'",
network: "mainnet",
tezosServer: "https://tezos-prod.cryptonomic-infra.tech:443",
apiKey: "ab682065-864a-4f11-bc77-0ef4e9493fa1",
apiKey: "galleon",
beaconClient: new DAppClient({name: "Tezori"}),
children: null,
isAddressInitialized: false
isAddressInitialized: false,
conseilUrl: 'https://conseil-prod.cryptonomic-infra.tech:443',
isBeaconConnected: false
}

export const GlobalContext = createContext<{
Expand Down
12 changes: 11 additions & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,17 @@ const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<GlobalProvider address={""} apiKey={""} derivationPath={""} network={""} tezosServer={""} beaconClient={null} isAddressInitialized={false}>
<GlobalProvider
isBeaconConnected={false}
conseilUrl=''
address={""}
apiKey={""}
derivationPath={""}
network={""}
tezosServer={""}
beaconClient={null}
isAddressInitialized={false}
>
<HashRouter basename={"/"}>
<Tezori3 />
</HashRouter>
Expand Down
34 changes: 34 additions & 0 deletions src/styles/default.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,38 @@ div.gallery-tile {

.beacon-button:disabled {
visibility: hidden;
}

.operation-container {
display: flex;
margin-bottom: 10px;
}

.label-container {
display: flex;
}

.operation-btn {
margin-left: 20px;
width: 100px;
}

.operation-amount {
margin-left: 10px;
width: 50px;
}

.operation-delegate-btn {
margin-left: 88px;
width: 100px;
}

.operation-address {
width: 188px;
box-sizing: border-box;
}

.operation-beacon-btn {
margin-left: 10px;
width: 150px;
}
9 changes: 9 additions & 0 deletions src/utils/currency.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { BigNumber } from 'bignumber.js';
const utez = 1_000_000;
export function tezToUtez(amount: number | string): number {
const a = typeof amount === 'string' ? parseFloat(amount) : amount;
const b = new BigNumber(a);
const m = b.multipliedBy(utez);

return m.toNumber();
}