Skip to content

Commit

Permalink
Integrate smart contracts execution tab
Browse files Browse the repository at this point in the history
  • Loading branch information
avalkov committed Jul 7, 2022
1 parent 97e7fac commit 8f19feb
Show file tree
Hide file tree
Showing 13 changed files with 1,389 additions and 182 deletions.
11 changes: 8 additions & 3 deletions .env-dev
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
NEXT_PUBLIC_GRAPHQL_URL=http://localhost:8080/v1/graphql
NEXT_PUBLIC_GRAPHQL_WS=ws://localhost:8080/v1/graphql
NEXT_PUBLIC_GRAPHQL_URL=http://34.122.182.3:8080/v1/graphql
NEXT_PUBLIC_GRAPHQL_WS=ws://34.122.182.3:8080/v1/graphql
NODE_ENV=development
PORT=3000
NEXT_PUBLIC_URL=http://localhost:3000
NEXT_PUBLIC_WS_CHAIN_URL=ws://localhost:26657/websocket
NEXT_PUBLIC_WS_CHAIN_URL=ws://34.123.153.6:26657/websocket
NEXT_PUBLIC_CHAIN_STATUS=testnet
NEXT_PUBLIC_CONTRACTS_URL=http://localhost:3333
NEXT_PUBLIC_RPC_URL=http://34.123.153.6:26657
# TODO: This can be fetched direclty from hasura
NEXT_PUBLIC_CHAIN_ID=cudos-testnet-private-3
NEXT_PUBLIC_GAS_PRICE=5000000000000acudos
5 changes: 5 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@ PORT=3000
NEXT_PUBLIC_URL=http://localhost:3000
NEXT_PUBLIC_RPC_WEBSOCKET=http://localhost:26657/websocket
NEXT_PUBLIC_CHAIN_TYPE=testnet
NEXT_PUBLIC_CONTRACTS_URL=http://localhost:3333
NEXT_PUBLIC_RPC_URL=http://localhost:26657
# TODO: This can be fetched direclty from hasura
NEXT_PUBLIC_CHAIN_ID=cudos-testnet-private-3
NEXT_PUBLIC_GAS_PRICE=5000000000000acudos
17 changes: 17 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: '3.6'
services:
big-dipper-2:
build:
context: .
dockerfile: Dockerfile-dev
args:
NEXT_PUBLIC_GRAPHQL_URL: ${NEXT_PUBLIC_GRAPHQL_URL}
NEXT_PUBLIC_GRAPHQL_WS: ${NEXT_PUBLIC_GRAPHQL_WS}
NEXT_PUBLIC_URL: ${NEXT_PUBLIC_URL}
NEXT_PUBLIC_WS_CHAIN_URL: ${NEXT_PUBLIC_WS_CHAIN_URL}
NEXT_PUBLIC_CHAIN_STATUS: ${NEXT_PUBLIC_CHAIN_STATUS}
NODE_ENV: ${NODE_ENV}
PORT: ${PORT}
restart: always
ports:
- "3000:3000"
1,160 changes: 1,011 additions & 149 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
"start": "NODE_ENV=production node dist/index.js",
"type-check": "tsc",
"lint": "eslint . --ext .ts,.tsx,.js,.jsx",
"lint-fix": "eslint . --ext .ts,.tsx,.js,.jsx --fix",
"test": "NODE_ENV=test jest",
"e2e": "cypress open",
"graphql:codegen": "graphql-codegen"
},
"dependencies": {
"@apollo/client": "^3.1.5",
"@cosmjs/stargate": "^0.28.10",
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
"@material-ui/core": "^4.11.3",
Expand All @@ -31,6 +33,7 @@
"color": "^3.1.3",
"copy-to-clipboard": "^3.3.1",
"cors": "^2.8.5",
"cudosjs": "^0.1.0",
"dayjs": "^1.10.4",
"dompurify": "^2.3.1",
"dotenv": "^8.2.0",
Expand All @@ -51,6 +54,7 @@
"react-cookie-consent": "^7.2.1",
"react-dom": "^17.0.2",
"react-json-pretty": "^2.2.0",
"react-jsonschema-form": "^1.8.1",
"react-share": "^4.4.0",
"react-toastify": "^7.0.3",
"react-virtualized-auto-sizer": "^1.0.4",
Expand Down
4 changes: 3 additions & 1 deletion public/locales/en/accounts.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,7 @@
"label": "Label",
"codeId": "Code Id",
"instaBlock": "Instantiated At Block",
"collateralTransactions": "Collateral Transactions"
"collateralTransactions": "Collateral Transactions",
"smartContractMessages": "Messages",
"smartContractInteraction": "Interact"
}
2 changes: 2 additions & 0 deletions src/screens/account_details/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Staking from './staking';
import Transactions from './transactions';
import OtherTokens from './other_tokens';
import SimpleBalance from './simple_balance';
import SmartContractInteraction from './smart_contract';

