Skip to content

Commit

Permalink
(feat) Issue #101
Browse files Browse the repository at this point in the history
(feat) Issue #83
  • Loading branch information
rrw-zilliqa committed Jan 23, 2025
1 parent 80c8f55 commit 2182862
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 50 deletions.
10 changes: 10 additions & 0 deletions README.zilliqa.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ errors due to their absence.
You can now pass `network=` and `name=` parameters to preload a network into `localStorage`.
For large sets of prewritten parameters, there is a list of connection objects in `config.json`.

These are overridden if we select network from your hostname.

## Configuration

There are some extra config options - see `public/config.json` for an example. In particular, `connections` is a list of potential connections, each of which is a dictionary:

* `menuName` - name that will appear in the connection menu for this option
* `url` - the URL to query
* `hostnames` - an array of hostnames. If the `window.location` hostname has one of these as a prefix, the `url` will be force-selected and the connections menu will not appear.

## Starting for development

.. because I keep forgetting!
Expand Down
2 changes: 1 addition & 1 deletion public/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
{ "menuName": "zq1-mainnet", "url": "https://mainnet-v934-fireblocks.mainnet-20240103-ase1.zq1.network", "hostnames": ["otterscan.zilliqa.com"] },
{ "menuName": "zq1-testnet", "url": "https://testnet-v932-fireblocks.testnet-ase1.zq1.dev", "hostnames": ["otterscan.testnet.zilliqa.com"] },
{ "menuName": "zq2-prototestnet", "url": "https://api.zq2-prototestnet.zilliqa.com", "hostnames": ["explorer.zq2-prototestnet.zilliqa.com" ] },
{ "menuName": "zq2-protomainnet", "url": "https://api.zq2-protomainnet.zilliqa.com", "hostnames": ["explorer.zq2-protomainnet.zilliqa.com"] }
{ "menuName": "zq2-protomainnet", "url": "https://api.zq2-protomainnet.zilliqa.com", "hostnames": ["explorer.zq2-protomainnet.zilliqa.com" ] }
]
}
5 changes: 3 additions & 2 deletions src/ConnectionErrorPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,13 @@ const ConnectionErrorPanel: FC<ConnectionErrorPanelProps> = ({
</Step>
</>
)}
{ config?.displayConnectionMenu ? (
<div className="flex space-x-2 mt-2">
<span className="text-blue-600">
<FontAwesomeIcon icon={faBarsProgress} size="1x" />
</span>
<NetworkMenuWithConfig config={config} />
</div>
<NetworkMenuWithConfig config={config} />
</div>) : (<div />) }
</div>
</div>
);
Expand Down
6 changes: 3 additions & 3 deletions src/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ const Header: FC<HeaderProps> = ({ sourcifyPresent }) => {
</div>
</Link>
</div>
<div className="pt-2 flex items-center justify-center">
<NetworkMenu />
</div>
{ config.displayConnectionMenu ? (<div className="pt-2 flex items-center justify-center">
<NetworkMenu />
</div>) : (<div />) }
<div className="flex items-baseline gap-x-3">
{(provider._network.chainId === 1n ||
config.priceOracleInfo?.nativeTokenPrice?.ethUSDOracleAddress) && (
Expand Down
2 changes: 1 addition & 1 deletion src/execution/address/ScillaContract.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type ContractProps = {
};

const ScillaContract: React.FC<ContractProps> = ({ address, content }) => {
let [loadContractState, setLoadContractState] = React.useState<boolean>();
let [loadContractState, setLoadContractState] = React.useState<number>(0);

return (
<div>
Expand Down
21 changes: 15 additions & 6 deletions src/execution/address/ScillaState.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FC, useContext, useState } from "react";
import { FC, useContext, useState, useRef } from "react";
import { RuntimeContext } from "../../useRuntime";
import { ContractState, useSmartContractState } from "../../useZilliqaHooks";
import { ContractState, useSmartContractState, invalidateSmartContractState } from "../../useZilliqaHooks";

type ScillaStateProps = {
address: string;
Expand Down Expand Up @@ -39,10 +39,10 @@ export const ScillaState: FC<ScillaStateProps> = ({
const [contractState, setContractState] = useState<ContractState | null>(
null,
);

const { data, isLoading } = useSmartContractState(
loadContractState ? zilliqa : undefined,
address,
loadContractState
);
if (data && contractState == null) {
setContractState(data);
Expand All @@ -53,7 +53,7 @@ export const ScillaState: FC<ScillaStateProps> = ({
<div className="mt-6">
<button
className="text-link-blue hover:text-link-blue-hover"
onClick={() => setLoadContractState(true)}
onClick={() => setLoadContractState(prev => prev + 1)}
>
Load Contract State
</button>
Expand All @@ -67,14 +67,22 @@ export const ScillaState: FC<ScillaStateProps> = ({

return (
<div className="mt-6">
<button
className="text-link-blue hover:text-link-blue-hover"
onClick={() => { setContractState(null); setLoadContractState(prev => prev + 1); }}
>
Refresh
</button>

<div className={isLoading ? "opacity-50": ""}>
<table className="w-ful border">
<thead>
<tr className="grid grid-cols-12 gap-x-2 bg-gray-100 py-2 text-left">
<th className="col-span-3 pl-1">name</th>
<th className="col-span-8 pr-1">value</th>
</tr>
</thead>
<tbody className="divide-y">
<tbody className="divide-y">
{contractState
? Object.keys(contractState).map((val) => (
<ScillaStateParamRow
Expand All @@ -86,6 +94,7 @@ export const ScillaState: FC<ScillaStateProps> = ({
: undefined}
</tbody>
</table>
</div>
</div>
</div>
);
};
81 changes: 46 additions & 35 deletions src/useConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ export type OtterscanConfig = {
* strings.
*/
backendFormat?: string;

/** Should we display the connection menu?
*/
displayConnectionMenu?: boolean;
};

/**
Expand Down Expand Up @@ -325,6 +329,7 @@ export const loadOtterscanConfig = async (): Promise<OtterscanConfig> => {
const data = await res.json();
// Override config for local dev
var config: OtterscanConfig = { ...data };
console.log(`DEV = ${import.meta.env.DEV} ${import.meta.env.VITE_ERIGON_URL}`);
if (import.meta.env.DEV) {
config.erigonURL = import.meta.env.VITE_ERIGON_URL ?? config.erigonURL;
config.beaconAPI =
Expand All @@ -339,6 +344,7 @@ export const loadOtterscanConfig = async (): Promise<OtterscanConfig> => {
);
}
}
console.log(`Erigon = ${config.erigonURL}`);
if (config.version === undefined) {
config.version = "(unknown)";
}
Expand All @@ -354,13 +360,13 @@ export const loadOtterscanConfig = async (): Promise<OtterscanConfig> => {
}
//console.log(JSON.stringify(config));
var storageConfiguration: any = {};
var hostForcesConnection : boolean = false;
try {
var storage = window["localStorage"];
if (storage !== undefined) {
storageConfiguration = JSON.parse(
storage.getItem("otterscanConfig") ?? "{}",
);
// console.log("storage Config " + JSON.stringify(storageConfiguration));
}
} catch (err) {
console.log(`Failed to get localStorage config - ${err}`);
Expand All @@ -369,17 +375,16 @@ export const loadOtterscanConfig = async (): Promise<OtterscanConfig> => {
// Default by hostname
try {
var host = window.location.host;
var connections =
storageConfiguration["connections"] ?? config.connections;
// Ignore locally stored connections when matching hostnames.
var connections = config.connections;
if (connections !== undefined) {
for (var c of connections) {
const hosts = c.hostnames;
if (hosts !== undefined) {
for (var h of hosts) {
if (host.startsWith(h)) {
if (!("erigonURL" in storageConfiguration)) {
storageConfiguration["erigonURL"] = c.url;
}
storageConfiguration["erigonURL"] = c.url;
hostForcesConnection = true;
}
}
}
Expand All @@ -406,39 +411,40 @@ export const loadOtterscanConfig = async (): Promise<OtterscanConfig> => {
}

// Set up URL parameters.
try {
var params = new URLSearchParams(window.location.search);
// Historical - this is the parameter devex used to use.
if (params.has("network")) {
const url = params.get("network");
storageConfiguration["erigonURL"] = url;
var connections =
storageConfiguration["connections"] ?? config.connections;
var found = false;
for (var c of connections) {
if (c.url === url) {
if (params.has("name")) {
let name = params.get("name");
connections = connections.map((c: ChainConnection) => {
if (c.url == url) {
c.menuName = name!;
}
return c;
});
if (!hostForcesConnection) {
try {
var params = new URLSearchParams(window.location.search);
// Historical - this is the parameter devex used to use.
if (params.has("network")) {
const url = params.get("network");
storageConfiguration["erigonURL"] = url;
var connections =
storageConfiguration["connections"] ?? config.connections;
var found = false;
for (var c of connections) {
if (c.url === url) {
if (params.has("name")) {
let name = params.get("name");
connections = connections.map((c: ChainConnection) => {
if (c.url == url) {
c.menuName = name!;
}
return c;
});
}
found = true;
break;
}
found = true;
break;
}
if (!found) {
var name = params.get("name") ?? url;
connections.push({ menuName: name, url });
}
storageConfiguration["connections"] = connections;
}
if (!found) {
var name = params.get("name") ?? url;
connections.push({ menuName: name, url });
}
storageConfiguration["connections"] = connections;
console.log("sc = " + JSON.stringify(storageConfiguration));
} catch (err) {
console.log(`Error parsing parameters - ${err}`);
}
} catch (err) {
console.log(`Error parsing parameters - ${err}`);
}

// Stash
Expand All @@ -454,7 +460,12 @@ export const loadOtterscanConfig = async (): Promise<OtterscanConfig> => {
console.log(`Error storing back to local storage - ${err}`);
}
config = { ...config, ...storageConfiguration };
// We deliberately do not store this, so that we have a fighting chance of
// being able to pop the menu back up again if a connection host was in the
// config file and is no longer there.
config.displayConnectionMenu = !hostForcesConnection;
console.log(JSON.stringify(config));

console.info("Loaded app config");
console.info(config);
return config;
Expand Down
6 changes: 4 additions & 2 deletions src/useZilliqaHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
DsBlockObj,
} from "@zilliqa-js/core/dist/types/src/types";
import { Zilliqa } from "@zilliqa-js/zilliqa";
import { Fetcher } from "swr";
import { mutate, Fetcher } from "swr";
import useSWRImmutable from "swr/immutable";
import useSWRInfinite from "swr/infinite";

Expand Down Expand Up @@ -152,9 +152,10 @@ export const smartContractStateFetcher: Fetcher<
export const useSmartContractState = (
zilliqa: Zilliqa | undefined,
address: string,
generation: number,
): { data: ContractState | undefined; isLoading: boolean } => {
const { data, error, isLoading } = useSWRImmutable(
zilliqa !== undefined ? [zilliqa, "useSmartContractState", address] : null,
zilliqa !== undefined ? [zilliqa, "useSmartContractState", address, generation] : null,
smartContractStateFetcher,
{ keepPreviousData: true },
);
Expand All @@ -163,3 +164,4 @@ export const useSmartContractState = (
}
return { data, isLoading };
};

0 comments on commit 2182862

Please sign in to comment.