Skip to content

Commit

Permalink
feat: gas price for deposit and withdraw tokens (#336)
Browse files Browse the repository at this point in the history
  • Loading branch information
AuHau authored Jun 1, 2021
1 parent 0bb4dcf commit 4a3f837
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 39 deletions.
28 changes: 17 additions & 11 deletions src/bee-debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import type {
LastChequesResponse,
LastChequesForPeerResponse,
LastCashoutActionResponse,
DepositTokensResponse,
WithdrawTokensResponse,
Settlements,
AllSettlements,
RemovePeerResponse,
Expand All @@ -27,7 +25,7 @@ import type {
ChainState,
} from './types'
import { assertBeeUrl, stripLastSlash } from './utils/url'
import { assertAddress, assertInteger, assertNonNegativeInteger } from './utils/type'
import { assertAddress, assertNonNegativeInteger } from './utils/type'
import { CashoutOptions } from './types'

/**
Expand Down Expand Up @@ -190,26 +188,34 @@ export class BeeDebug {
* Deposit tokens from overlay address into chequebook
*
* @param amount Amount of tokens to deposit (must be positive integer)
* @param gasPrice Gas Price in WEI for the transaction call
* @return string Hash of the transaction
*/
async depositTokens(amount: number | bigint): Promise<DepositTokensResponse> {
assertInteger(amount)
async depositTokens(amount: number | bigint, gasPrice?: bigint): Promise<string> {
assertNonNegativeInteger(amount)

if (amount < 0) throw new TypeError('must be positive number')
if (gasPrice) {
assertNonNegativeInteger(gasPrice)
}

return chequebook.depositTokens(this.url, amount)
return chequebook.depositTokens(this.url, amount, gasPrice)
}

/**
* Withdraw tokens from the chequebook to the overlay address
*
* @param amount Amount of tokens to withdraw (must be positive integer)
* @param gasPrice Gas Price in WEI for the transaction call
* @return string Hash of the transaction
*/
async withdrawTokens(amount: number | bigint): Promise<WithdrawTokensResponse> {
assertInteger(amount)
async withdrawTokens(amount: number | bigint, gasPrice?: bigint): Promise<string> {
assertNonNegativeInteger(amount)

if (amount < 0) throw new TypeError('must be positive number')
if (gasPrice) {
assertNonNegativeInteger(gasPrice)
}

return chequebook.withdrawTokens(this.url, amount)
return chequebook.withdrawTokens(this.url, amount, gasPrice)
}

/*
Expand Down
44 changes: 30 additions & 14 deletions src/modules/debug/chequebook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ import type {
ChequebookAddressResponse,
ChequebookBalanceResponse,
LastCashoutActionResponse,
CashoutResponse,
TransactionResponse,
LastChequesForPeerResponse,
LastChequesResponse,
DepositTokensResponse,
WithdrawTokensResponse,
} from '../../types'
import { CashoutOptions } from '../../types'

Expand Down Expand Up @@ -76,7 +74,7 @@ export async function cashoutLastCheque(url: string, peer: string, options?: Cas
headers['gas-limit'] = options.gasLimit.toString()
}

const response = await safeAxios<CashoutResponse>({
const response = await safeAxios<TransactionResponse>({
method: 'post',
url: url + chequebookEndpoint + `/cashout/${peer}`,
responseType: 'json',
Expand Down Expand Up @@ -119,33 +117,51 @@ export async function getLastCheques(url: string): Promise<LastChequesResponse>
/**
* Deposit tokens from overlay address into chequebook
*
* @param url Bee debug url
* @param amount Amount of tokens to deposit
* @param url Bee debug url
* @param amount Amount of tokens to deposit
* @param gasPrice Gas Price in WEI for the transaction call
* @return string Hash of the transaction
*/
export async function depositTokens(url: string, amount: number | bigint): Promise<DepositTokensResponse> {
const response = await safeAxios<DepositTokensResponse>({
export async function depositTokens(url: string, amount: number | bigint, gasPrice?: bigint): Promise<string> {
const headers: Record<string, string> = {}

if (gasPrice) {
headers['gas-price'] = gasPrice.toString()
}

const response = await safeAxios<TransactionResponse>({
method: 'post',
url: url + chequebookEndpoint + '/deposit',
responseType: 'json',
params: { amount: amount.toString(10) },
headers,
})

return response.data
return response.data.transactionHash
}

/**
* Withdraw tokens from the chequebook to the overlay address
*
* @param url Bee debug url
* @param amount Amount of tokens to withdraw
* @param url Bee debug url
* @param amount Amount of tokens to withdraw
* @param gasPrice Gas Price in WEI for the transaction call
* @return string Hash of the transaction
*/
export async function withdrawTokens(url: string, amount: number | bigint): Promise<WithdrawTokensResponse> {
const response = await safeAxios<WithdrawTokensResponse>({
export async function withdrawTokens(url: string, amount: number | bigint, gasPrice?: bigint): Promise<string> {
const headers: Record<string, string> = {}

if (gasPrice) {
headers['gas-price'] = gasPrice.toString()
}

const response = await safeAxios<TransactionResponse>({
method: 'post',
url: url + chequebookEndpoint + '/withdraw',
responseType: 'json',
params: { amount: amount.toString(10) },
headers,
})

return response.data
return response.data.transactionHash
}
9 changes: 1 addition & 8 deletions src/types/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export interface LastCashoutActionResponse {
result: CashoutResult | null
}

export interface CashoutResponse {
export interface TransactionResponse {
transactionHash: string
}

Expand All @@ -76,13 +76,6 @@ export interface LastChequesForPeerResponse {
export interface LastChequesResponse {
lastcheques: LastChequesForPeerResponse[]
}
export interface DepositTokensResponse {
transactionHash: string
}

export interface WithdrawTokensResponse {
transactionHash: string
}

export interface PeerBalance {
peer: string
Expand Down
12 changes: 7 additions & 5 deletions test/integration/modules/debug/chequebook.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import {
withdrawTokens,
} from '../../../../src/modules/debug/chequebook'
import { isPrefixedHexString } from '../../../../src/utils/hex'
import { beeDebugUrl, sleep } from '../../../utils'
import { beeDebugUrl, commonMatchers, sleep } from '../../../utils'

if (process.env.BEE_TEST_CHEQUEBOOK) {
commonMatchers()

describe('swap enabled chequebook', () => {
test('address', async () => {
const response = await getChequebookAddress(beeDebugUrl())
Expand All @@ -19,23 +21,23 @@ if (process.env.BEE_TEST_CHEQUEBOOK) {
test('balance', async () => {
const response = await getChequebookBalance(beeDebugUrl())

expect(typeof response.availableBalance).toBe('bigint')
expect(typeof response.totalBalance).toBe('bigint')
expect(response.availableBalance).toBeType('bigint')
expect(response.totalBalance).toBeType('bigint')
})

const TRANSACTION_TIMEOUT = 20 * 1000

const withDrawDepositTest = (amount: number | bigint) => async () => {
const withdrawResponse = await withdrawTokens(beeDebugUrl(), amount)
expect(typeof withdrawResponse.transactionHash).toBe('string')
expect(withdrawResponse).toBeType('string')

// TODO avoid sleep in tests
// See https://github.com/ethersphere/bee/issues/1191
await sleep(TRANSACTION_TIMEOUT)

const depositResponse = await depositTokens(beeDebugUrl(), amount)

expect(typeof depositResponse.transactionHash).toBe('string')
expect(depositResponse).toBeType('string')

// TODO avoid sleep in tests
// See https://github.com/ethersphere/bee/issues/1191
Expand Down
100 changes: 99 additions & 1 deletion test/unit/bee-debug-class.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assertAllIsDone, cashoutLastChequeMock, MOCK_SERVER_URL } from './nock'
import { assertAllIsDone, cashoutLastChequeMock, depositTokensMock, MOCK_SERVER_URL, withdrawTokensMock } from './nock'
import { BeeArgumentError, BeeDebug } from '../../src'
import { testAddress } from '../utils'

Expand Down Expand Up @@ -103,4 +103,102 @@ describe('BeeDebug class', () => {
await expect(bee.cashoutLastCheque(testAddress, { gasLimit: BigInt('-1') })).rejects.toThrow(BeeArgumentError)
})
})

describe('withdrawTokens', () => {
const TRANSACTION_HASH = '36b7efd913ca4cf880b8eeac5093fa27b0825906c600685b6abdd6566e6cfe8f'
const CASHOUT_RESPONSE = {
transactionHash: TRANSACTION_HASH,
}

it('should not pass headers if no gas price is specified', async () => {
withdrawTokensMock('10').reply(201, CASHOUT_RESPONSE)

const bee = new BeeDebug(MOCK_SERVER_URL)
await expect(bee.withdrawTokens(BigInt('10'))).resolves.toEqual(TRANSACTION_HASH)
assertAllIsDone()
})

it('should pass headers if gas price is specified', async () => {
withdrawTokensMock('10', '100000000000').reply(201, CASHOUT_RESPONSE)

const bee = new BeeDebug(MOCK_SERVER_URL)
await expect(bee.withdrawTokens(BigInt('10'), BigInt('100000000000'))).resolves.toEqual(TRANSACTION_HASH)
assertAllIsDone()
})

it('should throw error if passed wrong amount', async () => {
const bee = new BeeDebug(MOCK_SERVER_URL)

// @ts-ignore: Input testing
await expect(bee.withdrawTokens(true)).rejects.toThrow(TypeError)

// @ts-ignore: Input testing
await expect(bee.withdrawTokens('asd')).rejects.toThrow(TypeError)
// @ts-ignore: Input testing
await expect(bee.withdrawTokens(null)).rejects.toThrow(TypeError)
// @ts-ignore: Input testing
await expect(bee.withdrawTokens()).rejects.toThrow(TypeError)

await expect(bee.withdrawTokens(BigInt('-1'))).rejects.toThrow(BeeArgumentError)
})

it('should throw error if passed wrong gas price input', async () => {
const bee = new BeeDebug(MOCK_SERVER_URL)

// @ts-ignore: Input testing
await expect(bee.withdrawTokens(BigInt('1'), true)).rejects.toThrow(TypeError)
// @ts-ignore: Input testing
await expect(bee.withdrawTokens(BigInt('1'), 'asd')).rejects.toThrow(TypeError)
await expect(bee.withdrawTokens(BigInt('1'), BigInt('-1'))).rejects.toThrow(BeeArgumentError)
})
})

describe('depositTokens', () => {
const TRANSACTION_HASH = '36b7efd913ca4cf880b8eeac5093fa27b0825906c600685b6abdd6566e6cfe8f'
const CASHOUT_RESPONSE = {
transactionHash: TRANSACTION_HASH,
}

it('should not pass headers if no gas price is specified', async () => {
depositTokensMock('10').reply(201, CASHOUT_RESPONSE)

const bee = new BeeDebug(MOCK_SERVER_URL)
await expect(bee.depositTokens(BigInt('10'))).resolves.toEqual(TRANSACTION_HASH)
assertAllIsDone()
})

it('should pass headers if gas price is specified', async () => {
depositTokensMock('10', '100000000000').reply(201, CASHOUT_RESPONSE)

const bee = new BeeDebug(MOCK_SERVER_URL)
await expect(bee.depositTokens(BigInt('10'), BigInt('100000000000'))).resolves.toEqual(TRANSACTION_HASH)
assertAllIsDone()
})

it('should throw error if passed wrong amount', async () => {
const bee = new BeeDebug(MOCK_SERVER_URL)

// @ts-ignore: Input testing
await expect(bee.depositTokens(true)).rejects.toThrow(TypeError)

// @ts-ignore: Input testing
await expect(bee.depositTokens('asd')).rejects.toThrow(TypeError)
// @ts-ignore: Input testing
await expect(bee.depositTokens(null)).rejects.toThrow(TypeError)
// @ts-ignore: Input testing
await expect(bee.depositTokens()).rejects.toThrow(TypeError)

await expect(bee.depositTokens(BigInt('-1'))).rejects.toThrow(BeeArgumentError)
})

it('should throw error if passed wrong gas price input', async () => {
const bee = new BeeDebug(MOCK_SERVER_URL)

// @ts-ignore: Input testing
await expect(bee.depositTokens(BigInt('1'), true)).rejects.toThrow(TypeError)
// @ts-ignore: Input testing
await expect(bee.depositTokens(BigInt('1'), 'asd')).rejects.toThrow(TypeError)
await expect(bee.depositTokens(BigInt('1'), BigInt('-1'))).rejects.toThrow(BeeArgumentError)
})
})
})
24 changes: 24 additions & 0 deletions test/unit/nock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,27 @@ export function cashoutLastChequeMock(peer: string, gasPrice?: string, gasLimit?
reqheaders: headers,
}).post(`${CHEQUEBOOK_ENDPOINT}/cashout/${peer}`)
}

export function depositTokensMock(amount: string, gasPrice?: string): nock.Interceptor {
const headers: Record<string, string> = {}

if (gasPrice) {
headers['gas-price'] = gasPrice
}

return nock(MOCK_SERVER_URL, {
reqheaders: headers,
}).post(`${CHEQUEBOOK_ENDPOINT}/deposit?amount=${amount}`)
}

export function withdrawTokensMock(amount: string, gasPrice?: string): nock.Interceptor {
const headers: Record<string, string> = {}

if (gasPrice) {
headers['gas-price'] = gasPrice
}

return nock(MOCK_SERVER_URL, {
reqheaders: headers,
}).post(`${CHEQUEBOOK_ENDPOINT}/withdraw?amount=${amount}`)
}

0 comments on commit 4a3f837

Please sign in to comment.