Skip to content

Commit

Permalink
Rectifying merge conflicts after rebasing
Browse files Browse the repository at this point in the history
  • Loading branch information
marcin-cb committed Jun 20, 2024
1 parent a133218 commit 3af3c22
Show file tree
Hide file tree
Showing 9 changed files with 475 additions and 1,130 deletions.
174 changes: 32 additions & 142 deletions src/client/api.ts

Large diffs are not rendered by default.

105 changes: 51 additions & 54 deletions src/coinbase/address/developer_address.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import { Decimal } from "decimal.js";
import { ethers } from "ethers";
import { Address } from "../address";
import { Address as AddressModel } from "../../client";
import { ethers } from "ethers";
import { ArgumentError, InternalError } from "../errors";
import { Asset } from "../asset";
import { Balance } from "../balance";
import { BalanceMap } from "../balance_map";
import { Coinbase } from "../coinbase";
import { Transfer } from "../transfer";
import { ArgumentError, InternalError } from "../errors";
import { FaucetTransaction } from "../faucet_transaction";
import {
convertAmount,
delay,
destinationToAddressHexString,
getNormalizedAssetId,
} from "../utils";
import { Amount, Destination, TransferStatus } from "../types";
import { Asset } from "../asset";
import { Trade } from "../trade";
import { Transfer } from "../transfer";
import { Amount, Destination, TransferStatus } from "../types";
import { delay } from "../utils";
import { Wallet as WalletClass } from "../wallet";

