Skip to content

Commit ba79a30

Browse files
Soumya Mohapatraadecaro
authored andcommitted
Extend fungible integration test with issuer balance APIs
Add IssuedBalanceView, RedeemedBalanceView, and OutstandingBalanceView with corresponding view factories, support helpers (CheckIssuedBalance, CheckRedeemedBalance, CheckOutstandingBalance), and two assertion blocks in TestAll that exercise the new APIs after issue+redeem cycles. Signed-off-by: Soumya Mohapatra <soumyaranjanmohapatra8@gmail.com> Signed-off-by: Soumya Mohapatra <mohapatras@microsoft.com>
1 parent d2be457 commit ba79a30

4 files changed

Lines changed: 131 additions & 0 deletions

File tree

integration/token/fungible/sdk/issuer/sdk.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ func (p *SDK) Install() error {
3939
registry.RegisterFactory("balance", &views.BalanceViewFactory{}),
4040
registry.RegisterFactory("historyIssuedToken", &views.ListIssuedTokensViewFactory{}),
4141
registry.RegisterFactory("issuedTokenQuery", &views.ListIssuedTokensViewFactory{}),
42+
registry.RegisterFactory("issuedBalance", &views.IssuedBalanceViewFactory{}),
43+
registry.RegisterFactory("redeemedBalance", &views.RedeemedBalanceViewFactory{}),
44+
registry.RegisterFactory("outstandingBalance", &views.OutstandingBalanceViewFactory{}),
4245
registry.RegisterFactory("GetEnrollmentID", &views.GetEnrollmentIDViewFactory{}),
4346
registry.RegisterFactory("acceptedTransactionHistory", &views.ListAcceptedTransactionsViewFactory{}),
4447
registry.RegisterFactory("transactionInfo", &views.TransactionInfoViewFactory{}),

integration/token/fungible/support.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,36 @@ func ListUnspentTokens(network *integration.Infrastructure, id *token3.NodeRefer
390390
return ListUnspentTokensForTMSID(network, id, wallet, typ, nil)
391391
}
392392

393+
func CheckIssuedBalance(network *integration.Infrastructure, issuer *token3.NodeReference, wallet string, typ token.Type, expected uint64) {
394+
res, err := network.Client(issuer.ReplicaName()).CallView("issuedBalance", common.JSONMarshall(&views.IssuerBalanceQuery{
395+
Wallet: wallet,
396+
TokenType: typ,
397+
}))
398+
gomega.Expect(err).NotTo(gomega.HaveOccurred())
399+
balance := res.(uint64)
400+
gomega.Expect(balance).To(gomega.Equal(expected), "issued balance: got %d, expected %d", balance, expected)
401+
}
402+
403+
func CheckRedeemedBalance(network *integration.Infrastructure, issuer *token3.NodeReference, wallet string, typ token.Type, expected uint64) {
404+
res, err := network.Client(issuer.ReplicaName()).CallView("redeemedBalance", common.JSONMarshall(&views.IssuerBalanceQuery{
405+
Wallet: wallet,
406+
TokenType: typ,
407+
}))
408+
gomega.Expect(err).NotTo(gomega.HaveOccurred())
409+
balance := res.(uint64)
410+
gomega.Expect(balance).To(gomega.Equal(expected), "redeemed balance: got %d, expected %d", balance, expected)
411+
}
412+
413+
func CheckOutstandingBalance(network *integration.Infrastructure, issuer *token3.NodeReference, wallet string, typ token.Type, expected uint64) {
414+
res, err := network.Client(issuer.ReplicaName()).CallView("outstandingBalance", common.JSONMarshall(&views.IssuerBalanceQuery{
415+
Wallet: wallet,
416+
TokenType: typ,
417+
}))
418+
gomega.Expect(err).NotTo(gomega.HaveOccurred())
419+
balance := res.(uint64)
420+
gomega.Expect(balance).To(gomega.Equal(expected), "outstanding balance: got %d, expected %d", balance, expected)
421+
}
422+
393423
func ListUnspentTokensForTMSID(network *integration.Infrastructure, id *token3.NodeReference, wallet string, typ token.Type, tmsId *token2.TMSID) *token.UnspentTokens {
394424
res, err := network.Client(id.ReplicaName()).CallView("history", common.JSONMarshall(&views.ListUnspentTokens{
395425
Wallet: wallet,

integration/token/fungible/tests.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,12 @@ func TestAll(network *integration.Infrastructure, auditorId string, onRestart On
441441
CheckAuditedTransactions(network, auditor, AuditedTransactions[:10], &t0, &t12)
442442
CheckSpending(network, bob, "", "USD", auditor, 11)
443443

444+
// Verify issuer balance APIs after issue + redeem cycle.
445+
// Default issuer wallet issued 110 + 10 (withdraw) + 10 (post-redeem) = 130 USD; redeemed 11 USD.
446+
CheckIssuedBalance(network, issuer, "", "USD", 130)
447+
CheckRedeemedBalance(network, issuer, "", "USD", 11)
448+
CheckOutstandingBalance(network, issuer, "", "USD", 119)
449+
444450
// test multi action transfer...
445451
t13 := time.Now()
446452
IssueCash(network, "", "LIRA", 3, alice, auditor, true, issuer)
@@ -502,6 +508,16 @@ func TestAll(network *integration.Infrastructure, auditorId string, onRestart On
502508
gomega.Expect(h.Sum(64).ToBigInt().Cmp(big.NewInt(180))).To(gomega.BeEquivalentTo(0))
503509
gomega.Expect(h.ByType("EUR").Count()).To(gomega.BeEquivalentTo(h.Count()))
504510

511+
// Verify issuer balances after all issue and redeem operations.
512+
// Default issuer: 241 USD issued, 21 redeemed (11 + 10).
513+
CheckIssuedBalance(network, issuer, "", "USD", 241)
514+
CheckRedeemedBalance(network, issuer, "", "USD", 21)
515+
CheckOutstandingBalance(network, issuer, "", "USD", 220)
516+
// New issuer wallet: 180 EUR issued, 0 redeemed.
517+
CheckIssuedBalance(network, issuer, "newIssuerWallet", "EUR", 180)
518+
CheckRedeemedBalance(network, issuer, "newIssuerWallet", "EUR", 0)
519+
CheckOutstandingBalance(network, issuer, "newIssuerWallet", "EUR", 180)
520+
505521
CheckBalanceAndHolding(network, issuer, "", "USD", 110, auditor)
506522
CheckBalanceAndHolding(network, issuer, "", "EUR", 150, auditor)
507523
CheckBalanceAndHolding(network, issuer, "issuer.owner", "EUR", 10, auditor)

integration/token/fungible/views/history.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,85 @@ func (p *TransactionInfoViewFactory) NewView(in []byte) (view.View, error) {
181181

182182
return f, nil
183183
}
184+
185+
// IssuerBalanceQuery contains the input parameters for issuer balance views.
186+
type IssuerBalanceQuery struct {
187+
Wallet string
188+
TokenType token2.Type
189+
TMSID *token.TMSID
190+
}
191+
192+
// IssuedBalanceView returns the total amount of non-redeemed tokens issued by the given wallet.
193+
type IssuedBalanceView struct {
194+
*IssuerBalanceQuery
195+
}
196+
197+
func (p *IssuedBalanceView) Call(context view.Context) (interface{}, error) {
198+
wallet := ttx.GetIssuerWallet(context, p.Wallet, ServiceOpts(p.TMSID)...)
199+
if wallet == nil {
200+
return nil, errors.Errorf("wallet [%s] not found", p.Wallet)
201+
}
202+
203+
return wallet.IssuedBalance(context.Context(), token.WithBalanceType(p.TokenType))
204+
}
205+
206+
type IssuedBalanceViewFactory struct{}
207+
208+
func (f *IssuedBalanceViewFactory) NewView(in []byte) (view.View, error) {
209+
v := &IssuedBalanceView{IssuerBalanceQuery: &IssuerBalanceQuery{}}
210+
if err := json.Unmarshal(in, v.IssuerBalanceQuery); err != nil {
211+
return nil, errors.Wrapf(err, "failed unmarshalling input")
212+
}
213+
214+
return v, nil
215+
}
216+
217+
// RedeemedBalanceView returns the total amount of redeemed tokens originally issued by the given wallet.
218+
type RedeemedBalanceView struct {
219+
*IssuerBalanceQuery
220+
}
221+
222+
func (p *RedeemedBalanceView) Call(context view.Context) (interface{}, error) {
223+
wallet := ttx.GetIssuerWallet(context, p.Wallet, ServiceOpts(p.TMSID)...)
224+
if wallet == nil {
225+
return nil, errors.Errorf("wallet [%s] not found", p.Wallet)
226+
}
227+
228+
return wallet.RedeemedBalance(context.Context(), token.WithBalanceType(p.TokenType))
229+
}
230+
231+
type RedeemedBalanceViewFactory struct{}
232+
233+
func (f *RedeemedBalanceViewFactory) NewView(in []byte) (view.View, error) {
234+
v := &RedeemedBalanceView{IssuerBalanceQuery: &IssuerBalanceQuery{}}
235+
if err := json.Unmarshal(in, v.IssuerBalanceQuery); err != nil {
236+
return nil, errors.Wrapf(err, "failed unmarshalling input")
237+
}
238+
239+
return v, nil
240+
}
241+
242+
// OutstandingBalanceView returns IssuedBalance − RedeemedBalance for the given wallet.
243+
type OutstandingBalanceView struct {
244+
*IssuerBalanceQuery
245+
}
246+
247+
func (p *OutstandingBalanceView) Call(context view.Context) (interface{}, error) {
248+
wallet := ttx.GetIssuerWallet(context, p.Wallet, ServiceOpts(p.TMSID)...)
249+
if wallet == nil {
250+
return nil, errors.Errorf("wallet [%s] not found", p.Wallet)
251+
}
252+
253+
return wallet.OutstandingBalance(context.Context(), token.WithBalanceType(p.TokenType))
254+
}
255+
256+
type OutstandingBalanceViewFactory struct{}
257+
258+
func (f *OutstandingBalanceViewFactory) NewView(in []byte) (view.View, error) {
259+
v := &OutstandingBalanceView{IssuerBalanceQuery: &IssuerBalanceQuery{}}
260+
if err := json.Unmarshal(in, v.IssuerBalanceQuery); err != nil {
261+
return nil, errors.Wrapf(err, "failed unmarshalling input")
262+
}
263+
264+
return v, nil
265+
}

0 commit comments

Comments
 (0)