Skip to content

Commit b0910ec

Browse files
authored
Merge pull request #843 from rsksmart/feature/FLY-2046
Feature/FLY-2046 - Recommended PegIn/PegOut endpoints
2 parents 1445e72 + d7d04fe commit b0910ec

33 files changed

+1785
-19
lines changed

.mockery.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ packages:
4444
SetGeneralConfigUseCase:
4545
GetPegoutReportUseCase:
4646
GetPeginReportUseCase:
47+
RecommendedPegoutUseCase:
48+
RecommendedPeginUseCase:
4749
GetRevenueReportUseCase:
4850
github.com/rsksmart/liquidity-provider-server/internal/entities/liquidity_provider:
4951
interfaces:

OpenApi.yml

Lines changed: 124 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,11 @@ components:
159159
GetTransactionsItem:
160160
properties:
161161
amount:
162-
$ref: '#/components/schemas/Wei'
162+
$ref: '#/components/schemas/'
163163
callFee:
164-
$ref: '#/components/schemas/Wei'
164+
$ref: '#/components/schemas/'
165165
gasFee:
166-
$ref: '#/components/schemas/Wei'
166+
$ref: '#/components/schemas/'
167167
quoteHash:
168168
type: string
169169
status:
@@ -175,11 +175,11 @@ components:
175175
items:
176176
properties:
177177
amount:
178-
$ref: '#/components/schemas/Wei'
178+
$ref: '#/components/schemas/'
179179
callFee:
180-
$ref: '#/components/schemas/Wei'
180+
$ref: '#/components/schemas/'
181181
gasFee:
182-
$ref: '#/components/schemas/Wei'
182+
$ref: '#/components/schemas/'
183183
quoteHash:
184184
type: string
185185
status:
@@ -574,8 +574,8 @@ components:
574574
ProviderDetail:
575575
properties:
576576
fee:
577-
$ref: '#/components/schemas/'
578577
deprecated: true
578+
$ref: '#/components/schemas/'
579579
feePercentage:
580580
type: number
581581
fixedFee:
@@ -612,6 +612,29 @@ components:
612612
- pegin
613613
- pegout
614614
type: object
615+
RecommendedOperationDTO:
616+
properties:
617+
estimatedCallFee:
618+
description: Estimated call fee if a quote is created with the recommended
619+
amount
620+
example: "100000"
621+
estimatedGasFee:
622+
description: Estimated gas fee if a quote is created with the recommended
623+
amount
624+
example: "100000"
625+
estimatedProductFee:
626+
description: Estimated product fee if a quote is created with the recommended
627+
amount
628+
example: "100000"
629+
recommendedQuoteValue:
630+
description: Recommended quote value for the input amount
631+
example: "100000"
632+
required:
633+
- recommendedQuoteValue
634+
- estimatedCallFee
635+
- estimatedGasFee
636+
- estimatedProductFee
637+
type: object
615638
RetainedPeginQuoteDTO:
616639
properties:
617640
callForUserTxHash:
@@ -779,8 +802,6 @@ components:
779802
rbtcLockingCap:
780803
$ref: '#/components/schemas/'
781804
type: object
782-
Wei: {}
783-
entities.Wei: {}
784805
pkg.AcceptAuthenticatedQuoteRequest:
785806
properties:
786807
quoteHash:
@@ -853,6 +874,29 @@ components:
853874
required:
854875
- collateral
855876
type: object
877+
pkg.RecommendedOperationDTO:
878+
properties:
879+
estimatedCallFee:
880+
description: Estimated call fee if a quote is created with the recommended
881+
amount
882+
example: "100000"
883+
estimatedGasFee:
884+
description: Estimated gas fee if a quote is created with the recommended
885+
amount
886+
example: "100000"
887+
estimatedProductFee:
888+
description: Estimated product fee if a quote is created with the recommended
889+
amount
890+
example: "100000"
891+
recommendedQuoteValue:
892+
description: Recommended quote value for the input amount
893+
example: "100000"
894+
required:
895+
- recommendedQuoteValue
896+
- estimatedCallFee
897+
- estimatedGasFee
898+
- estimatedProductFee
899+
type: object
856900
pkg.TrustedAccountRequest:
857901
properties:
858902
address:
@@ -1079,6 +1123,45 @@ paths:
10791123
$ref: '#/components/schemas/GetPeginQuoteResponse'
10801124
description: ""
10811125
summary: Pegin GetQuote
1126+
/pegin/recommended:
1127+
get:
1128+
description: ' Returns the recommended quote value to create a quote whose total
1129+
payment is the input amount'
1130+
parameters:
1131+
- description: Amount in wei expected to use as total payment for the quote
1132+
in: query
1133+
name: amount
1134+
required: true
1135+
schema:
1136+
description: Amount in wei expected to use as total payment for the quote
1137+
format: string
1138+
type: string
1139+
- description: Destination address for the pegin. Is optional, but if provided,
1140+
it will increase the estimation accuracy.
1141+
in: query
1142+
name: destination_address
1143+
schema:
1144+
description: Destination address for the pegin. Is optional, but if provided,
1145+
it will increase the estimation accuracy.
1146+
format: string
1147+
type: string
1148+
- description: Hex-encoded data payload to include in the pegin transaction.
1149+
Is optional, but if provided, it will increase the estimation accuracy.
1150+
in: query
1151+
name: data
1152+
schema:
1153+
description: Hex-encoded data payload to include in the pegin transaction.
1154+
Is optional, but if provided, it will increase the estimation accuracy.
1155+
format: string
1156+
type: string
1157+
responses:
1158+
"200":
1159+
content:
1160+
application/json:
1161+
schema:
1162+
$ref: '#/components/schemas/RecommendedOperationDTO'
1163+
description: Recommended operation object
1164+
summary: Recommended pegin
10821165
/pegin/status:
10831166
get:
10841167
description: ' Returns the status of an accepted pegin quote'
@@ -1192,6 +1275,38 @@ paths:
11921275
$ref: '#/components/schemas/GetPegoutQuoteResponse'
11931276
description: ""
11941277
summary: Pegout GetQuote
1278+
/pegout/recommended:
1279+
get:
1280+
description: ' Returns the recommended quote value to create a quote whose total
1281+
payment is the input amount'
1282+
parameters:
1283+
- description: Amount in wei expected to use as total payment for the quote
1284+
in: query
1285+
name: amount
1286+
required: true
1287+
schema:
1288+
description: Amount in wei expected to use as total payment for the quote
1289+
format: string
1290+
type: string
1291+
- description: 'Destination address type for the pegout. Is optional, but if
1292+
provided, it will increase the estimation accuracy. Must be one of: p2pkh,
1293+
p2sh, p2wpkh, p2wsh, p2tr'
1294+
in: query
1295+
name: destination_type
1296+
schema:
1297+
description: 'Destination address type for the pegout. Is optional, but
1298+
if provided, it will increase the estimation accuracy. Must be one of:
1299+
p2pkh, p2sh, p2wpkh, p2wsh, p2tr'
1300+
format: string
1301+
type: string
1302+
responses:
1303+
"200":
1304+
content:
1305+
application/json:
1306+
schema:
1307+
$ref: '#/components/schemas/RecommendedOperationDTO'
1308+
description: Recommended operation object
1309+
summary: Recommended pegout
11951310
/pegout/status:
11961311
get:
11971312
description: ' Returns the status of an accepted pegout quote'
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package bitcoin
2+
3+
import (
4+
"errors"
5+
"github.com/rsksmart/liquidity-provider-server/internal/entities/blockchain"
6+
)
7+
8+
type bitcoinNetworkAddresses struct {
9+
P2PKH string
10+
P2SH string
11+
P2WPKH string
12+
P2WSH string
13+
P2TR string
14+
}
15+
16+
type bitcoinAllNetworksAddresses struct {
17+
Mainnet bitcoinNetworkAddresses
18+
Testnet bitcoinNetworkAddresses
19+
Regtest bitcoinNetworkAddresses
20+
}
21+
22+
func (networks *bitcoinAllNetworksAddresses) Network(network string) (bitcoinNetworkAddresses, error) {
23+
switch network {
24+
case "mainnet":
25+
return networks.Mainnet, nil
26+
case "testnet3":
27+
return networks.Testnet, nil
28+
case "regtest":
29+
return networks.Regtest, nil
30+
default:
31+
return bitcoinNetworkAddresses{}, errors.New("unknown network")
32+
}
33+
}
34+
35+
func (addresses *bitcoinNetworkAddresses) Address(address blockchain.BtcAddressType) (string, error) {
36+
switch address {
37+
case "p2pkh":
38+
return addresses.P2PKH, nil
39+
case "p2sh":
40+
return addresses.P2SH, nil
41+
case "p2wpkh":
42+
return addresses.P2WPKH, nil
43+
case "p2wsh":
44+
return addresses.P2WSH, nil
45+
case "p2tr":
46+
return addresses.P2TR, nil
47+
default:
48+
return "", errors.New("unknown address type")
49+
}
50+
}
51+
52+
var bitcoinZeroAddresses = bitcoinAllNetworksAddresses{
53+
Mainnet: bitcoinNetworkAddresses{
54+
P2PKH: blockchain.BitcoinMainnetP2PKHZeroAddress,
55+
P2SH: blockchain.BitcoinMainnetP2SHZeroAddress,
56+
P2WPKH: blockchain.BitcoinMainnetP2WPKHZeroAddress,
57+
P2WSH: blockchain.BitcoinMainnetP2WSHZeroAddress,
58+
P2TR: blockchain.BitcoinMainnetP2TRZeroAddress,
59+
},
60+
Testnet: bitcoinNetworkAddresses{
61+
P2PKH: blockchain.BitcoinTestnetP2PKHZeroAddress,
62+
P2SH: blockchain.BitcoinTestnetP2SHZeroAddress,
63+
P2WPKH: blockchain.BitcoinTestnetP2WPKHZeroAddress,
64+
P2WSH: blockchain.BitcoinTestnetP2WSHZeroAddress,
65+
P2TR: blockchain.BitcoinTestnetP2TRZeroAddress,
66+
},
67+
Regtest: bitcoinNetworkAddresses{
68+
P2PKH: blockchain.BitcoinTestnetP2PKHZeroAddress,
69+
P2SH: blockchain.BitcoinTestnetP2SHZeroAddress,
70+
P2WPKH: blockchain.BitcoinRegtestP2WPKHZeroAddress,
71+
P2WSH: blockchain.BitcoinRegtestP2WSHZeroAddress,
72+
P2TR: blockchain.BitcoinRegtestP2TRZeroAddress,
73+
},
74+
}

