Skip to content

Commit

Permalink
feat: shield nam
Browse files Browse the repository at this point in the history
  • Loading branch information
mateuszjasiuk committed Oct 4, 2024
1 parent 5dc4f19 commit f46e58f
Show file tree
Hide file tree
Showing 16 changed files with 398 additions and 5 deletions.
91 changes: 91 additions & 0 deletions apps/namadillo/src/App/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import { ShieldingTransferMsgValue } from "@namada/types";
import { Toasts } from "App/Common/Toast";
import { AppLayout } from "App/Layout/AppLayout";
import { defaultAccountAtom } from "atoms/accounts";
import { chainAtom, nativeTokenAddressAtom } from "atoms/chain";
import { rpcUrlAtom } from "atoms/settings";
import BigNumber from "bignumber.js";
import { createBrowserHistory } from "history";
import { useSdk } from "hooks";
import { useExtensionEvents } from "hooks/useExtensionEvents";
import { useOnNamadaExtensionAttached } from "hooks/useOnNamadaExtensionAttached";
import { useTransactionCallback } from "hooks/useTransactionCallbacks";
import { useTransactionNotifications } from "hooks/useTransactionNotifications";
import { useAtomValue } from "jotai";
import { broadcastTx, EncodedTxData, signTx } from "lib/query";
import { Outlet } from "react-router-dom";
import { ShieldMessageType } from "workers/ShieldWorker";
import ShieldWorker from "workers/ShieldWorker?worker";
import { ChainLoader } from "./Setup/ChainLoader";

