Skip to content

Commit

Permalink
[PSDK-441] createPayloadSignature for Wallet Class (#207)
Browse files Browse the repository at this point in the history
* [PSDK-441] createPayloadSignature for Wallet Class

* fix doc string typo
  • Loading branch information
John-peterson-coinbase authored Sep 4, 2024
1 parent 5820dbc commit c9eaaee
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/coinbase/address/wallet_address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ export class WalletAddress extends Address {
/**
* Creates a Payload Signature.
*
* @param unsignedPayload - The Unisgned Payload to sign.
* @param unsignedPayload - The Unsigned Payload to sign.
* @returns A promise that resolves to the Payload Signature object.
* @throws {APIError} if the API request to create a Payload Signature fails.
* @throws {Error} if the address does not have a private key loaded or an associated Server-Signer.
Expand Down
17 changes: 17 additions & 0 deletions src/coinbase/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { convertStringToHex, delay, formatDate, getWeekBackDate } from "./utils"
import { StakingOperation } from "./staking_operation";
import { StakingReward } from "./staking_reward";
import { StakingBalance } from "./staking_balance";
import { PayloadSignature } from "./payload_signature";

/**
* A representation of a Wallet. Wallets come with a single default Address, but can expand to have a set of Addresses,
Expand Down Expand Up @@ -755,6 +756,22 @@ export class Wallet {
return await this.getDefaultAddress()!.createTransfer(options);
}

/**
* Creates a Payload Signature.
*
* @param unsignedPayload - The Unsigned Payload to sign.
* @returns A promise that resolves to the Payload Signature object.
* @throws {APIError} if the API request to create a Payload Signature fails.
* @throws {Error} if the default address is not found.
*/
public async createPayloadSignature(unsignedPayload: string): Promise<PayloadSignature> {
if (!this.getDefaultAddress()) {
throw new Error("Default address not found");
}

return await this.getDefaultAddress()!.createPayloadSignature(unsignedPayload);
}

/**
* Returns a String representation of the Wallet.
*
Expand Down
65 changes: 65 additions & 0 deletions src/tests/wallet_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ import {
externalAddressApiMock,
stakeApiMock,
walletStakeApiMock,
VALID_SIGNED_PAYLOAD_SIGNATURE_MODEL,
} from "./utils";
import { Trade } from "../coinbase/trade";
import { WalletAddress } from "../coinbase/address/wallet_address";
import { StakingOperation } from "../coinbase/staking_operation";
import { StakingReward } from "../coinbase/staking_reward";
import { StakingBalance } from "../coinbase/staking_balance";
import { PayloadSignature } from "../coinbase/payload_signature";

describe("Wallet Class", () => {
let wallet: Wallet;
Expand Down Expand Up @@ -624,6 +626,69 @@ describe("Wallet Class", () => {
});
});

describe("#createPayloadSignature", () => {
let unsignedPayload = VALID_SIGNED_PAYLOAD_SIGNATURE_MODEL.unsigned_payload;
let signature =
"0xa4e14b28d86dfd7bae739d724ba2ffb13b4458d040930b805eea0a4bc2f5251e7901110677d1ef2ec23ef810c755d0bc72cc6472a4cfb3c53ef242c6ba9fa60a1b";

beforeAll(() => {
Coinbase.apiClients.address = addressesApiMock;
});

beforeEach(() => {
jest.clearAllMocks();
});

it("should successfully create a payload signature", async () => {
Coinbase.apiClients.address!.createPayloadSignature = mockReturnValue(
VALID_SIGNED_PAYLOAD_SIGNATURE_MODEL,
);

const payloadSignature = await wallet.createPayloadSignature(unsignedPayload);

expect(Coinbase.apiClients.address!.createPayloadSignature).toHaveBeenCalledWith(
wallet.getId(),
wallet.getDefaultAddress()!.getId(),
{
unsigned_payload: unsignedPayload,
signature,
},
);
expect(Coinbase.apiClients.address!.createPayloadSignature).toHaveBeenCalledTimes(1);
expect(payloadSignature).toBeInstanceOf(PayloadSignature);
});

it("should throw an APIError when the API call to create a payload signature fails", async () => {
Coinbase.apiClients.address!.createPayloadSignature = mockReturnRejectedValue(
new APIError("Failed to create payload signature"),
);

expect(async () => {
await wallet.createPayloadSignature(unsignedPayload);
}).rejects.toThrow(Error);

expect(Coinbase.apiClients.address!.createPayloadSignature).toHaveBeenCalledWith(
wallet.getId(),
wallet.getDefaultAddress()!.getId(),
{
unsigned_payload: unsignedPayload,
signature,
},
);
expect(Coinbase.apiClients.address!.createPayloadSignature).toHaveBeenCalledTimes(1);
});

it("should throw an Error when the wallet does not have a default address", async () => {
const invalidWallet = Wallet.init(walletModel);

expect(async () => {
await invalidWallet.createPayloadSignature(unsignedPayload);
}).rejects.toThrow(Error);

expect(Coinbase.apiClients.address!.createPayloadSignature).not.toHaveBeenCalled();
});
});

describe(".create", () => {
beforeEach(() => {});
it("should return a Wallet instance", async () => {
Expand Down

0 comments on commit c9eaaee

Please sign in to comment.