internal/adapters/dataproviders/bitcoin/mempool_space/api.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,10 @@ func (api *MempoolSpaceApi) GetBlockchainInfo() (blockchain.BitcoinBlockchainInf
466466
}, nil
467467
}
468468

469+
func (api *MempoolSpaceApi) GetZeroAddress(addressType blockchain.BtcAddressType) (string, error) {
470+
return "", errors.New("not supported in MempoolSpace API")
471+
}
472+
469473
func (api *MempoolSpaceApi) getBlock(blockHash string) (*btcutil.Block, error) {
470474
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, fmt.Sprintf("%s/block/%s/raw", api.url, blockHash), nil)
471475
if err != nil {

internal/adapters/dataproviders/bitcoin/rpc.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,14 @@ func (rpc *bitcoindRpc) GetBlockchainInfo() (blockchain.BitcoinBlockchainInfo, e
253253
}, nil
254254
}
255255

256+
func (rpc *bitcoindRpc) GetZeroAddress(addressType blockchain.BtcAddressType) (string, error) {
257+
addresses, err := bitcoinZeroAddresses.Network(rpc.conn.NetworkParams.Name)
258+
if err != nil {
259+
return "", err
260+
}
261+
return addresses.Address(addressType)
262+
}
263+
256264
func (rpc *bitcoindRpc) getTxBlock(txHash string) (*wire.MsgBlock, *chainhash.Hash, error) {
257265
parsedTxHash, err := chainhash.NewHashFromStr(txHash)
258266
if err != nil {

internal/adapters/dataproviders/bitcoin/rpc_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,3 +653,57 @@ func TestBitcoindRpc_GetBlockchainInfo(t *testing.T) {
653653
client.AssertExpectations(t)
654654
})
655655
}
656+
657+
func TestBitcoindRpc_GetZeroAddress(t *testing.T) {
658+
t.Run("should return zero address in mainnet", func(t *testing.T) {
659+
rpc := bitcoin.NewBitcoindRpc(bitcoin.NewConnection(&chaincfg.MainNetParams, &mocks.ClientAdapterMock{}))
660+
cases := test.Table[blockchain.BtcAddressType, string]{
661+
{Value: blockchain.BtcAddressTypeP2PKH, Result: blockchain.BitcoinMainnetP2PKHZeroAddress},
662+
{Value: blockchain.BtcAddressTypeP2SH, Result: blockchain.BitcoinMainnetP2SHZeroAddress},
663+
{Value: blockchain.BtcAddressTypeP2WPKH, Result: blockchain.BitcoinMainnetP2WPKHZeroAddress},
664+
{Value: blockchain.BtcAddressTypeP2WSH, Result: blockchain.BitcoinMainnetP2WSHZeroAddress},
665+
{Value: blockchain.BtcAddressTypeP2TR, Result: blockchain.BitcoinMainnetP2TRZeroAddress},
666+
}
667+
test.RunTable(t, cases, func(addressType blockchain.BtcAddressType) string {
668+
result, err := rpc.GetZeroAddress(addressType)
669+
require.NoError(t, err)
670+
return result
671+
})
672+
})
673+
t.Run("should return zero address in testnet", func(t *testing.T) {
674+
rpc := bitcoin.NewBitcoindRpc(bitcoin.NewConnection(&chaincfg.TestNet3Params, &mocks.ClientAdapterMock{}))
675+
cases := test.Table[blockchain.BtcAddressType, string]{
676+
{Value: blockchain.BtcAddressTypeP2PKH, Result: blockchain.BitcoinTestnetP2PKHZeroAddress},
677+
{Value: blockchain.BtcAddressTypeP2SH, Result: blockchain.BitcoinTestnetP2SHZeroAddress},
678+
{Value: blockchain.BtcAddressTypeP2WPKH, Result: blockchain.BitcoinTestnetP2WPKHZeroAddress},
679+
{Value: blockchain.BtcAddressTypeP2WSH, Result: blockchain.BitcoinTestnetP2WSHZeroAddress},
680+
{Value: blockchain.BtcAddressTypeP2TR, Result: blockchain.BitcoinTestnetP2TRZeroAddress},
681+
}
682+
test.RunTable(t, cases, func(addressType blockchain.BtcAddressType) string {
683+
result, err := rpc.GetZeroAddress(addressType)
684+
require.NoError(t, err)
685+
return result
686+
})
687+
})
688+
t.Run("should return zero address in regtest", func(t *testing.T) {
689+
rpc := bitcoin.NewBitcoindRpc(bitcoin.NewConnection(&chaincfg.RegressionNetParams, &mocks.ClientAdapterMock{}))
690+
cases := test.Table[blockchain.BtcAddressType, string]{
691+
{Value: blockchain.BtcAddressTypeP2PKH, Result: blockchain.BitcoinTestnetP2PKHZeroAddress},
692+
{Value: blockchain.BtcAddressTypeP2SH, Result: blockchain.BitcoinTestnetP2SHZeroAddress},
693+
{Value: blockchain.BtcAddressTypeP2WPKH, Result: blockchain.BitcoinRegtestP2WPKHZeroAddress},
694+
{Value: blockchain.BtcAddressTypeP2WSH, Result: blockchain.BitcoinRegtestP2WSHZeroAddress},
695+
{Value: blockchain.BtcAddressTypeP2TR, Result: blockchain.BitcoinRegtestP2TRZeroAddress},
696+
}
697+
test.RunTable(t, cases, func(addressType blockchain.BtcAddressType) string {
698+
result, err := rpc.GetZeroAddress(addressType)
699+
require.NoError(t, err)
700+
return result
701+
})
702+
})
703+
t.Run("should return error if network not supported", func(t *testing.T) {
704+
rpc := bitcoin.NewBitcoindRpc(bitcoin.NewConnection(&chaincfg.SigNetParams, &mocks.ClientAdapterMock{}))
705+
result, err := rpc.GetZeroAddress(blockchain.BtcAddressTypeP2PKH)
706+
require.Error(t, err)
707+
assert.Empty(t, result)
708+
})
709+
}

internal/adapters/dataproviders/liquidity_provider.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ func (lp *LocalLiquidityProvider) HasPegoutLiquidity(ctx context.Context, requir
8484
return nil
8585
} else {
8686
return fmt.Errorf(
87-
"not enough liquidity, missing %s satoshi",
87+
"%w, missing %s satoshi",
88+
usecases.NoLiquidityError,
8889
requiredLiquidity.Sub(requiredLiquidity, availableLiquidity).ToSatoshi().String(),
8990
)
9091
}

internal/adapters/dataproviders/rootstock/federation/federation_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,6 @@ func TestBuildFlyoverErpRedeemScript(t *testing.T) {
246246
flyoverScript := federation.GetFlyoverRedeemScript(derivationBytes, fedRedeemScript)
247247

248248
str := hex.EncodeToString(flyoverScript)
249-
fmt.Println(str)
250249
assert.True(t, checkSubstrings(str, fedInfo.ErpKeys...))
251250
assert.EqualValues(t, flyoverErpScriptString, str)
252251
}

0 commit comments

Comments
 (0)