export {
Overview,
Expand All @@ -12,4 +13,5 @@ export {
Transactions,
OtherTokens,
SimpleBalance,
SmartContractInteraction,
};
190 changes: 190 additions & 0 deletions src/screens/account_details/components/smart_contract/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import {
useEffect, useState,
} from 'react';
import Form from 'react-jsonschema-form';
import {
connectWasmQueryClient, connectWasmSigningClient,
getAccount, getQueryFunc, getExecuteFunc,
} from '@utils/smart_contract_interaction';
import {
SigningCosmWasmClient, CosmWasmClient,
} from 'cudosjs';

interface ISmartContractInteractionProps {
rpcUrl: string;
chainID: string,
gasPrice:string,
address: string,
querySchema?: string,
executeSchema?: string,
}

type SmartContractInteractionDetails = {
account: any;
querySchemaObj: any;
executeSchemaObj: any;
queryClient: CosmWasmClient;
executeClient: SigningCosmWasmClient;
}

const initialState: SmartContractInteractionDetails = {
account: '',
querySchemaObj: null,
executeSchemaObj: null,
queryClient: null,
executeClient: null,
};

const SmartContractInteraction = (props: ISmartContractInteractionProps) => {
const [state, setState] = useState<SmartContractInteractionDetails>(initialState);

useEffect(() => {
const newState: any = {};

if (props.querySchema) {
const querySchemaObj = JSON.parse(props.querySchema);

AddMissingTitles(querySchemaObj, '');

newState.querySchemaObj = querySchemaObj;

connectWasmQueryClient(props.rpcUrl).then((client) => {
setState((prevState) => ({
...prevState,
queryClient: client,
}));
}).catch((err) => {
console.error(`connecting query client failed ${err}`);
});
}

if (props.executeSchema) {
const executeSchemaObj = JSON.parse(props.executeSchema);

AddMissingTitles(executeSchemaObj, '');

newState.executeSchemaObj = executeSchemaObj;

getAccount(props.chainID).then((acc) => {
setState((prevState) => ({
...prevState,
account: acc,
}));
}).catch((err) => {
console.error(`getting account failed ${err}`);
});

connectWasmSigningClient(props.chainID, props.rpcUrl, props.gasPrice).then((client) => {
setState((prevState) => ({
...prevState,
executeClient: client,
}));
}).catch((err) => {
console.error(`connecting execute client failed ${err}`);
});
}

setState((prevState) => ({
...prevState,
...newState,
}));
}, []);

const onSubmitQuery = (event: any) => {
const formData = getFormData(event, 0);
const queryFunc = getQueryFunc(state.queryClient, props.address);
queryFunc(formData).then((res) => {
console.log(res);
});
};

const onSubmitExecute = async (event: any) => {
const formData = getFormData(event, 1);
const executeFunc = getExecuteFunc(state.executeClient, props.address);
executeFunc(state.account.address, formData).then((res) => {
console.log(res);
});
};

return (
<>
{
state.querySchemaObj
&& <h2>Query:</h2>
&& <Form schema={state.querySchemaObj} onSubmit={onSubmitQuery} noValidate />
}
{
state.executeSchemaObj
&& <h2>Execute:</h2>
&& <Form schema={state.executeSchemaObj} onSubmit={onSubmitExecute} noValidate />
}
</>
);
};

SmartContractInteraction.defaultProps = {
querySchema: '',
executeSchema: '',
};

const getFormData = (event: any, menuIndex: number): string => {
const menu = document.querySelectorAll('select[id=\'root_anyof_select\']')[menuIndex] as any;
const selectedOption = menu.selectedOptions[0].text as string;

if (!(selectedOption in event.formData)) {
throw new Error('Invalid form data');
}

// Not using event.formData directly becasue it may contain unnecessary properties

return JSON.stringify({ [selectedOption]: event.formData[selectedOption] });
};

const AddMissingTitles = (obj: any, parentProp: string) => {
if (typeof obj !== 'object') {
return;
}

const keys = Object.keys(obj);

for (const key of keys) {
if (!obj.hasOwnProperty(key)) {
continue;
}

let nextKey = key;

if (Number.isInteger(key)) {
nextKey = parentProp;
}

AddMissingTitles(obj[key], nextKey);

if (['oneOf', 'anyOf'].includes(parentProp)) {
AddMissingTitle(obj[nextKey]);
}
}
};

const AddMissingTitle = (obj: any) => {
if ('title' in obj) {
return;
}

if ('required' in obj && obj.required.length == 1) {
obj.title = obj.required[0];
return;
}

if ('type' in obj && obj.type === 'null') {
obj.title = 'None';
return;
}

if ('$ref' in obj) {
const parts = obj.$ref.split('/');
obj.title = parts[parts.length - 1];
}
};

export default SmartContractInteraction;
5 changes: 5 additions & 0 deletions src/screens/account_details/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
fetchRewards,
fetchUnbondingBalance,
fetchCosmWasmInstantiation,
fetchContractSchemasByAddress,
} from './utils';

const defaultTokenUnit: TokenUnit = {
Expand Down Expand Up @@ -62,6 +63,7 @@ const initialState: AccountDetailState = {
},
},
},
contractSchemas: [],
tab: 0,
};

Expand Down Expand Up @@ -128,6 +130,7 @@ export const useAccountDetails = () => {
fetchUnbondingBalance(address),
fetchRewards(address),
fetchCosmWasmInstantiation(address),
fetchContractSchemasByAddress(address),
];
const [
commission,
Expand All @@ -136,6 +139,7 @@ export const useAccountDetails = () => {
unbonding,
rewards,
cosmWasmInstantiation,
fetchedContractSchemas,
] = await Promise.allSettled(promises);

const formattedRawData: any = {};
Expand All @@ -148,6 +152,7 @@ export const useAccountDetails = () => {

const rawData: any = {};
rawData.cosmwasm = R.pathOr([], ['value'], cosmWasmInstantiation);
rawData.contractSchemas = R.pathOr([], ['value'], fetchedContractSchemas);
handleSetState(rawData);
};

Expand Down
Loading

0 comments on commit 8f19feb

Please sign in to comment.