Skip to content

Commit 57423a5

Browse files
committed
feat: errors, add utils, signup
Refactoring of error handler and returning data format Added: tokenApproval, isTokenTransferApproved, signup, renewToken
1 parent dbc4b4b commit 57423a5

10 files changed

+148
-148
lines changed

README.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,11 @@ For the functions that modify the marketplace state (like creating a new request
5454

5555
All the features of the API will be available after initializing the Marketplace object, using a valid API secret Key.
5656

57-
To get an API secret key, it's necessary to send to **https://ethdenver-api.aave.com/signup** a POST request with the body:
57+
To get an API secret key, it's necessary to send to **https://ethdenver-api.aave.com/auth/signup** a POST request with the body:
5858
```
5959
{
60+
"name": "my name",
61+
"company": "company name", // optional
6062
"email": "[email protected]",
6163
"password": "my-secret-password"
6264
}
@@ -228,4 +230,4 @@ const await.marketplace.utils.refreshCollateralPrice(loanAddress);
228230

229231
## LICENSE
230232

231-
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
233+
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.

src/aave-js.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
// Import here Polyfills if needed. Recommended core-js (npm i -D core-js)
22
// import "core-js/fn/array.find"
33
// ...
4-
// tslint:disable-next-line
5-
import Web3 from 'web3'
64

75
import { LoanAPIInstance } from './types'
86
import LoanRequest from './services/LoanRequest'
7+
import Utils from './services/Utils'
98

109
export class Marketplace implements Marketplace {
1110
public requests: LoanAPIInstance
11+
public utils: Utils
1212

13-
constructor(token: string, web3?: Web3, apiUrl?: string) {
14-
this.requests = new LoanRequest(token, web3, apiUrl)
13+
constructor(token: string, apiUrl?: string) {
14+
this.requests = new LoanRequest(token, apiUrl)
15+
this.utils = new Utils(token, apiUrl)
1516
}
1617
}

src/services/BaseService.ts

+21-29
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import axios, { AxiosError, AxiosInstance } from 'axios'
22
import { isValidChecksumAddress } from 'ethereumjs-util'
3-
// tslint:disable-next-line
4-
import Web3 from 'web3'
53

6-
import { BaseResponse } from '../types'
7-
import { Transaction } from 'web3/eth/types'
8-
import { TransactionReceipt } from 'web3-core/types'
4+
class ServiceError extends Error {
5+
public code: number
6+
constructor(message: string, code: number) {
7+
super(message)
8+
this.code = code
9+
}
10+
}
911

1012
export default class BaseService {
1113
protected readonly api: AxiosInstance
12-
protected readonly web3?: Web3
1314

14-
constructor(token: string, web3?: Web3, apiUrl?: string) {
15+
constructor(token: string, apiUrl?: string) {
1516
this.api = axios.create({
1617
baseURL: apiUrl || 'https://api.aave.com',
1718
headers: { Authorization: `Bearer ${token}` }
1819
})
19-
this.web3 = web3
2020
}
2121

2222
protected static checkAddressChecksum(address: string): void {
@@ -25,18 +25,22 @@ export default class BaseService {
2525
}
2626
}
2727

28-
protected static errorHandler(e: AxiosError, resourceType: string, address: string = ''): BaseResponse {
28+
protected static errorHandler(e: AxiosError, resourceType: string, address: string = ''): ServiceError {
2929
const status = e.response ? e.response.status : 504
3030

3131
switch (status) {
32-
case 404:
33-
return { error: `${resourceType} ${address} doesn't exists`, code: 404 }
32+
case 400: {
33+
const errorText = e.response && e.response.data && e.response.data.error ? e.response.data.error : ''
34+
return new ServiceError(`bad request: ${errorText}`, 400)
35+
}
3436
case 401:
35-
return { error: 'invalid access token', code: 401 }
37+
return new ServiceError('invalid access token', 401)
38+
case 404:
39+
return new ServiceError(`${resourceType} ${address} doesn't exists`, 404)
3640
case 504:
37-
return { error: 'probably some troubles with network connection', code: 504 }
41+
return new ServiceError('probably some troubles with network connection', 504)
3842
default:
39-
return { error: 'internal server error, please contact support', code: 500 }
43+
return new ServiceError('internal server error, please contact support', 500)
4044
}
4145
}
4246

