Skip to content

Commit

Permalink
Hook up unbond to Approvals and Ledger
Browse files Browse the repository at this point in the history
  • Loading branch information
jurevans committed Jul 25, 2023
1 parent 0de3b86 commit a2fdefa
Show file tree
Hide file tree
Showing 15 changed files with 238 additions and 102 deletions.
3 changes: 1 addition & 2 deletions apps/extension/.prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": false,
"bracketSpacing": false
"singleQuote": false
}
6 changes: 6 additions & 0 deletions apps/extension/src/Approvals/ApproveTx/ConfirmLedgerTx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
SubmitSignedBondMsg,
SubmitSignedRevealPKMsg,
SubmitSignedTransferMsg,
SubmitSignedUnbondMsg,
} from "background/ledger/messages";
import { Ports } from "router";
import { closeCurrentTab } from "utils";
Expand Down Expand Up @@ -124,6 +125,11 @@ export const ConfirmLedgerTx: React.FC<Props> = ({ details }) => {
Ports.Background,
new SubmitSignedBondMsg(msgId, toBase64(bytes), signatures)
);
case TxType.Unbond:
return await requester.sendMessage(
Ports.Background,
new SubmitSignedUnbondMsg(msgId, toBase64(bytes), signatures)
);
case TxType.Transfer:
return await requester.sendMessage(
Ports.Background,
Expand Down
11 changes: 10 additions & 1 deletion apps/extension/src/background/approvals/init.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { Router } from "router";
import { ApproveBondMsg, ApproveTransferMsg } from "provider";
import {
ApproveBondMsg,
ApproveTransferMsg,
ApproveUnbondMsg,
ApproveWithdrawMsg,
} from "provider";
import {
RejectTxMsg,
SubmitApprovedBondMsg,
SubmitApprovedUnbondMsg,
SubmitApprovedTransferMsg,
SubmitApprovedWithdrawMsg,
} from "./messages";

import { ROUTE } from "./constants";
Expand All @@ -14,10 +20,13 @@ import { getHandler } from "./handler";
export function init(router: Router, service: ApprovalsService): void {
router.registerMessage(ApproveBondMsg);
router.registerMessage(ApproveTransferMsg);
router.registerMessage(ApproveUnbondMsg);
router.registerMessage(ApproveWithdrawMsg);
router.registerMessage(RejectTxMsg);
router.registerMessage(SubmitApprovedBondMsg);
router.registerMessage(SubmitApprovedUnbondMsg);
router.registerMessage(SubmitApprovedTransferMsg);
router.registerMessage(SubmitApprovedWithdrawMsg);

router.addHandler(ROUTE, getHandler(service));
}
30 changes: 30 additions & 0 deletions apps/extension/src/background/approvals/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ enum MessageType {
SubmitApprovedTransfer = "submit-approved-transfer",
SubmitApprovedBond = "submit-approved-bond",
SubmitApprovedUnbond = "submit-approved-unbond",
SubmitApprovedWithdraw = "submit-approved-withdraw",
}

export class RejectTxMsg extends Message<void> {
Expand Down Expand Up @@ -121,3 +122,32 @@ export class SubmitApprovedUnbondMsg extends Message<void> {
return SubmitApprovedUnbondMsg.type();
}
}

export class SubmitApprovedWithdrawMsg extends Message<void> {
public static type(): MessageType {
return MessageType.SubmitApprovedWithdraw;
}

constructor(public readonly msgId: string, public readonly password: string) {
super();
}

validate(): void {
if (!this.msgId) {
throw new Error("msgId must not be empty!");
}
if (!this.password) {
throw new Error("Password is required to submit unbond tx!");
}

return;
}

route(): string {
return ROUTE;
}

type(): string {
return SubmitApprovedWithdrawMsg.type();
}
}
41 changes: 25 additions & 16 deletions apps/extension/src/background/approvals/service.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import browser from "webextension-polyfill";
import {fromBase64} from "@cosmjs/encoding";
import {v4 as uuid} from "uuid";
import { fromBase64 } from "@cosmjs/encoding";
import { v4 as uuid } from "uuid";
import BigNumber from "bignumber.js";
import {deserialize} from "@dao-xyz/borsh";
import { deserialize } from "@dao-xyz/borsh";

import {AccountType, SubmitBondMsgValue, TransferMsgValue} from "@namada/types";
import {TxType} from "@namada/shared";
import {KVStore} from "@namada/storage";
import {
AccountType,
SubmitBondMsgValue,
SubmitUnbondMsgValue,
TransferMsgValue,
} from "@namada/types";
import { TxType } from "@namada/shared";
import { KVStore } from "@namada/storage";

import {KeyRingService, TabStore} from "background/keyring";
import {LedgerService} from "background/ledger";
import {paramsToUrl} from "@namada/utils";
import { KeyRingService, TabStore } from "background/keyring";
import { LedgerService } from "background/ledger";
import { paramsToUrl } from "@namada/utils";

export class ApprovalsService {
constructor(
Expand All @@ -33,7 +38,7 @@ export class ApprovalsService {
target,
token,
amount: amountBN,
tx: {publicKey = ""},
tx: { publicKey = "" },
} = txDetails;
const amount = new BigNumber(amountBN.toString());
const baseUrl = `${browser.runtime.getURL("approvals.html")}#/approve-tx/${
Expand Down Expand Up @@ -66,7 +71,7 @@ export class ApprovalsService {
source,
nativeToken: token,
amount: amountBN,
tx: {publicKey = ""},
tx: { publicKey = "" },
} = txDetails;
const amount = new BigNumber(amountBN.toString());
const baseUrl = `${browser.runtime.getURL("approvals.html")}#/approve-tx/${
Expand All @@ -85,16 +90,20 @@ export class ApprovalsService {
this._launchApprovalWindow(url);
}

// Deserialize bond details and prompt user
async approveUnbond(txMsg: string, type?: AccountType): Promise<void> {
// Deserialize unbond details and prompt user
async approveUnbond(txMsg: string, type: AccountType): Promise<void> {
const txMsgBuffer = Buffer.from(fromBase64(txMsg));
const id = uuid();
await this.txStore.set(id, txMsg);

// Decode tx details and launch approval screen
const txDetails = deserialize(txMsgBuffer, SubmitBondMsgValue);
const txDetails = deserialize(txMsgBuffer, SubmitUnbondMsgValue);

const {source, nativeToken, amount: amountBN} = txDetails;
const {
source,
amount: amountBN,
tx: { publicKey = "" },
} = txDetails;
const amount = new BigNumber(amountBN.toString());
const baseUrl = `${browser.runtime.getURL("approvals.html")}#/approve-tx/${
TxType.Unbond
Expand All @@ -103,9 +112,9 @@ export class ApprovalsService {
const url = paramsToUrl(baseUrl, {
id,
source,
token: nativeToken,
amount: amount.toString(),
accountType: type as string,
publicKey,
});

this._launchApprovalWindow(url);
Expand Down
16 changes: 15 additions & 1 deletion apps/extension/src/background/ledger/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
SubmitSignedBondMsg,
SubmitSignedRevealPKMsg,
GetRevealPKBytesMsg,
SubmitSignedUnbondMsg,
} from "./messages";

export const getHandler: (service: LedgerService) => Handler = (service) => {
Expand Down Expand Up @@ -37,7 +38,11 @@ export const getHandler: (service: LedgerService) => Handler = (service) => {
env,
msg as SubmitSignedBondMsg
);

case SubmitSignedUnbondMsg:
return handleSubmitSignedUnbondMsg(service)(
env,
msg as SubmitSignedBondMsg
);
default:
throw new Error("Unknown msg type");
}
Expand Down Expand Up @@ -71,6 +76,15 @@ const handleSubmitSignedBondMsg: (
};
};

const handleSubmitSignedUnbondMsg: (
service: LedgerService
) => InternalHandler<SubmitSignedUnbondMsg> = (service) => {
return async (_, msg) => {
const { bytes, msgId, signatures } = msg;
return await service.submitUnbond(msgId, bytes, signatures);
};
};
``;
const handleGetTxBytesMsg: (
service: LedgerService
) => InternalHandler<GetTxBytesMsg> = (service) => {
Expand Down
7 changes: 1 addition & 6 deletions apps/extension/src/background/ledger/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,7 @@ export class SubmitSignedUnbondMsg extends Message<void> {
constructor(
public readonly msgId: string,
public readonly bytes: string,
public readonly signatures: ResponseSign,
public readonly publicKey: string
public readonly signatures: ResponseSign
) {
super();
}
Expand All @@ -259,10 +258,6 @@ export class SubmitSignedUnbondMsg extends Message<void> {
if (!this.signatures) {
throw new Error("No signatures were provided!");
}

if (!this.publicKey) {
throw new Error("No publicKey provided!");
}
}

route(): string {
Expand Down
39 changes: 39 additions & 0 deletions apps/extension/src/background/ledger/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
AccountType,
Bip44Path,
SubmitBondMsgValue,
SubmitUnbondMsgValue,
TransferMsgValue,
} from "@namada/types";
import { ResponseSign } from "@namada/ledger-namada";
Expand Down Expand Up @@ -233,6 +234,44 @@ export class LedgerService {
await this.keyring.broadcastUpdateBalance();
}

/* Submit a bond with provided signatures */
async submitUnbond(
msgId: string,
bytes: string,
signatures: ResponseSign
): Promise<void> {
const txMsg = await this.txStore.get(msgId);

if (!txMsg) {
throw new Error(`Bond Transaction ${msgId} not found!`);
}

const { tx } = deserialize(fromBase64(txMsg), SubmitUnbondMsgValue);
const encodedTx = encodeTx(tx);

const { rawSignature, wrapperSignature } = signatures;

try {
const rawSig = encodeSignature(rawSignature);
const wrapperSig = encodeSignature(wrapperSignature);
await this.sdk.submit_signed_tx(
encodedTx,
fromBase64(bytes),
rawSig,
wrapperSig
);

await this.broadcastUpdateStaking();

// Clear pending tx if successful
await this.txStore.set(msgId, null);
} catch (e) {
console.warn(e);
}

await this.keyring.broadcastUpdateBalance();
}

/**
* Append a new address record for use with Ledger
*/
Expand Down
50 changes: 24 additions & 26 deletions apps/extension/src/provider/InjectedNamada.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import {
DerivedAccount,
Namada as INamada,
Signer as ISigner,
TxMsgProps,
} from "@namada/types";
import { InjectedProxy } from "./InjectedProxy";
import { Signer } from "./Signer";
import {InjectedProxy} from "./InjectedProxy";
import {Signer} from "./Signer";

export class InjectedNamada implements INamada {
constructor(private readonly _version: string) { }
constructor(private readonly _version: string) {}

public async connect(chainId: string): Promise<void> {
return await InjectedProxy.requestMethod<string, void>("connect", chainId);
Expand Down Expand Up @@ -39,54 +40,51 @@ export class InjectedNamada implements INamada {

public async balances(
owner: string
): Promise<{ token: string; amount: string }[]> {
): Promise<{token: string; amount: string}[]> {
return await InjectedProxy.requestMethod<
string,
{ token: string; amount: string }[]
{token: string; amount: string}[]
>("balances", owner);
}

public getSigner(chainId: string): ISigner | undefined {
return new Signer(chainId, this);
}

public async submitBond(props: {
txMsg: string;
type: AccountType;
publicKey?: string;
}): Promise<void> {
const { txMsg, type, publicKey } = props;
public async submitBond(props: TxMsgProps): Promise<void> {
const {txMsg, type} = props;
return await InjectedProxy.requestMethod<
{ txMsg: string; type: AccountType; publicKey?: string },
{txMsg: string; type: AccountType},
void
>("submitBond", {
txMsg,
type,
publicKey,
});
}

public async submitUnbond(txMsg: string): Promise<void> {
return await InjectedProxy.requestMethod<string, void>(
"submitUnbond",
txMsg
);
public async submitUnbond(props: TxMsgProps): Promise<void> {
const {txMsg, type} = props;
return await InjectedProxy.requestMethod<
{txMsg: string; type: AccountType},
void
>("submitUnbond", {txMsg, type});
}

public async submitWithdraw(txMsg: string): Promise<void> {
return await InjectedProxy.requestMethod<string, void>(
"submitWithdraw",
txMsg
);
public async submitWithdraw(props: TxMsgProps): Promise<void> {
const {txMsg, type} = props;
return await InjectedProxy.requestMethod<
{txMsg: string; type: AccountType},
void
>("submitWithdraw", {txMsg, type});
}

public async submitTransfer(props: {
txMsg: string;
type: AccountType;
}): Promise<void> {
const { txMsg, type } = props;
const {txMsg, type} = props;
return await InjectedProxy.requestMethod<
{ txMsg: string; type: AccountType },
{txMsg: string; type: AccountType},
void
>("submitTransfer", {
txMsg,
Expand All @@ -106,7 +104,7 @@ export class InjectedNamada implements INamada {
address: string;
}): Promise<string | undefined> {
return await InjectedProxy.requestMethod<
{ txMsg: string; address: string },
{txMsg: string; address: string},
string
>("encodeInitAccount", props);
}
Expand Down
Loading

0 comments on commit a2fdefa

Please sign in to comment.