Skip to content

Commit

Permalink
Finalizing UI
Browse files Browse the repository at this point in the history
  • Loading branch information
schnetzlerjoe committed Sep 10, 2023
1 parent 3a48ae8 commit cd582a9
Show file tree
Hide file tree
Showing 25 changed files with 538 additions and 108 deletions.
2 changes: 1 addition & 1 deletion packages/snap/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cosmsnap/snap",
"version": "0.1.11",
"version": "0.1.12",
"description": "The Cosmos extension for your Metamask wallet.",
"repository": {
"type": "git",
Expand Down
4 changes: 2 additions & 2 deletions packages/snap/snap.manifest.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"version": "0.1.11",
"version": "0.1.12",
"description": "Cosmos Extension that adds Cosmos support to Metamask.",
"proposedName": "Cosmos Extension",
"repository": {
"type": "git",
"url": "https://github.com/cosmos/snap.git"
},
"source": {
"shasum": "K1GF1TDVAZKDQ/MyqbyzZEyBka8M1lGheqS7CS1otPQ=",
"shasum": "mjWxRVx7VvVyf7FsGBLI0orobQyZhLK4x+vUbu/HqM0=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
14 changes: 10 additions & 4 deletions packages/snap/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { OnRpcRequestHandler } from "@metamask/snaps-types";
import { AccountData } from '@cosmjs/amino';
import { panel, text, heading, divider, copyable } from "@metamask/snaps-ui";
import { initializeChains } from "./initialize";
import { Chain, Chains, Fees } from "./types/chains";
import { Chain, Chains, Fees, Msg } from "./types/chains";
import { Address } from "./types/address";
import { ChainState, AddressState } from "./state";
import { Result } from "./types/result";
Expand Down Expand Up @@ -139,7 +139,7 @@ export const onRpcRequest: OnRpcRequestHandler = async ({
}

//Get messages if any from JSON string
let messages;
let messages: Msg[] = [];

if (request.params.msgs) {
if (typeof request.params.msgs == "string") {
Expand All @@ -150,14 +150,18 @@ export const onRpcRequest: OnRpcRequestHandler = async ({
// create all msg prompts
let uiTransact = [
heading("Confirm Transaction"),
divider(),
heading("Chain"),
text(`${request.params.chain_id}`),
divider(),
heading("Transaction"),
]

messages.txMsgs.map((item: { typeUrl: string, value: Object}) => {
messages.map((item) => {
uiTransact.push(heading(item.typeUrl)),
uiTransact.push(text(JSON.stringify(item.value, null, 2)))
uiTransact.push(text(JSON.stringify(item.value, null, 2))),
uiTransact.push(divider()),
uiTransact.push(text(""))
});

// Ensure user confirms transaction
Expand Down Expand Up @@ -332,6 +336,7 @@ export const onRpcRequest: OnRpcRequestHandler = async ({
heading("Confirm Transaction"),
heading("Chain"),
text(`${request.params.chain_id}`),
divider(),
heading("Transactions"),
divider(),
]
Expand Down Expand Up @@ -402,6 +407,7 @@ export const onRpcRequest: OnRpcRequestHandler = async ({
heading("Confirm Transaction"),
heading("Chain"),
text(`${request.params.chain_id}`),
divider(),
heading("Transactions"),
divider(),
]
Expand Down
5 changes: 5 additions & 0 deletions packages/snap/src/types/chains.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { HttpEndpoint } from "@cosmjs/stargate";

export interface Msg {
typeUrl: string;
value: any;
}

export interface Chain {
chain_name: string;
chain_id: string;
Expand Down
8 changes: 6 additions & 2 deletions packages/snapper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ Add the provider as a global object within your dApp.
```typescript
import { CosmosSnap } from "@cosmsnap/snapper";
window.cosmos = new CosmosSnap();
// then use it anywhere!
window.cosmos.changeSnapId("local:http://localhost:8080")

const memo = "Hello from Metamask!";

Expand Down Expand Up @@ -44,6 +42,12 @@ const signingClient = await SigningStargateClient.connectWithSigner(
const result = await signingClient.sign(wallet.address, [msg], fee, memo);
```

Use in development mode.
`Note:` You must run the snap locally for this to run properly.
```typescript
window.cosmos.changeSnapId("local:http://localhost:8080");
```

Structure of the provider.
```typescript
export interface SnapProvider {
Expand Down
2 changes: 1 addition & 1 deletion packages/snapper/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cosmsnap/snapper",
"version": "0.1.13",
"version": "0.1.14",
"description": "A helper package with utilities to interact with the Cosmos Extension for MetaMask.",
"repository": {
"type": "git",
Expand Down
3 changes: 3 additions & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@
"@keplr-wallet/types": "0.12.12",
"@metamask/detect-provider": "^2.0.0",
"@sveltejs/adapter-node": "^1.3.1",
"@types/lodash": "^4.14.198",
"autoprefixer": "latest",
"gridjs": "^6.0.6",
"gridjs-svelte": "^2.1.1",
"lodash": "^4.17.21",
"mongodb": "^6.0.0",
"svelte-ace": "^1.0.21",
"svelte-jsoneditor": "^0.18.3",
"svelte-preprocess": "^5.0.4"
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/components/Alert.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</svg>
<span class="sr-only">Warning icon</span>
</div>
<div class="ml-3 text-sm font-normal">Improve password difficulty.</div>
<div class="ml-3 text-sm font-normal">{$state.alertText}</div>
<button type="button" class="ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex items-center justify-center h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700" data-dismiss-target="#toast-warning" aria-label="Close">
<span class="sr-only">Close</span>
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
Expand All @@ -27,7 +27,7 @@
</svg>
<span class="sr-only">Error icon</span>
</div>
<div class="ml-3 text-sm font-normal">Item has been deleted.</div>
<div class="ml-3 text-sm font-normal">{$state.alertText}</div>
<button type="button" class="ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex items-center justify-center h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700" data-dismiss-target="#toast-danger" aria-label="Close">
<span class="sr-only">Close</span>
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
Expand Down
27 changes: 19 additions & 8 deletions packages/ui/src/components/Balance.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { copyToClipboard } from "../utils/general";
import { directory } from "../store/directory";
import _ from "lodash";
export let chain_id = "osmosis-1";
export let name = "Osmosis";
Expand Down Expand Up @@ -45,12 +46,12 @@
{name}
</div>
<div class="group-53">
<div class="price inter-medium-white-12px">
${dollarAmount}
</div>
<div class="percent inter-medium-white-14px">
{tokenAmount} {tokenDenom.substring(1).toUpperCase()}
</div>
<p class="price inter-medium-white-12px">
${_.round(dollarAmount, 2)}
</p>
<p class="percent inter-medium-white-14px w-[150px]">
{_.round(tokenAmount, 2) + " " + tokenDenom.substring(1).toUpperCase()}
</p>
</div>
</div>
</div>
Expand Down Expand Up @@ -140,14 +141,17 @@
font-size: 22px;
font-style: normal;
font-weight: 700;
width: fit-content;
overflow: hidden;
text-overflow: ellipsis;
}
.group-53 {
display: grid;
display: flex;
height: 17px;
width: 100%;
grid-auto-flow: column;
margin-top: 5px;
justify-content: space-between;
}
.price {
Expand All @@ -164,6 +168,9 @@
font-style: normal;
font-weight: 500;
opacity: 0.45;
width: fit-content;
overflow: hidden;
text-overflow: ellipsis;
}
.percent {
Expand All @@ -173,6 +180,9 @@
min-width: 46px;
opacity: 0.45;
text-align: right;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.inter-medium-white-14px {
Expand All @@ -181,6 +191,7 @@
font-size: var(--font-size-m);
font-style: normal;
font-weight: 500;
text-overflow: ellipsis;
}
.group-49 {
Expand Down
24 changes: 17 additions & 7 deletions packages/ui/src/components/Info.svelte
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
<script>
import { Popover } from 'flowbite-svelte';
import { QuestionCircleSolid, ChevronRightOutline } from 'flowbite-svelte-icons';
export let image = "/skip-dark-logo.png";
export let header = "Powered by the Skip API";
export let firstPara = "Select a different chain to transfer your asset to & witness the power of Inter-Blockchain Communication (IBC).";
export let secondPara = "Keep the Source and Destination the same to send on the same chain.";
export let buttonText = "Learn more";
export let buttonUrl = "https://skip.money/docs";
</script>

<div class="position-absolute flex items-center text-sm font-light text-gray-500 dark:text-gray-400">
<div class="flex items-center text-sm font-light text-gray-500 dark:text-gray-400">
<button id="b3">
<QuestionCircleSolid class="w-4 h-4 ml-1.5" />
<span class="sr-only">Show information</span>
</button>
</div>
<Popover defaultClass="py-2 px-3 bg-white rounded-lg font-['Inter']" triggeredBy="#b3" class="w-72 text-sm font-light text-gray-500 bg-white" placement="bottom-start">
<div class="p-3 space-y-2">
<h3 class="text-black font-semibold">Powered by the Skip API</h3>
Select a different chain to transfer your asset to & witness the power of Inter-Blockchain Communication (IBC).
<p>Keep the Source and Destination the same to send on the same chain.
</p>
<a href="https://skip.money/docs" target="_blank" class="flex items-center font-medium text-primary-600 dark:text-primary-500 dark:hover:text-primary-600 hover:text-primary-700">
Learn more <ChevronRightOutline class="w-2 h-2 ml-1.5 text-primary-600 dark:text-primary-500" />
{#if image}
<!-- svelte-ignore a11y-missing-attribute -->
<img class="w-[50px] h-[50px]" src={image}/>
{/if}
<h3 class="text-lg text-black font-semibold">{header}</h3>
{firstPara}
<p>{secondPara}</p>
<a href={buttonUrl} target="_blank" class="flex items-center font-medium text-primary-600 dark:text-primary-500 dark:hover:text-primary-600 hover:text-primary-700">
{buttonText} <ChevronRightOutline class="w-2 h-2 ml-1.5 text-primary-600 dark:text-primary-500" />
</a>
</div>
</Popover>
67 changes: 50 additions & 17 deletions packages/ui/src/components/Transfer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,63 @@
import { chains } from "../store/chains";
import Info from "./Info.svelte";
import { balances } from "../store/balances";
import { getSkipRecommendation, getRoute, type Route } from '../utils/ibc';
import { getSkipRecommendation, getMsgs, type CoinIBC } from '../utils/ibc';
import { state } from "../store/state";
import type { Coin } from "@cosmjs/stargate";
import type { Msg } from "@cosmsnap/snapper";
import _ from 'lodash';
import { makeCoinPresentable } from "../utils/general";
let source = "cosmoshub-4";
let destination = "cosmoshub-4";
let denom = "uatom";
let available: Coin = {amount: "0", denom};
let amount = 0;
let noRoute = false;
let recipient = "";
let slippage = "1";
let sourceBalances: CoinIBC[] = [];
let defaultSourceAsset: string = "";
$: {
if ($balances) {
let source_chain = $balances.filter(item => item.chain_id == source)[0];
if (source_chain) {
sourceBalances = source_chain.balances;
defaultSourceAsset = source_chain.balances[0].ibc ? source_chain.balances[0].ibc_denom! : source_chain.balances[0].denom;
}
}
}
const computeIBCRoute = async () => {
noRoute = false;
if (source != destination) {
try {
let skipRec = await getSkipRecommendation(denom, source, destination);
if (skipRec.recommendations.length == 0) {
noRoute = true;
throw new Error("No recommended asset found.");
}
let routeSkip = await getRoute(amount.toString(), denom, source, skipRec.recommendations[0].asset.denom, destination);
if (!routeSkip) {
noRoute = true;
throw new Error("No route found.");
let msg = await getMsgs(source, denom, destination, skipRec.recommendations[0].asset.denom, (amount*1000000).toString(), slippage, $chains);
let fees = {
amount: [
{
amount: "100000",
denom: "uosmo"
}
],
gas: "300000",
}
console.log(routeSkip);
let messages: Msg[] = msg.msgs.map(item => {
let msgCamel: any = _.mapKeys(JSON.parse(item.msg), (value: any, key: any) => _.camelCase(key));
return {
value: msgCamel,
typeUrl: item.msg_type_url
}
});
await window.cosmos.signAndBroadcast(source, messages, fees);
} catch (error: any) {
console.log(error);
noRoute = true;
$state.alertType = "danger";
$state.showAlert = true;
Expand All @@ -41,12 +72,12 @@
if (filtBal.length > 0) {
let filtTokens = filtBal[0].balances.filter(item => item.denom == denom);
if (filtTokens.length > 0) {
available = filtTokens[0]
available = makeCoinPresentable(filtTokens[0])
} else {
available = { amount: "0", denom };
available = makeCoinPresentable({ amount: "0", denom, ibc: false });
}
} else {
available = { amount: "0", denom };
available = makeCoinPresentable({ amount: "0", denom, ibc: false });
}
}
</script>
Expand All @@ -69,17 +100,18 @@
<div class="percent inter-medium-white-14px">
Asset
</div>
<select bind:value={denom} id="denom" name="denom" class="group-32-1 source-chain-osmosis inter-medium-white-14px">
<option class="source-chain-osmosis inter-medium-white-14px" value="uosmo">OSMO</option>
<option class="source-chain-osmosis inter-medium-white-14px" value="uatom">ATOM</option>
<select bind:value={defaultSourceAsset} id="denom" name="denom" class="group-32-1 source-chain-osmosis inter-medium-white-14px">
{#each sourceBalances as balance}
<option class="source-chain-osmosis inter-medium-white-14px" value={balance.ibc ? balance.ibc_denom : balance.denom}>{makeCoinPresentable(balance).denom}</option>
{/each}
</select>
</div>
<input type="number" placeholder="Enter amount" class="enter-amount inter-medium-white-14px overlap-group-7"/>
<input bind:value={amount} type="number" placeholder="Enter amount" class="enter-amount inter-medium-white-14px overlap-group-7"/>
<div class="flex w-full items-end">
<div class="percent inter-medium-white-14px">
Destination Chain
</div>
<div class="z-index-[1000]">
<div class="z-[1000]">
<Info/>
</div>
</div>
Expand All @@ -91,9 +123,10 @@
<div hidden={!noRoute} class="text-align-left w-full mt-4 inter-medium-red-14px">
Route Not Found
</div>
<input bind:value={amount} type="text" placeholder="Enter recipient address" class="enter-amount inter-medium-white-14px overlap-group-7"/>
<div class="available-balance-1454789 inter-medium-blueberry-14px">
Available: {Math.round((Number(available.amount) / 1000000) * 100) / 100} {available.denom.substring(1).toUpperCase()}
<input bind:value={recipient} type="text" placeholder="Enter recipient address" class="enter-amount inter-medium-white-14px overlap-group-7"/>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div on:click={() => { amount = _.round((Number(available.amount) / 1000000)) }} class="available-balance-1454789 inter-medium-blueberry-14px cursor-pointer">
Available: {_.round((Number(available.amount) / 1000000))} {available.denom.substring(1).toUpperCase()}
</div>
<button on:click={computeIBCRoute} class="frame-1-2 frame-1-4 button-send">
<div class="send-amount-1 inter-medium-white-12px">
Expand Down
Loading

0 comments on commit cd582a9

Please sign in to comment.