@@ -15,6 +15,7 @@ import (
1515 commonpb "github.com/code-payments/code-protobuf-api/generated/go/common/v1"
1616 transactionpb "github.com/code-payments/code-protobuf-api/generated/go/transaction/v2"
1717
18+ "github.com/code-payments/code-server/pkg/code/balance"
1819 "github.com/code-payments/code-server/pkg/code/common"
1920 "github.com/code-payments/code-server/pkg/code/data/intent"
2021 "github.com/code-payments/code-server/pkg/code/data/nonce"
@@ -104,6 +105,14 @@ func (s *transactionServer) StartSwap(streamer transactionpb.Transaction_StartSw
104105 // Section: Validation
105106 //
106107
108+ _ , err = s .data .GetSwapById (ctx , swapId )
109+ if err == nil {
110+ return handleStartSwapError (streamer , NewSwapDeniedError ("attempt to reuse swap id" ))
111+ } else if err != swap .ErrNotFound {
112+ log .WithError (err ).Warn ("failure checking for existing swap record" )
113+ return handleStartSwapError (streamer , err )
114+ }
115+
107116 if bytes .Equal (fromMint .PublicKey ().ToBytes (), toMint .PublicKey ().ToBytes ()) {
108117 return handleStartSwapError (streamer , NewSwapValidationError ("must swap between two different mints" ))
109118 }
@@ -112,22 +121,59 @@ func (s *transactionServer) StartSwap(streamer transactionpb.Transaction_StartSw
112121 return handleStartSwapError (streamer , NewSwapValidationError ("amount must be positive" ))
113122 }
114123
115- _ , err = common .GetVmConfigForMint (ctx , s .data , fromMint )
124+ sourceVmConfig , err : = common .GetVmConfigForMint (ctx , s .data , fromMint )
116125 if err == common .ErrUnsupportedMint {
117126 return handleStartSwapError (streamer , NewSwapValidationError ("invalid source mint" ))
118127 } else if err != nil {
119128 log .WithError (err ).Warn ("failure getting source vm config" )
120129 return handleStartSwapError (streamer , err )
121130 }
122131
123- _ , err = common .GetVmConfigForMint (ctx , s .data , toMint )
132+ destinationVmConfig , err : = common .GetVmConfigForMint (ctx , s .data , toMint )
124133 if err == common .ErrUnsupportedMint {
125134 return handleStartSwapError (streamer , NewSwapValidationError ("invalid destination mint" ))
126135 } else if err != nil {
127136 log .WithError (err ).Warn ("failure getting destination vm config" )
128137 return handleStartSwapError (streamer , err )
129138 }
130139
140+ ownerSourceTimelockVault , err := owner .ToTimelockVault (sourceVmConfig )
141+ if err != nil {
142+ log .WithError (err ).Warn ("failure getting owner destination timelock vault" )
143+ return handleStartSwapError (streamer , err )
144+ }
145+
146+ _ , err = s .data .GetTimelockByVault (ctx , ownerSourceTimelockVault .PublicKey ().ToBase58 ())
147+ if err == timelock .ErrTimelockNotFound {
148+ return handleStartSwapError (streamer , NewSwapValidationError ("source timelock vault account not opened" ))
149+ } else if err != nil {
150+ log .WithError (err ).Warn ("failure getting source timelock record" )
151+ return handleStartSwapError (streamer , err )
152+ }
153+
154+ balance , err := balance .CalculateFromCache (ctx , s .data , ownerSourceTimelockVault )
155+ if err != nil {
156+ log .WithError (err ).Warn ("failure getting owner source timelock vault balance" )
157+ return handleStartSwapError (streamer , err )
158+ }
159+ if balance < startCurrencyCreatorSwapReq .Amount {
160+ return handleStartSwapError (streamer , NewSwapValidationError ("insufficient balance" ))
161+ }
162+
163+ ownerDestinationTimelockVault , err := owner .ToTimelockVault (destinationVmConfig )
164+ if err != nil {
165+ log .WithError (err ).Warn ("failure getting owner destination timelock vault" )
166+ return handleStartSwapError (streamer , err )
167+ }
168+
169+ _ , err = s .data .GetTimelockByVault (ctx , ownerDestinationTimelockVault .PublicKey ().ToBase58 ())
170+ if err == timelock .ErrTimelockNotFound {
171+ return handleStartSwapError (streamer , NewSwapValidationError ("destination timelock vault account not opened" ))
172+ } else if err != nil {
173+ log .WithError (err ).Warn ("failure getting destination timelock record" )
174+ return handleStartSwapError (streamer , err )
175+ }
176+
131177 _ , err = s .data .GetIntent (ctx , startCurrencyCreatorSwapReq .FundingId )
132178 if err == nil {
133179 return handleStartSwapError (streamer , NewSwapValidationError ("funding intent already exists" ))
@@ -475,11 +521,6 @@ func (s *transactionServer) Swap(streamer transactionpb.Transaction_SwapServer)
475521 log .WithError (err ).Warn ("failure getting owner source vm swap ata" )
476522 return handleSwapError (streamer , err )
477523 }
478- ownerDestinationTimelockVault , err := owner .ToTimelockVault (destinationVmConfig )
479- if err != nil {
480- log .WithError (err ).Warn ("failure getting owner destination timelock vault" )
481- return handleSwapError (streamer , err )
482- }
483524
484525 //
485526 // Section: Validation
@@ -497,18 +538,6 @@ func (s *transactionServer) Swap(streamer transactionpb.Transaction_SwapServer)
497538 return handleSwapError (streamer , NewSwapValidationError ("owner cannot be swap authority" ))
498539 }
499540
500- if bytes .Equal (fromMint .PublicKey ().ToBytes (), toMint .PublicKey ().ToBytes ()) {
501- return handleSwapError (streamer , NewSwapValidationError ("must swap between two different mints" ))
502- }
503-
504- _ , err = s .data .GetTimelockByVault (ctx , ownerDestinationTimelockVault .PublicKey ().ToBase58 ())
505- if err == timelock .ErrTimelockNotFound {
506- return handleSwapError (streamer , NewSwapValidationError ("destination timelock vault account not opened" ))
507- } else if err != nil {
508- log .WithError (err ).Warn ("failure getting destination timelock record" )
509- return handleSwapError (streamer , err )
510- }
511-
512541 // todo: for any of these invalid funding cases, we should cancel the swap
513542 intentRecord , err := s .data .GetIntent (ctx , swapRecord .FundingId )
514543 if err != nil {
0 commit comments