@@ -46,26 +50,14 @@ export default class BaseService {
4650
errorParam: string = '',
4751
method: 'get' | 'post' = 'get',
4852
params?: object
49-
): Promise<BaseResponse> {
53+
): Promise<any> {
5054
const api = method === 'post' ? this.api.post : this.api.get
5155

5256
try {
5357
const { data } = await api(endpoint, params)
54-
55-
return { data, code: 200 }
58+
return data
5659
} catch (e) {
57-
return BaseService.errorHandler(e, resourceType, errorParam)
58-
}
59-
}
60-
61-
private async sendTransaction(tx: Transaction): Promise<TransactionReceipt> {
62-
if (this.web3) {
63-
const currentNetwork = await this.web3.eth.net.getNetworkType()
64-
if (currentNetwork === 'kovan') {
65-
return await this.web3.eth.sendTransaction(tx)
66-
}
67-
throw `this version of API allows transactions only on kovan network, but ${currentNetwork} chosen`
60+
throw BaseService.errorHandler(e, resourceType, errorParam)
6861
}
69-
throw 'web3 provider is not specified'
7062
}
7163
}

src/services/LoanRequest.ts

+28-28
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,20 @@
1-
// tslint:disable-next-line
2-
import Web3 from 'web3'
3-
4-
import {
5-
LoanTransactionResponse,
6-
LoanMetadataResponse,
7-
LoanRequestResponse,
8-
LoanAddressesByBorrowerResponse,
9-
LoansAddressesResponse,
10-
LoanAPIInstance,
11-
BaseLoanModel,
12-
MaxLoanAmountResponse
13-
} from '../types'
1+
import { Transaction } from 'web3/eth/types'
2+
3+
import { LoanAPIInstance, BaseLoanModel, LoanRequestModel, LoanMetadata } from '../types'
144
import BaseService from './BaseService'
155