export const history = createBrowserHistory({ window });
Expand All @@ -15,6 +25,87 @@ export function App(): JSX.Element {
useOnNamadaExtensionAttached();
useTransactionNotifications();
useTransactionCallback();

const rpcUrl = useAtomValue(rpcUrlAtom);

// const worker = new ShieldedSyncWorker();
// const maspIndexerUrl = useAtomValue(maspIndexerUrlAtom);

// // eslint-disable-next-line @typescript-eslint/no-explicit-any
// (window as any).shieldedSync = () => {
// console.log("maspIndexerUrl", maspIndexerUrl);
// const msg: ShieldedSyncMessageType = {
// type: "shielded-sync-multicore",
// payload: {
// rpcUrl,
// maspIndexerUrl,
// vks: [
// "zvknam1qvgwgy79qqqqpq88yru6n3f3ugfme002t7272a0ke8zdr2kt80jhnjwmgxkwm7yc6ydp8tfh8lmd28n8hrmcvqszjm3tnytryaf4qhwu645xks4nnx64m3fnpm8yr6hrpd8jtsupyzz4knqleuy7jdjz32jcz9ual56vrf3estg0e6kew0g9aqs4vg2d6n569c78ttqw4zw6mvjkhwfprcc804qt3yewsrxf8l67p87ltnqjtjkr35pfnnxavs9c5wqpr2t2lf3husqn4zvux",
// ],
// },
// };

// worker.postMessage(msg);
// };
//
//
const { sdk } = useSdk();

const shieldWorker = new ShieldWorker();
const { data: account } = useAtomValue(defaultAccountAtom);
const { data: chain } = useAtomValue(chainAtom);
const { data: token } = useAtomValue(nativeTokenAddressAtom);
const shiedlingMsgValue = {
target:
"znam1vue386rsee5c65qsvlm9tgj5lqetz6ejkln3j57utc44w2n8upty57z7lh07myrj3clfxyl9lvn",
data: [
{
source: account?.address || "",
token: token!,
amount: 100 as unknown as BigNumber,
},
],
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).buildShieldlingTx = () => {
const msg: ShieldMessageType = {
type: "shield",
payload: {
account: account!,
gasConfig: {
gasLimit: 250000,
gasPrice: 0.000001,
},
shieldingProps: [shiedlingMsgValue],
rpcUrl,
token: token!,
chain: chain!,
},
};

shieldWorker.postMessage(msg);
};

shieldWorker.onmessage = async (e) => {
const encodedTx = e.data
.payload as EncodedTxData<ShieldingTransferMsgValue>;
console.log("encodedTx2", encodedTx);
const signedTxs = await signTx("namada", encodedTx, account?.address || "");
console.log("signedTx", signedTxs);

signedTxs.forEach((tx) => {
signedTxs.forEach((signedTx) => {
broadcastTx(
encodedTx,
signedTx,
encodedTx.meta?.props
// TODO: event type
);
});
});
};

return (
<>
<Toasts />
Expand Down
2 changes: 2 additions & 0 deletions apps/namadillo/src/atoms/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export const getIndexerApi = (): DefaultApi => {
// Helper function to use outside of hooks
const getApi = (get: <Value>(atom: Atom<Value>) => Value): DefaultApi => {
const indexerUrl = get(indexerUrlAtom);
console.log("indexerUrl", indexerUrl, typeof indexerUrl);
//TODO: this returns "" sometimes
const configuration = new Configuration({ basePath: indexerUrl });

return new DefaultApi(configuration);
Expand Down
16 changes: 16 additions & 0 deletions apps/namadillo/src/atoms/staking/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
BondMsgValue,
ClaimRewardsMsgValue,
RedelegateMsgValue,
ShieldingTransferMsgValue,
UnbondMsgValue,
WithdrawMsgValue,
} from "@namada/types";
Expand All @@ -21,6 +22,7 @@ import {
createClaimAndStakeTx,
createClaimTx,
createReDelegateTx,
createShieldingTx,
createUnbondTx,
createWithdrawTx,
fetchClaimableRewards,
Expand All @@ -38,6 +40,20 @@ export const getStakingTotalAtom = atomWithQuery<StakingTotals>((get) => {
};
});

export const createShieldingTxAtom = atomWithMutation((get) => {
const chain = get(chainAtom);
return {
mutationKey: ["create-shielding-tx"],
enabled: chain.isSuccess,
mutationFn: async ({
params,
gasConfig,
account,
}: BuildTxAtomParams<ShieldingTransferMsgValue>) =>
createShieldingTx(chain.data!, account, params, gasConfig),
};
});

export const createBondTxAtom = atomWithMutation((get) => {
const chain = get(chainAtom);
return {
Expand Down
20 changes: 20 additions & 0 deletions apps/namadillo/src/atoms/staking/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
ClaimRewardsMsgValue,
ClaimRewardsProps,
RedelegateMsgValue,
ShieldingTransferMsgValue,
ShieldingTransferProps,
TxMsgValue,
UnbondMsgValue,
WithdrawMsgValue,
Expand Down Expand Up @@ -43,6 +45,24 @@ export const createBondTx = async (
return transactionPairs;
};

export const createShieldingTx = async (
chain: ChainSettings,
account: Account,
shiedlingProps: ShieldingTransferMsgValue[],
gasConfig: GasConfig
): Promise<TransactionPair<ShieldingTransferProps> | undefined> => {
const { tx } = await getSdkInstance();
const transactionPairs = await buildTxPair(
account,
gasConfig,
chain,
shiedlingProps,
tx.buildShieldingTransfer,
shiedlingProps[0].data[0].source
);
return transactionPairs;
};

export const createUnbondTx = async (
chain: ChainSettings,
account: Account,
Expand Down
113 changes: 113 additions & 0 deletions apps/namadillo/src/lib/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Sdk } from "@heliax/namada-sdk/web";
import {
Account,
AccountType,
TxMsgValue,
TxProps,
WrapperTxProps,
} from "@namada/types";
import { getIndexerApi } from "atoms/api";
import invariant from "invariant";
import { Address, ChainSettings, GasConfig } from "types";

export type EncodedTxData<T> = {
type: string;
txs: TxProps[] &
{
innerTxHashes: string[];
}[];
wrapperTxProps: WrapperTxProps;
meta?: {
props: T[];
};
};

export const isPublicKeyRevealed = async (
address: Address
): Promise<boolean> => {
const api = getIndexerApi();
console.log("address", address);
let publicKey: string | undefined;
try {
publicKey = (await api.apiV1RevealedPublicKeyAddressGet(address)).data
?.publicKey;
console.log("publicKey", publicKey);
} catch {}
return Boolean(publicKey);
};

const getTxProps = (
account: Account,
gasConfig: GasConfig,
chain: ChainSettings
): WrapperTxProps => {
invariant(
!!account.publicKey,
"Account doesn't contain a publicKey attached to it"
);

return {
token: chain.nativeTokenAddress,
feeAmount: gasConfig.gasPrice,
gasLimit: gasConfig.gasLimit,
chainId: chain.chainId,
publicKey: account.publicKey!,
memo: "",
};
};

export const buildTx2 = async <T>(
sdk: Sdk,
account: Account,
gasConfig: GasConfig,
chain: ChainSettings,
queryProps: T[],
txFn: (wrapperTxProps: WrapperTxProps, props: T) => Promise<TxMsgValue>
): Promise<EncodedTxData<T>> => {
const { tx } = sdk;
const wrapperTxProps = getTxProps(account, gasConfig, chain);
const txs: TxMsgValue[] = [];
const txProps: TxProps[] = [];
console.log("wrapperTxProps", wrapperTxProps);

// Determine if RevealPK is needed:
// const publicKeyRevealed = await isPublicKeyRevealed(account.address);
// console.log("publicKeyRevealed", publicKeyRevealed, account.address);
// if (!publicKeyRevealed) {
// const revealPkTx = await tx.buildRevealPk(wrapperTxProps);
// txs.push(revealPkTx);
// }

console.log("queryProps", queryProps);

const encodedTxs = await Promise.all(
queryProps.map((props) => txFn.apply(tx, [wrapperTxProps, props]))
);
console.log("encodedTxs", encodedTxs);

txs.push(...encodedTxs);

if (account.type === AccountType.Ledger) {
txProps.push(...txs);
} else {
txProps.push(tx.buildBatch(txs));
}

return {
txs: txProps.map(({ args, hash, bytes, signingData }) => {
const innerTxHashes = tx.getInnerTxHashes(bytes);
return {
args,
hash,
bytes,
signingData,
innerTxHashes,
};
}),
wrapperTxProps,
type: txFn.name,
meta: {
props: queryProps,
},
};
};
2 changes: 1 addition & 1 deletion apps/namadillo/src/lib/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import {
} from "@namada/types";
import { getIndexerApi } from "atoms/api";
import { chainParametersAtom } from "atoms/chain";
import { getSdkInstance } from "hooks";
import invariant from "invariant";
import { getDefaultStore } from "jotai";
import { Address, ChainSettings, GasConfig } from "types";
import { TransactionEventsClasses } from "types/events";
import { getSdkInstance } from "utils/sdk";

export type TransactionPair<T> = {
encodedTxData: EncodedTxData<T>;
Expand Down
38 changes: 38 additions & 0 deletions apps/namadillo/src/utils/sdk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import initSdk from "@heliax/namada-sdk/inline-init";
import { getSdk, Sdk } from "@heliax/namada-sdk/web";
import { nativeTokenAddressAtom } from "atoms/chain";
import { maspIndexerUrlAtom, rpcUrlAtom } from "atoms/settings";
import { getDefaultStore } from "jotai";

// TODO: temp import fix
const initializeSdk = async (): Promise<Sdk> => {
const { cryptoMemory } = await initSdk();
const store = getDefaultStore();
const rpcUrl = store.get(rpcUrlAtom);
const maspIndexerUrl = store.get(maspIndexerUrlAtom);
const nativeToken = store.get(nativeTokenAddressAtom);

if (!nativeToken.isSuccess) {
throw "Native token not loaded";
}

const sdk = getSdk(
cryptoMemory,
rpcUrl,
maspIndexerUrl,
"",
nativeToken.data
);
return sdk;
};

// Global instance of initialized SDK
let sdkInstance: Promise<Sdk>;

// Helper to access SDK instance
export const getSdkInstance = async (): Promise<Sdk> => {
if (!sdkInstance) {
sdkInstance = initializeSdk();
}
return sdkInstance;
};
Loading

0 comments on commit f46e58f

Please sign in to comment.