Skip to content

Commit

Permalink
Adds solana wallet adapter (#39)
Browse files Browse the repository at this point in the history
* feat: adds solana wallet adapter

* feat: cleaning up dependencies

* fix: fixes code as per pr review comments

* fix: fixes styling for dapp buttons

* fix: unused fragment

* fix: pr comments
  • Loading branch information
0xC0A1 authored Aug 11, 2021
1 parent 8b8fe5a commit 00aa49c
Show file tree
Hide file tree
Showing 18 changed files with 451 additions and 785 deletions.
69 changes: 33 additions & 36 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,36 @@
"name": "dapp-scaffold",
"version": "0.1.0",
"private": true,
"repository": {
"type": "git",
"url": "https://github.com/solana-labs/dapp-scaffold"
},
"homepage": ".",
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject",
"program:build": "cd program && cargo build-bpf",
"program:test": "cd program && cargo test-bpf",
"localnet:up": "solana-test-validator --bpf-program BpfProgram1111111111111111111111111111111111 program/target/deploy/bpf_program_template.so --reset",
"localnet:logs": "solana logs -u localhost",
"predeploy": "git pull --ff-only && yarn && yarn build",
"deploy": "gh-pages -d build",
"deploy:ar": "arweave deploy-dir build --key-file ",
"format:fix": "prettier --write \"**/*.+(js|jsx|ts|tsx|json|css|md)\""
},
"dependencies": {
"@ant-design/icons": "^4.5.0",
"@craco/craco": "^5.7.0",
"@ledgerhq/hw-transport-webusb": "^5.41.0",
"@project-serum/serum": "^0.13.34",
"@project-serum/sol-wallet-adapter": "^0.2.4",
"@solana/spl-token": "^0.1.6",
"@solana/spl-token-registry": "^0.2.203",
"@solana/spl-token-swap": "^0.1.0",
"@solana/wallet-adapter-ant-design": "^0.1.0",
"@solana/wallet-adapter-base": "^0.4.1",
"@solana/wallet-adapter-react": "^0.6.0",
"@solana/wallet-adapter-wallets": "^0.6.0",
"@solana/web3.js": "^1.22.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
Expand All @@ -28,19 +49,16 @@
"react-scripts": "3.4.3",
"typescript": "^4.0.0"
},
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject",
"program:build": "cd program && cargo build-bpf",
"program:test": "cd program && cargo test-bpf",
"localnet:up": "solana-test-validator --bpf-program BpfProgram1111111111111111111111111111111111 program/target/deploy/bpf_program_template.so --reset",
"localnet:logs": "solana logs -u localhost",
"predeploy": "git pull --ff-only && yarn && yarn build",
"deploy": "gh-pages -d build",
"deploy:ar": "arweave deploy-dir build --key-file ",
"format:fix": "prettier --write \"**/*.+(js|jsx|ts|tsx|json|css|md)\""
"devDependencies": {
"@types/bn.js": "^4.11.6",
"@types/bs58": "^4.0.1",
"@types/jest": "^24.9.1",
"@types/node": "^12.12.62",
"@types/react": "^16.9.50",
"@types/react-dom": "^16.9.8",
"arweave-deploy": "^1.9.1",
"gh-pages": "^3.1.0",
"prettier": "^2.1.2"
},
"eslintConfig": {
"extends": "react-app"
Expand All @@ -57,28 +75,7 @@
"last 1 safari version"
]
},
"repository": {
"type": "git",
"url": "https://github.com/solana-labs/dapp-scaffold"
},
"homepage": ".",
"devDependencies": {
"@types/bn.js": "^4.11.6",
"@types/bs58": "^4.0.1",
"@types/jest": "^24.9.1",
"@types/ledgerhq__hw-transport": "^4.21.3",
"@types/ledgerhq__hw-transport-webusb": "^4.70.1",
"@types/node": "^12.12.62",
"@types/react": "^16.9.50",
"@types/react-dom": "^16.9.8",
"arweave-deploy": "^1.9.1",
"gh-pages": "^3.1.0",
"prettier": "^2.1.2"
},
"jest": {
"transform": {
"(@project-serum/sol-wallet-adapter).+\\.js$": "<rootDir>/node_modules/react-scripts/node_modules/babel-jest"
},
"transformIgnorePatterns": [
"/node_modules/(?!@project-serum/sol-wallet-adapter)"
]
Expand Down
22 changes: 8 additions & 14 deletions src/components/AppBar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
import React from "react";
import { Button, Popover } from "antd";
import { useWallet } from "../../contexts/wallet";
import { CurrentUserBadge } from "../CurrentUserBadge";
import { SettingOutlined } from "@ant-design/icons";
import { Settings } from "../Settings";
import { LABELS } from "../../constants";
import { ConnectButton } from "../ConnectButton";
import {
WalletDisconnectButton,
WalletMultiButton,
} from "@solana/wallet-adapter-ant-design";
import { useWallet } from "@solana/wallet-adapter-react";

export const AppBar = (props: { left?: JSX.Element; right?: JSX.Element }) => {
const { connected } = useWallet();

const TopBar = (
<div className="App-Bar-right">
{connected ? (
<CurrentUserBadge />
) : (
<ConnectButton
type="text"
size="large"
allowWalletChange={true}
style={{ color: "#2abdd2" }}
/>
)}
<WalletMultiButton type="primary" />
<div style={{ margin: 5 }} />
{connected ? <WalletDisconnectButton type="ghost" /> : null}
<Popover
placement="topRight"
title={LABELS.SETTINGS_TOOLTIP}
Expand Down
33 changes: 24 additions & 9 deletions src/components/ConnectButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useWalletModal } from "@solana/wallet-adapter-ant-design";
import { useWallet } from "@solana/wallet-adapter-react";
import { Button, Dropdown, Menu } from "antd";
import { ButtonProps } from "antd/lib/button";
import React from "react";
import React, { useCallback } from "react";
import { LABELS } from "../../constants";
import { useWallet } from "../../contexts/wallet";

export interface ConnectButtonProps
extends ButtonProps,
Expand All @@ -11,24 +12,38 @@ export interface ConnectButtonProps
}

export const ConnectButton = (props: ConnectButtonProps) => {
const { connected, connect, select, provider } = useWallet();
const { setVisible } = useWalletModal();

const { connected, connect, select, wallet, wallets } = useWallet();
const { onClick, children, disabled, allowWalletChange, ...rest } = props;

// only show if wallet selected or user connected
const handleChangeWalletButtonClick: React.MouseEventHandler<HTMLElement> = useCallback(
(event) => {
if (connected) {
onClick?.(event);
return;
}
setVisible(true);
},
[setVisible, onClick, connected]
);

// only show if wallet selected or user connected
const menu = (
<Menu>
<Menu.Item key="3" onClick={select}>
Change Wallet
</Menu.Item>
{wallets.map((wallet) => (
<Menu.Item key={wallet.name} onClick={() => select(wallet.name)}>
Change Wallet to {wallet.name}
</Menu.Item>
))}
</Menu>
);

if (!provider || !allowWalletChange) {
if (!wallet || !allowWalletChange) {
return (
<Button
{...rest}
onClick={connected ? onClick : connect}
onClick={handleChangeWalletButtonClick}
disabled={connected && disabled}
>
{connected ? props.children : LABELS.CONNECT_LABEL}
Expand Down
12 changes: 6 additions & 6 deletions src/components/CurrentUserBadge/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import React from "react";
import { useWallet } from "../../contexts/wallet";
import { formatNumber, shortenAddress } from "../../utils/utils";
import { Identicon } from "../Identicon";
import { useNativeAccount } from "../../contexts/accounts";
import { LAMPORTS_PER_SOL } from "@solana/web3.js";
import { useWallet } from "@solana/wallet-adapter-react";

export const CurrentUserBadge = (props: {}) => {
const { wallet } = useWallet();
export const CurrentUserBadge = () => {
const { publicKey } = useWallet();
const { account } = useNativeAccount();

if (!wallet?.publicKey) {
if (!publicKey) {
return null;
}

Expand All @@ -21,9 +21,9 @@ export const CurrentUserBadge = (props: {}) => {
{formatNumber.format((account?.lamports || 0) / LAMPORTS_PER_SOL)} SOL
</span>
<div className="wallet-key">
{shortenAddress(`${wallet.publicKey}`)}
{shortenAddress(`${publicKey}`)}
<Identicon
address={wallet.publicKey.toBase58()}
address={publicKey.toBase58()}
style={{ marginLeft: "0.5rem", display: "flex" }}
/>
</div>
Expand Down
31 changes: 17 additions & 14 deletions src/components/Layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,29 @@ import React from "react";
import "./../../App.less";
import { Layout } from "antd";
import { Link } from "react-router-dom";
import { WalletModalProvider } from "@solana/wallet-adapter-ant-design";

import { LABELS } from "../../constants";
import { AppBar } from "../AppBar";

const { Header, Content } = Layout;

export const AppLayout = React.memo((props: any) => {
export const AppLayout = React.memo(({ children }) => {
return (
<div className="App wormhole-bg">
<Layout title={LABELS.APP_TITLE}>
<Header className="App-Bar">
<Link to="/">
<div className="app-title">
<h2>Solana DAPP</h2>
</div>
</Link>
<AppBar />
</Header>
<Content style={{ padding: "0 50px" }}>{props.children}</Content>
</Layout>
</div>
<WalletModalProvider>
<div className="App wormhole-bg">
<Layout title={LABELS.APP_TITLE}>
<Header className="App-Bar">
<Link to="/">
<div className="app-title">
<h2>Solana DAPP</h2>
</div>
</Link>
<AppBar />
</Header>
<Content style={{ padding: "0 50px" }}>{children}</Content>
</Layout>
</div>
</WalletModalProvider>
);
});
2 changes: 1 addition & 1 deletion src/components/Settings/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import { Button, Select } from "antd";
import { ENDPOINTS, useConnectionConfig } from "../../contexts/connection";
import { useWallet } from "../../contexts/wallet";
import { useWallet } from "@solana/wallet-adapter-react";

export const Settings = () => {
const { connected, disconnect } = useWallet();
Expand Down
3 changes: 2 additions & 1 deletion src/constants/labels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const LABELS = {
FAUCET_INFO:
"This faucet will help you fund your accounts outside of Solana main network.",
ACCOUNT_FUNDED: "Account funded.",
AIRDROP_FAIL: "Airdrop failed, please check you're not on mainnet or your localnet is running.",
REPAY_QUESTION: "How much would you like to repay?",
REPAY_ACTION: "Repay",
RESERVE_STATUS_TITLE: "Reserve Status & Configuration",
Expand All @@ -30,7 +31,7 @@ export const LABELS = {
MENU_FAUCET: "Faucet",
MENU_TRANSACTION: "Transactions",
MARGIN_TRADING: "Margin Trading",
APP_TITLE: "Oyster Lending",
APP_TITLE: "Solana DAPP",
CONNECT_BUTTON: "Connect",
WALLET_TOOLTIP: "Wallet public key",
WALLET_BALANCE: "Wallet balance",
Expand Down
2 changes: 1 addition & 1 deletion src/contexts/accounts.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useCallback, useContext, useEffect, useState } from "react";
import { useConnection } from "./connection";
import { useWallet } from "./wallet";
import {
AccountInfo,
ConfirmedSignatureInfo,
Expand All @@ -14,6 +13,7 @@ import { chunks } from "./../utils/utils";
import { EventEmitter } from "./../utils/eventEmitter";
import { useUserAccounts } from "../hooks/useUserAccounts";
import { WRAPPED_SOL_MINT, programIds } from "../utils/ids";
import { useWallet } from "@solana/wallet-adapter-react";

const AccountsContext = React.createContext<any>(null);

Expand Down
10 changes: 5 additions & 5 deletions src/contexts/connection.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useLocalStorageState } from "./../utils/utils";
import {
Account,
Keypair,
clusterApiUrl,
Connection,
PublicKey,
Expand All @@ -11,9 +11,9 @@ import React, { useContext, useEffect, useMemo, useState } from "react";
import { notify } from "./../utils/notifications";
import { ExplorerLink } from "../components/ExplorerLink";
import { setProgramIds } from "../utils/ids";
import { WalletAdapter } from "./wallet";
import { cache, getMultipleAccounts, MintParser } from "./accounts";
import { TokenListProvider, ENV as ChainID, TokenInfo } from "@solana/spl-token-registry";
import { WalletAdapter } from "@solana/wallet-adapter-base";

export type ENV =
| "mainnet-beta"
Expand Down Expand Up @@ -130,7 +130,7 @@ export function ConnectionProvider({ children = undefined as any }) {
// is empty after opening its first time, preventing subsequent subscriptions from receiving responses.
// This is a hack to prevent the list from every getting empty
useEffect(() => {
const id = connection.onAccountChange(new Account().publicKey, () => {});
const id = connection.onAccountChange(new Keypair().publicKey, () => {});
return () => {
connection.removeAccountChangeListener(id);
};
Expand All @@ -145,7 +145,7 @@ export function ConnectionProvider({ children = undefined as any }) {

useEffect(() => {
const id = sendConnection.onAccountChange(
new Account().publicKey,
new Keypair().publicKey,
() => {}
);
return () => {
Expand Down Expand Up @@ -234,7 +234,7 @@ export const sendTransaction = async (
connection: Connection,
wallet: WalletAdapter,
instructions: TransactionInstruction[],
signers: Account[],
signers: Keypair[],
awaitConfirmation = true
) => {
if (!wallet?.publicKey) {
Expand Down
Loading

0 comments on commit 00aa49c

Please sign in to comment.