/**
* A representation of a blockchain address, which is a developer-controlled account on a network.
Expand Down Expand Up @@ -93,13 +89,11 @@ export class DeveloperAddress extends Address {
* @param {string} assetId - The asset ID.
* @returns {Decimal} The balance of the asset.
*/
public async getBalance(assetId: string): Promise<Decimal> {
const normalizedAssetId = getNormalizedAssetId(assetId);

async getBalance(assetId: string): Promise<Decimal> {
const response = await Coinbase.apiClients.address!.getAddressBalance(
this._model.wallet_id,
this._model.address_id,
normalizedAssetId,
Asset.primaryDenomination(assetId),
);

if (!response.data) {
Expand Down Expand Up @@ -180,35 +174,23 @@ export class DeveloperAddress extends Address {
if (!Coinbase.useServerSigner && !this._key) {
throw new InternalError("Cannot transfer from address without private key loaded");
}
let normalizedAmount = new Decimal(amount.toString());
const asset = await Asset.fetch(this.getNetworkId(), assetId);
const [destinationAddress, destinationNetworkId] =
this.getDestinationAddressAndNetwork(destination);

const normalizedAmount = new Decimal(amount.toString());
const currentBalance = await this.getBalance(assetId);
if (currentBalance.lessThan(normalizedAmount)) {
throw new ArgumentError(
`Insufficient funds: ${normalizedAmount} requested, but only ${currentBalance} available`,
);
}

normalizedAmount = convertAmount(normalizedAmount, assetId);

const normalizedDestination = destinationToAddressHexString(destination);

const normalizedAssetId = ((): string => {
switch (assetId) {
case Coinbase.assets.Gwei:
return Coinbase.assets.Eth;
case Coinbase.assets.Wei:
return Coinbase.assets.Eth;
default:
return assetId;
}
})();

const createTransferRequest = {
amount: normalizedAmount.toFixed(0),
network_id: this.getNetworkId(),
asset_id: normalizedAssetId,
destination: normalizedDestination,
amount: asset.toAtomicAmount(normalizedAmount).toString(),
network_id: destinationNetworkId,
asset_id: asset.primaryDenomination(),
destination: destinationAddress,
};

let response = await Coinbase.apiClients.transfer!.createTransfer(
Expand Down Expand Up @@ -251,6 +233,25 @@ export class DeveloperAddress extends Address {
throw new Error("Transfer timed out");
}

/**
* Returns the address and network ID of the given destination.
*
* @param destination - The destination to get the address and network ID of.
* @returns The address and network ID of the destination.
*/
private getDestinationAddressAndNetwork(destination: Destination): [string, string] {
if (typeof destination !== "string" && destination.getNetworkId() !== this.getNetworkId()) {
throw new ArgumentError("Transfer must be on the same Network");
}
if (destination instanceof WalletClass) {
return [destination.getDefaultAddress()!.getId(), destination.getNetworkId()];
}
if (destination instanceof Address) {
return [destination.getId(), destination.getNetworkId()];
}
return [destination, this.getNetworkId()];
}

/**
* Returns whether the Address has a private key backing it to sign transactions.
*
Expand All @@ -264,15 +265,18 @@ export class DeveloperAddress extends Address {
* Trades the given amount of the given Asset for another Asset. Only same-network Trades are supported.
*
* @param amount - The amount of the Asset to send.
* @param fromAssetId - The ID of the Asset to trade from. For Ether, eth, gwei, and wei are supported.
* @param toAssetId - The ID of the Asset to trade to. For Ether, eth, gwei, and wei are supported.
* @param fromAssetId - The ID of the Asset to trade from.
* @param toAssetId - The ID of the Asset to trade to.
* @returns The Trade object.
* @throws {Error} If the private key is not loaded, or if the asset IDs are unsupported, or if there are insufficient funds.
*/
public async createTrade(amount: Amount, fromAssetId: string, toAssetId: string): Promise<Trade> {
await this.validateCanTrade(amount, fromAssetId, toAssetId);
const trade = await this.createTradeRequest(amount, fromAssetId, toAssetId);
const fromAsset = await Asset.fetch(this.getNetworkId(), fromAssetId);
const toAsset = await Asset.fetch(this.getNetworkId(), toAssetId);
const wallet = new ethers.Wallet(this._key!.privateKey);

await this.validateCanTrade(amount, fromAssetId);
const trade = await this.createTradeRequest(amount, fromAsset, toAsset);
// NOTE: Trading does not yet support server signers at this point.
const signed_payload = await trade.getTransaction().sign(wallet);
const approveTransactionSignedPayload = trade.getApproveTransaction()
Expand All @@ -286,19 +290,19 @@ export class DeveloperAddress extends Address {
* Creates a trade model for the specified amount and assets.
*
* @param amount - The amount of the Asset to send.
* @param fromAssetId - The ID of the Asset to trade from. For Ether, eth, gwei, and wei are supported.
* @param toAssetId - The ID of the Asset to trade to. For Ether, eth, gwei, and wei are supported.
* @param fromAsset - The Asset to trade from.
* @param toAsset - The Asset to trade to.
* @returns A promise that resolves to a Trade object representing the new trade.
*/
private async createTradeRequest(
amount: Amount,
fromAssetId: string,
toAssetId: string,
fromAsset: Asset,
toAsset: Asset,
): Promise<Trade> {
const tradeRequestPayload = {
amount: Asset.toAtomicAmount(new Decimal(amount.toString()), fromAssetId).toString(),
from_asset_id: Asset.primaryDenomination(fromAssetId),
to_asset_id: Asset.primaryDenomination(toAssetId),
amount: fromAsset.toAtomicAmount(new Decimal(amount.toString())).toString(),
from_asset_id: fromAsset.primaryDenomination(),
to_asset_id: toAsset.primaryDenomination(),
};
const tradeModel = await Coinbase.apiClients.trade!.createTrade(
this.getWalletId(),
Expand Down Expand Up @@ -343,19 +347,12 @@ export class DeveloperAddress extends Address {
*
* @param amount - The amount of the Asset to send.
* @param fromAssetId - The ID of the Asset to trade from. For Ether, eth, gwei, and wei are supported.
* @param toAssetId - The ID of the Asset to trade to. For Ether, eth, gwei, and wei are supported.
* @throws {Error} If the private key is not loaded, or if the asset IDs are unsupported, or if there are insufficient funds.
*/
private async validateCanTrade(amount: Amount, fromAssetId: string, toAssetId: string) {
private async validateCanTrade(amount: Amount, fromAssetId: string) {
if (!this.canSign()) {
throw new Error("Cannot trade from address without private key loaded");
}
if (!Asset.isSupported(fromAssetId)) {
throw new Error(`Unsupported from asset: ${fromAssetId}`);
}
if (!Asset.isSupported(toAssetId)) {
throw new Error(`Unsupported to asset: ${toAssetId}`);
}
const currentBalance = await this.getBalance(fromAssetId);
amount = new Decimal(amount.toString());
if (currentBalance.lessThan(amount)) {
Expand Down
15 changes: 7 additions & 8 deletions src/coinbase/address/external_address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,15 +198,13 @@ export class ExternalAddress extends Address {

const response = await Coinbase.apiClients.stake!.getStakingContext(request);
const { claimable_balance, stakeable_balance, unstakeable_balance } = response!.data.context;
const asset = await Asset.fetch(this.getNetworkId(), assetId);

return {
claimableBalance: Asset.fromAtomicAmount(new Decimal(claimable_balance), assetId)
.toFixed()
.toString(),
stakeableBalance: Asset.fromAtomicAmount(new Decimal(stakeable_balance), assetId)
.toFixed()
.toString(),
unstakeableBalance: Asset.fromAtomicAmount(new Decimal(unstakeable_balance), assetId)
claimableBalance: asset.fromAtomicAmount(new Decimal(claimable_balance)).toFixed().toString(),
stakeableBalance: asset.fromAtomicAmount(new Decimal(stakeable_balance)).toFixed().toString(),
unstakeableBalance: asset
.fromAtomicAmount(new Decimal(unstakeable_balance))
.toFixed()
.toString(),
};
Expand All @@ -233,8 +231,9 @@ export class ExternalAddress extends Address {
if (stakingAmount.lessThanOrEqualTo(0)) {
throw new Error(`Amount required greater than zero.`);
}
const asset = await Asset.fetch(this.getNetworkId(), assetId);

options.amount = Asset.toAtomicAmount(new Decimal(amount.toString()), assetId).toString();
options.amount = asset.toAtomicAmount(new Decimal(amount.toString())).toString();

const request = {
network_id: this.getNetworkId(),
Expand Down
19 changes: 0 additions & 19 deletions src/coinbase/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,25 +82,6 @@ export async function delay(seconds: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, seconds * 1000));
}

/**
* Converts a Destination to an Address hex string.
*
* @param destination - The Destination to convert.
* @returns The Address Hex string.
* @throws {Error} If the Destination is an unsupported type.
*/
export function destinationToAddressHexString(destination: Destination): string {
if (typeof destination === "string") {
return destination;
} else if (destination instanceof Address) {
return destination.getId();
} else if (destination instanceof Wallet) {
return destination.getDefaultAddress()!.getId();
} else {
throw new Error("Unsupported type");
}
}

/**
* Parses an Unsigned Payload and returns the JSON object.
*
Expand Down
Loading

0 comments on commit 3af3c22

Please sign in to comment.