Skip to content

Commit

Permalink
[PSDK-117] Implement Transfer Class
Browse files Browse the repository at this point in the history
  • Loading branch information
John-peterson-coinbase committed May 14, 2024
1 parent 2007a99 commit 6090dbd
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/coinbase/coinbase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import { InvalidAPIKeyFormat, InternalError, InvalidConfiguration } from "./erro
export class Coinbase {
apiClients: ApiClients = {};

/**
* Represents the number of Wei per Ether.
*/
static readonly WEI_PER_ETHER: bigint = BigInt("1000000000000000000");

/**
* Initializes the Coinbase SDK.
* @constructor
Expand Down
19 changes: 19 additions & 0 deletions src/coinbase/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,22 @@ export class InvalidConfiguration extends Error {
}
}
}

/**
* InvalidUnsignedPayload error is thrown when the unsigned payload is invalid.
*/
export class InvalidUnsignedPayload extends Error {
static DEFAULT_MESSAGE = "Invalid unsigned payload";

/**
* Initializes a new InvalidUnsignedPayload instance.
* @param message - The error message.
*/
constructor(message: string = InvalidUnsignedPayload.DEFAULT_MESSAGE) {
super(message);
this.name = "InvalidUnsignedPayload";
if (Error.captureStackTrace) {
Error.captureStackTrace(this, InvalidUnsignedPayload);
}
}
}
147 changes: 147 additions & 0 deletions src/coinbase/transfer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { ApiClients } from "./types";
import { Coinbase } from "./coinbase";
import { Transfer as TransferModel } from "../client/api";
import { ethers } from "ethers";
import { InvalidUnsignedPayload } from "./errors";

/**
* A representation of a Transfer, which moves an amount of an Asset from
* a user-controlled Wallet to another Address. The fee is assumed to be paid
* in the native Asset of the Network.
*/
export class Transfer {
private model: TransferModel;
private client: ApiClients;
private transaction?: ethers.Transaction;

/**
* Initializes a new Transfer instance.
* @param {TransferModel} transferModel - The Transfer model.
* @param {ApiClients} client - The API clients.
*/
constructor(transferModel: TransferModel, client: ApiClients) {
this.model = transferModel;
this.client = client;
}

/**
* Returns the ID of the Transfer.
* @returns {string} The Transfer ID.
*/
public getId(): string {
return this.model.transfer_id;
}

/**
* Returns the Network ID of the Transfer.
* @returns {string} The Network ID.
*/
public getNetworkId(): string {
return this.model.network_id;
}

/**
* Returns the Wallet ID of the Transfer.
* @returns {string} The Wallet ID.
*/
public getWalletId(): string {
return this.model.wallet_id;
}

/**
* Returns the From Address ID of the Transfer.
* @returns {string} The From Address ID.
*/
public getFromAddressId(): string {
return this.model.address_id;
}

/**
* Returns the Destination Address ID of the Transfer.
* @returns {string} The Destination Address ID.
*/
public getDestinationAddressId(): string {
return this.model.destination;
}

/**
* Returns the Asset ID of the Transfer.
* @returns {string} The Asset ID.
*/
public getAssetId(): string {
return this.model.asset_id;
}

/**
* Returns the Amount of the Transfer.
* @returns {string} The Amount of the Asset.
*/
public getAmount(): bigint {
const amount = BigInt(this.model.amount);

if (this.getAssetId() === "ETH") {
return amount / Coinbase.WEI_PER_ETHER;
}
return BigInt(this.model.amount);
}

/**
* Returns the Unsigned Payload of the Transfer.
* @returns {string} The Unsigned Payload as a Hex string.
*/
public getUnsignedPayload(): string {
return this.model.unsigned_payload;
}

/**
* Returns the Signed Payload of the Transfer.
* @returns {string | undefined} The Signed Payload as a Hex string, or undefined if not yet available.
*/
public getSignedPayload(): string | undefined {
return this.model.signed_payload;
}

/**
* Returns the Transaction Hash of the Transfer.
* @returns {string | undefined} The Transaction Hash as a Hex string, or undefined if not yet available
*/
public getTransactionhash(): string | undefined {
return this.model.transaction_hash;
}

/**
* Returns the Transaction of the Transfer.
* @returns {ethers.Transaction} The ethers.js Transaction object.
* @throws (InvalidUnsignedPayload) If the unsigned payload is invalid.
*/
public getTransaction(): ethers.Transaction {
if (this.transaction) return this.transaction;

let transaction = new ethers.Transaction();

Check failure on line 120 in src/coinbase/transfer.ts

View workflow job for this annotation

GitHub Actions / lint

'transaction' is never reassigned. Use 'const' instead

const rawPayload = this.getUnsignedPayload()
.match(/../g)
?.map(byte => parseInt(byte, 16));
if (!rawPayload) {
throw new InvalidUnsignedPayload("Unable to parse unsigned payload");
}

// TODO: Add try catch block to wrap decoding.
const rawPayloadBytes = new Uint8Array(rawPayload);

const decoder = new TextDecoder();

const parsedPayload = JSON.parse(decoder.decode(rawPayloadBytes));

transaction.chainId = BigInt(parsedPayload["chainId"]);
transaction.nonce = BigInt(parsedPayload["nonce"]);
transaction.maxPriorityFeePerGas = BigInt(parsedPayload["maxPriorityFeePerGas"]);
transaction.maxFeePerGas = BigInt(parsedPayload["maxFeePerGas"]);
transaction.gasLimit = BigInt(parsedPayload["gas"]);
transaction.to = parsedPayload["to"];
transaction.value = BigInt(parsedPayload["value"]);
transaction.data = parsedPayload["input"];

return transaction;
}
}
2 changes: 1 addition & 1 deletion src/coinbase/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class User {

/**
* Initializes a new User instance.
* @param {UserModel} user - The user model.
* @param {UserModel} user - The User model.
* @param {ApiClients} client - The API clients.
*/
constructor(user: UserModel, client: ApiClients) {
Expand Down

0 comments on commit 6090dbd

Please sign in to comment.