166
export default class LoanRequest extends BaseService implements LoanAPIInstance {
17-
constructor(token: string, web3?: Web3, apiUrl?: string) {
18-
super(token, web3, apiUrl)
7+
constructor(token: string, apiUrl?: string) {
8+
super(token, apiUrl)
9+
}
10+
public async approve(amount: number, tokenSymbol: string): Promise<Transaction> {
11+
return await this.apiRequest('/request/approveTransfer', 'token approval', tokenSymbol, 'post', {
12+
amount,
13+
tokenSymbol
14+
})
1915
}
2016

21-
public async create(borrowerWalletAddress: string, params: BaseLoanModel): Promise<LoanTransactionResponse> {
17+
public async create(borrowerWalletAddress: string, params: BaseLoanModel): Promise<Transaction> {
2218
BaseService.checkAddressChecksum(borrowerWalletAddress)
2319

2420
return await this.apiRequest('/request', 'loan requests creation', '', 'post', {
@@ -27,7 +23,7 @@ export default class LoanRequest extends BaseService implements LoanAPIInstance
2723
})
2824
}
2925

30-
public async placeCollateral(loanAddress: string, borrowerAddress: string): Promise<LoanTransactionResponse> {
26+
public async placeCollateral(loanAddress: string, borrowerAddress: string): Promise<Transaction> {
3127
BaseService.checkAddressChecksum(loanAddress)
3228
BaseService.checkAddressChecksum(borrowerAddress)
3329

@@ -39,7 +35,7 @@ export default class LoanRequest extends BaseService implements LoanAPIInstance
3935
)
4036
}
4137

42-
public async fund(loanAddress: string, lenderAddress: string, amount: number): Promise<LoanTransactionResponse> {
38+
public async fund(loanAddress: string, lenderAddress: string, amount: number): Promise<Transaction> {
4339
BaseService.checkAddressChecksum(loanAddress)
4440
BaseService.checkAddressChecksum(lenderAddress)
4541

@@ -51,7 +47,7 @@ export default class LoanRequest extends BaseService implements LoanAPIInstance
5147
)
5248
}
5349

54-
public async payback(loanAddress: string, borrowerAddress: string): Promise<LoanTransactionResponse> {
50+
public async payback(loanAddress: string, borrowerAddress: string): Promise<Transaction> {
5551
BaseService.checkAddressChecksum(loanAddress)
5652
BaseService.checkAddressChecksum(borrowerAddress)
5753

@@ -65,28 +61,26 @@ export default class LoanRequest extends BaseService implements LoanAPIInstance
6561
public async getMaxLoanAmountFromCollateral(
6662
collateralAmount: number,
6763
collateralType: string,
68-
moe: string,
69-
ltv?: number
70-
): Promise<MaxLoanAmountResponse> {
64+
moe: string
65+
): Promise<number> {
7166
return await this.apiRequest('/request/maxamount/', 'getting max loan amount', collateralType, 'post', {
7267
collateralAmount,
7368
collateralType,
74-
moe,
75-
ltv
69+
moe
7670
})
7771
}
7872

79-
public async getLoanData(loanAddress: string): Promise<LoanRequestResponse> {
73+
public async getLoanData(loanAddress: string): Promise<LoanRequestModel> {
8074
BaseService.checkAddressChecksum(loanAddress)
8175

8276
return await this.apiRequest(`/request/getone/${loanAddress}`, 'loan requests', loanAddress)
8377
}
8478

85-
public async getAllAddresses(): Promise<LoansAddressesResponse> {
79+
public async getAllAddresses(): Promise<string[]> {
8680
return await this.apiRequest('/request', 'loan requests addresses')
8781
}
8882

89-
public async getLoansByBorrower(borrowerAddress: string): Promise<LoanAddressesByBorrowerResponse> {
83+
public async getLoansByBorrower(borrowerAddress: string): Promise<string[]> {
9084
BaseService.checkAddressChecksum(borrowerAddress)
9185

9286
return await this.apiRequest(
@@ -96,7 +90,13 @@ export default class LoanRequest extends BaseService implements LoanAPIInstance
9690
)
9791
}
9892

99-
public async getMetadata(): Promise<LoanMetadataResponse> {
93+
public async getLoansByLender(lenderAddress: string): Promise<string[]> {
94+
BaseService.checkAddressChecksum(lenderAddress)
95+
96+
return await this.apiRequest(`/request/getlistbylender/${lenderAddress}`, 'loan addresses by lender', lenderAddress)
97+
}
98+
99+
public async getMetadata(): Promise<LoanMetadata> {
100100
return await this.apiRequest('/request/metadata', 'loan requests metadata')
101101
}
102102
}

src/services/Utils.ts

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Transaction } from 'web3/eth/types'
2+
3+
import BaseService from './BaseService'
4+
5+
export default class Utils extends BaseService {
6+
constructor(token: string, apiUrl?: string) {
7+
super(token, apiUrl)
8+
}
9+
public async approveTransfer(address: string, tokenSymbol: string): Promise<Transaction> {
10+
return await this.apiRequest('/common/approvetransfer/', 'token approval', tokenSymbol, 'post', {
11+
address,
12+
token: tokenSymbol
13+
})
14+
}
15+
16+
public async isTransferApproved(address: string, tokenSymbol: string, amount: number): Promise<boolean> {
17+
return await this.apiRequest(
18+
`/common/istransferapproved/${address}/${tokenSymbol}/${amount}`,
19+
'is token transfer approved'
20+
)
21+
}
22+
23+
public async signup(email: string, name: string, password: string, organisation?: string): Promise<string> {
24+
return await this.apiRequest('/auth/signup', 'signup', '', 'post', { email, name, password, organisation })
25+
}
26+
27+
public async renewToken(email: string, password: string): Promise<string> {
28+
return await this.apiRequest('/auth/renewtoken', 'token renewal', '', 'post', { email, password })
29+
}
30+
}

src/types.ts

+12-47
Original file line numberDiff line numberDiff line change
@@ -34,57 +34,22 @@ export interface LoanRequestModel extends BaseLoanModel {
3434
isCrowdLendingLoan: boolean
3535
peggedCurrency?: string
3636
peggedMedium?: string
37+
nextInstalmentAmount?: number
3738
type: string
3839
}
3940

40-
export interface BaseResponse {
41-
data?: any
42-
error?: string
43-
code: ResponseCodes
44-
}
45-
46-
export interface MaxLoanAmountResponse extends BaseResponse {
47-
data?: number
48-
}
49-
50-
export interface LoanTransactionResponse extends BaseResponse {
51-
data?: Transaction
52-
}
53-
54-
export interface LoanRequestResponse extends BaseResponse {
55-
data?: LoanRequestModel
56-
}
57-
58-
export interface LoanMetadataResponse extends BaseResponse {
59-
data?: LoanMetadata
60-
}
61-
62-
export interface LoansAddressesResponse extends BaseResponse {
63-
data?: string[]
64-
}
65-
66-
export interface LoanAddressesByBorrowerResponse extends BaseResponse {
67-
data?: {
68-
requestsAsBorrower: string[]
69-
requestsAsLender: string[]
70-
}
71-
}
72-
7341
export interface LoanAPIInstance {
74-
create(creatorWalletAddress: string, params: BaseLoanModel): Promise<LoanTransactionResponse>
75-
placeCollateral(loanAddress: string, borrowerAddress: string): Promise<LoanTransactionResponse>
76-
fund(loanAddress: string, lenderAddress: string, amount: number): Promise<LoanTransactionResponse>
77-
payback(loanAddress: string, borrowerAddress: string): Promise<LoanTransactionResponse>
78-
getMaxLoanAmountFromCollateral(
79-
collateralAmount: number,
80-
collateralType: string,
81-
moe: string,
82-
ltv?: number
83-
): Promise<MaxLoanAmountResponse>
84-
getLoanData(loanAddress: string): Promise<LoanRequestResponse>
85-
getAllAddresses(): Promise<LoansAddressesResponse>
86-
getLoansByBorrower(borrowerAddress: string): Promise<LoanAddressesByBorrowerResponse>
87-
getMetadata(): Promise<LoanMetadataResponse>
42+
approve(amount: number, tokenSymbol: string): Promise<Transaction>
43+
create(creatorWalletAddress: string, params: BaseLoanModel): Promise<Transaction>
44+
placeCollateral(loanAddress: string, borrowerAddress: string): Promise<Transaction>
45+
fund(loanAddress: string, lenderAddress: string, amount: number): Promise<Transaction>
46+
payback(loanAddress: string, borrowerAddress: string): Promise<Transaction>
47+
getMaxLoanAmountFromCollateral(collateralAmount: number, collateralType: string, moe: string): Promise<number>
48+
getLoanData(loanAddress: string): Promise<LoanRequestModel>
49+
getAllAddresses(): Promise<string[]>
50+
getLoansByBorrower(borrowerAddress: string): Promise<string[]>
51+
getLoansByLender(lenderAddress: string): Promise<string[]>
52+
getMetadata(): Promise<LoanMetadata>
8853
}
8954

9055
export interface MarketplaceInstance {

test/BaseService.test.ts

+1-25
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ describe('BaseService tests', () => {
2727
response: { status, data: null, headers: null, statusText: '', config: {} }
2828
})
2929
it('should return correct error codes', () => {
30-
for (const status of [401, 404, 500, 504]) {
30+
for (const status of [400, 401, 404, 500, 504]) {
3131
expect(BaseService['errorHandler'](axiosErrorMock(status), 'type').code).toBe(status)
3232
}
3333
})
@@ -42,28 +42,4 @@ describe('BaseService tests', () => {
4242
)
4343
})
4444
})
45-
46-
describe('sendTransaction method', () => {
47-
it('should send transaction', async () => {
48-
const tx = { some: 1 }
49-
const web3Mock = <any>{
50-
eth: {
51-
sendTransaction: async (tx: any) => Promise.resolve(tx),
52-
net: { getNetworkType: async () => Promise.resolve('kovan') }
53-
}
54-
}
55-
const service = new BaseService('token', web3Mock)
56-
await expect(service['sendTransaction'](<any>tx)).resolves.toEqual(tx)
57-
})
58-
59-
it('should raise exception if now web3 specified', async () => {
60-
await expect(defaultService['sendTransaction'](<any>{})).rejects.toBe('web3 provider is not specified')
61-
})
62-
63-
it('should raise exception on incorrect network', async () => {
64-
const web3Mock = <any>{ eth: { net: { getNetworkType: async () => Promise.resolve('main') } } }
65-
const service = new BaseService('86C019FF04C4', web3Mock)
66-
await expect(service['sendTransaction'](<any>{})).rejects.toBeTruthy()
67-
})
68-
})
6945
})

0 commit comments

Comments
 (0)