[SDK] Fix tx history & Update WASM (#353)

* bugfix on detecting pending vtxos

* bugfix: don't return on error from previous round

* bugfix on wasm browser storage

* implements listVtxos on SDK

* Bug fix

Co-authored-by: Pietralberto Mazza <altafan@users.noreply.github.com>

* bug fix

* Fixes

* revert RedeemTx check

* Fix after merge

* bug fix on wasm wrapper

* Fix static tx history (without tx feed)

* add createAt timestamp in Vtxo domain

* Fixes

* Fixes

* Polish

* Fix

* Fix

---------

Co-authored-by: Pietralberto Mazza <altafan@users.noreply.github.com>
Co-authored-by: altafan <18440657+altafan@users.noreply.github.com>
Co-authored-by: louisinger <louis@vulpem.com>
This commit is contained in:
João Bordalo
2024-10-31 16:56:46 +00:00
committed by altafan
parent 79bb474dd2
commit 786a69da7d
28 changed files with 801 additions and 871 deletions

View File

@@ -1082,6 +1082,10 @@
}, },
"pubkey": { "pubkey": {
"type": "string" "type": "string"
},
"createdAt": {
"type": "string",
"format": "int64"
} }
} }
} }

View File

@@ -322,6 +322,7 @@ message Vtxo {
string redeem_tx = 8; string redeem_tx = 8;
uint64 amount = 9; uint64 amount = 9;
string pubkey = 10; string pubkey = 10;
int64 created_at = 11;
} }
message GetTransactionsStreamRequest {} message GetTransactionsStreamRequest {}

View File

@@ -2440,6 +2440,7 @@ type Vtxo struct {
RedeemTx string `protobuf:"bytes,8,opt,name=redeem_tx,json=redeemTx,proto3" json:"redeem_tx,omitempty"` RedeemTx string `protobuf:"bytes,8,opt,name=redeem_tx,json=redeemTx,proto3" json:"redeem_tx,omitempty"`
Amount uint64 `protobuf:"varint,9,opt,name=amount,proto3" json:"amount,omitempty"` Amount uint64 `protobuf:"varint,9,opt,name=amount,proto3" json:"amount,omitempty"`
Pubkey string `protobuf:"bytes,10,opt,name=pubkey,proto3" json:"pubkey,omitempty"` Pubkey string `protobuf:"bytes,10,opt,name=pubkey,proto3" json:"pubkey,omitempty"`
CreatedAt int64 `protobuf:"varint,11,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
} }
func (x *Vtxo) Reset() { func (x *Vtxo) Reset() {
@@ -2544,6 +2545,13 @@ func (x *Vtxo) GetPubkey() string {
return "" return ""
} }
func (x *Vtxo) GetCreatedAt() int64 {
if x != nil {
return x.CreatedAt
}
return 0
}
type GetTransactionsStreamRequest struct { type GetTransactionsStreamRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -3067,7 +3075,7 @@ var file_ark_v1_service_proto_rawDesc = []byte{
0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x02, 0x74, 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x09, 0x52, 0x02, 0x74, 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74,
0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x72,
0x65, 0x6e, 0x74, 0x54, 0x78, 0x69, 0x64, 0x22, 0x9b, 0x02, 0x0a, 0x04, 0x56, 0x74, 0x78, 0x6f, 0x65, 0x6e, 0x74, 0x54, 0x78, 0x69, 0x64, 0x22, 0xba, 0x02, 0x0a, 0x04, 0x56, 0x74, 0x78, 0x6f,
0x12, 0x2c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x12, 0x2c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70,
0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x14, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x14,
@@ -3085,171 +3093,173 @@ var file_ark_v1_service_proto_rawDesc = []byte{
0x65, 0x65, 0x6d, 0x54, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18,
0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a,
0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70,
0x75, 0x62, 0x6b, 0x65, 0x79, 0x22, 0x1e, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64,
0x5f, 0x61, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74,
0x65, 0x64, 0x41, 0x74, 0x22, 0x1e, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73,
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x22, 0x8c, 0x01, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8c, 0x01, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18,
0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x00, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x33, 0x0a, 0x06, 0x72, 0x65, 0x64, 0x65,
0x52, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76,
0x48, 0x00, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x33, 0x0a, 0x06, 0x72, 0x65, 0x64, 0x31, 0x2e, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
0x65, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x42, 0x04, 0x0a,
0x76, 0x31, 0x2e, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x02, 0x74, 0x78, 0x22, 0xd8, 0x01, 0x0a, 0x10, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x72, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x42, 0x04, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64,
0x0a, 0x02, 0x74, 0x78, 0x22, 0xd8, 0x01, 0x0a, 0x10, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x31, 0x0a, 0x0b,
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x31, 0x0a, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f,
0x0b, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12,
0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x35, 0x0a, 0x0f, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x74, 0x78,
0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76,
0x12, 0x35, 0x0a, 0x0f, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x74, 0x31, 0x2e, 0x56, 0x74, 0x78, 0x6f, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c,
0x78, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x65, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x46, 0x0a, 0x16, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x65,
0x76, 0x31, 0x2e, 0x56, 0x74, 0x78, 0x6f, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x64, 0x5f, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x73,
0x6c, 0x65, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x46, 0x0a, 0x16, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e,
0x65, 0x64, 0x5f, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x14, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x65,
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x64, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x91,
0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x14, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
0x65, 0x64, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x91, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x31, 0x0a, 0x0b, 0x73, 0x70, 0x65, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x74, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e,
0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x31, 0x0a, 0x0b, 0x73, 0x70, 0x65, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52,
0x6e, 0x74, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x0a, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x35, 0x0a, 0x0f, 0x73,
0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x03,
0x52, 0x0a, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x35, 0x0a, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x74,
0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x78, 0x6f, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x74, 0x78,
0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x6f, 0x73, 0x2a, 0x98, 0x01, 0x0a, 0x0a, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x67,
0x74, 0x78, 0x6f, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45,
0x78, 0x6f, 0x73, 0x2a, 0x98, 0x01, 0x0a, 0x0a, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c,
0x67, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x0a, 0x18, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x45,
0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x47, 0x49, 0x53, 0x54, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18,
0x1c, 0x0a, 0x18, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, 0x49, 0x4e, 0x41,
0x45, 0x47, 0x49, 0x53, 0x54, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x4c, 0x49, 0x5a, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x52, 0x4f,
0x18, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, 0x49, 0x4e, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49,
0x41, 0x4c, 0x49, 0x5a, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x52, 0x5a, 0x45, 0x44, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53,
0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x32, 0xeb, 0x0d,
0x49, 0x5a, 0x45, 0x44, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x0a, 0x0a, 0x41, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x07,
0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x32, 0xeb, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31,
0x0d, 0x0a, 0x0a, 0x41, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f,
0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0a,
0x1a, 0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x12, 0x08, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x74, 0x0a, 0x12, 0x47, 0x65,
0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x0a, 0x12, 0x08, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x74, 0x0a, 0x12, 0x47,
0x65, 0x74, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x12, 0x21, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6f,
0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
0x74, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x74, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x21, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x61,
0x3a, 0x01, 0x2a, 0x22, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75,
0x67, 0x12, 0x98, 0x01, 0x0a, 0x1a, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x3a,
0x01, 0x2a, 0x22, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67,
0x12, 0x98, 0x01, 0x0a, 0x1a, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x70,
0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12,
0x29, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f,
0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x61, 0x72, 0x6b,
0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75,
0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x3a, 0x01,
0x2a, 0x22, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x72, 0x65, 0x67,
0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x9c, 0x01, 0x0a, 0x1b,
0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x46,
0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2a, 0x2e, 0x61, 0x72,
0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74,
0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64,
0x12, 0x29, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31,
0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73,
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x61, 0x72, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70,
0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x3a, 0x01, 0x2a, 0x22,
0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x19, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x3a, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x7d, 0x0a, 0x10, 0x53, 0x75,
0x01, 0x2a, 0x22, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x72, 0x65, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x1f,
0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x9c, 0x01, 0x0a, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72,
0x1b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2a, 0x2e, 0x61, 0x20, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54,
0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, 0x76,
0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x74, 0x72, 0x65, 0x65, 0x2f, 0x73, 0x75, 0x62,
0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x6d, 0x69, 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x8d, 0x01, 0x0a, 0x14, 0x53, 0x75,
0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x3a, 0x01, 0x2a, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d,
0x22, 0x19, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73,
0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x7d, 0x0a, 0x10, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31,
0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61,
0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x82,
0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x3a, 0x01, 0x2a, 0x22, 0x1f, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f,
0x1a, 0x20, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x75, 0x6e, 0x64, 0x2f, 0x74, 0x72, 0x65, 0x65, 0x2f, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x53,
0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x8e, 0x01, 0x0a, 0x16, 0x53, 0x75,
0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, 0x62, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69,
0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x74, 0x72, 0x65, 0x65, 0x2f, 0x73, 0x75, 0x74, 0x54, 0x78, 0x73, 0x12, 0x25, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75,
0x62, 0x6d, 0x69, 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x8d, 0x01, 0x0a, 0x14, 0x53, 0x62, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69,
0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x74, 0x54, 0x78, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x61, 0x72,
0x72, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65,
0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a, 0x01, 0x2a, 0x22, 0x1a,
0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74,
0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x6b, 0x0a, 0x0e, 0x47, 0x65,
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x3a, 0x01, 0x2a, 0x22, 0x1f, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x2e, 0x61,
0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x74, 0x72, 0x65, 0x65, 0x2f, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74,
0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x8e, 0x01, 0x0a, 0x16, 0x53,
0x75, 0x62, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65,
0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x25, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53,
0x75, 0x62, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65,
0x69, 0x74, 0x54, 0x78, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x61,
0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e,
0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a, 0x01, 0x2a, 0x22,
0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x73, 0x75, 0x62, 0x6d, 0x69,
0x74, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x6b, 0x0a, 0x0e, 0x47,
0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x2e,
0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53,
0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61,
0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74,
0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x72,
0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72,
0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x30, 0x01, 0x12, 0x56, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4,
0x12, 0x13, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x30, 0x01, 0x12, 0x56, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12,
0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x13, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71,
0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x70, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69,
0x69, 0x6e, 0x67, 0x2f, 0x7b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93,
0x12, 0x64, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x70, 0x69,
0x74, 0x12, 0x1c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x6e, 0x67, 0x2f, 0x7b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12,
0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x64, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74,
0x1d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x12, 0x1c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d,
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61,
0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x73, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82,
0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61,
0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x73, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74,
0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76,
0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e,
0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76,
0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e,
0x6e, 0x74, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x57, 0x0a, 0x08, 0x47, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e,
0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x74, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x57, 0x0a, 0x08, 0x47, 0x65,
0x1a, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e,
0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x7b, 0x74, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e,
0x78, 0x69, 0x64, 0x7d, 0x12, 0x64, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x42, 0x79, 0x49, 0x64, 0x12, 0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x7b, 0x74, 0x78,
0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x69, 0x64, 0x7d, 0x12, 0x64, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42,
0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x79, 0x49, 0x64, 0x12, 0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x1a, 0x1c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75,
0x6e, 0x64, 0x2f, 0x69, 0x64, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x5d, 0x0a, 0x09, 0x4c, 0x69, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19,
0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e,
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x64, 0x2f, 0x69, 0x64, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x5d, 0x0a, 0x09, 0x4c, 0x69, 0x73,
0x74, 0x1a, 0x19, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e,
0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x2f, 0x1a, 0x19, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74,
0x7b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0x80, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4,
0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x2f, 0x7b,
0x65, 0x61, 0x6d, 0x12, 0x24, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0x80, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65,
0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x61, 0x6d, 0x12, 0x24, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54,
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61,
0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76,
0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x72, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x30, 0x01, 0x42, 0x92, 0x01, 0x0a, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x72, 0x61,
0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x30, 0x01, 0x42, 0x92, 0x01, 0x0a, 0x0a,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x6b, 0x2d, 0x6e, 0x65, 0x74, 0x77, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, 0x76,
0x6f, 0x72, 0x6b, 0x2f, 0x61, 0x72, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x73, 0x70, 0x65, 0x63, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x72, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x6b, 0x2d, 0x6e, 0x65, 0x74, 0x77, 0x6f,
0x6b, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x72, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, 0x72, 0x6b, 0x2f, 0x61, 0x72, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x73, 0x70, 0x65, 0x63, 0x2f,
0xaa, 0x02, 0x06, 0x41, 0x72, 0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, 0x41, 0x72, 0x6b, 0x5c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x72, 0x6b,
0x56, 0x31, 0xe2, 0x02, 0x12, 0x41, 0x72, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x72, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, 0xaa,
0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x41, 0x72, 0x6b, 0x3a, 0x3a, 0x56, 0x02, 0x06, 0x41, 0x72, 0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, 0x41, 0x72, 0x6b, 0x5c, 0x56,
0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x31, 0xe2, 0x02, 0x12, 0x41, 0x72, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x41, 0x72, 0x6b, 0x3a, 0x3a, 0x56, 0x31,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -97,7 +97,8 @@ type Vtxo struct {
Pubkey string Pubkey string
Amount uint64 Amount uint64
RoundTxid string RoundTxid string
ExpiresAt *time.Time ExpiresAt time.Time
CreatedAt time.Time
RedeemTx string RedeemTx string
IsOOR bool IsOOR bool
SpentBy string SpentBy string

View File

@@ -112,11 +112,6 @@ type vtxo struct {
} }
func (v vtxo) toVtxo() client.Vtxo { func (v vtxo) toVtxo() client.Vtxo {
var expiresAt *time.Time
if v.GetExpireAt() > 0 {
t := time.Unix(v.GetExpireAt(), 0)
expiresAt = &t
}
return client.Vtxo{ return client.Vtxo{
Outpoint: client.Outpoint{ Outpoint: client.Outpoint{
Txid: v.GetOutpoint().GetTxid(), Txid: v.GetOutpoint().GetTxid(),
@@ -124,11 +119,12 @@ func (v vtxo) toVtxo() client.Vtxo {
}, },
Amount: v.GetAmount(), Amount: v.GetAmount(),
RoundTxid: v.GetRoundTxid(), RoundTxid: v.GetRoundTxid(),
ExpiresAt: expiresAt, ExpiresAt: time.Unix(v.GetExpireAt(), 0),
IsOOR: v.GetIsOor(), IsOOR: v.GetIsOor(),
RedeemTx: v.GetRedeemTx(), RedeemTx: v.GetRedeemTx(),
SpentBy: v.GetSpentBy(), SpentBy: v.GetSpentBy(),
Pubkey: v.GetPubkey(), Pubkey: v.GetPubkey(),
CreatedAt: time.Unix(v.GetCreatedAt(), 0),
} }
} }

View File

@@ -474,67 +474,8 @@ func (a *restClient) ListVtxos(
return nil, nil, err return nil, nil, err
} }
spendableVtxos := make([]client.Vtxo, 0, len(resp.Payload.SpendableVtxos)) spendableVtxos := vtxosFromRest(resp.Payload.SpendableVtxos)
for _, v := range resp.Payload.SpendableVtxos { spentVtxos := vtxosFromRest(resp.Payload.SpentVtxos)
var expiresAt *time.Time
if v.ExpireAt != "" && v.ExpireAt != "0" {
expAt, err := strconv.Atoi(v.ExpireAt)
if err != nil {
return nil, nil, err
}
t := time.Unix(int64(expAt), 0)
expiresAt = &t
}
amount, err := strconv.Atoi(v.Amount)
if err != nil {
return nil, nil, err
}
spendableVtxos = append(spendableVtxos, client.Vtxo{
Outpoint: client.Outpoint{
Txid: v.Outpoint.Txid,
VOut: uint32(v.Outpoint.Vout),
},
Amount: uint64(amount),
RoundTxid: v.RoundTxid,
ExpiresAt: expiresAt,
IsOOR: v.IsOor,
RedeemTx: v.RedeemTx,
SpentBy: v.SpentBy,
Pubkey: v.Pubkey,
})
}
spentVtxos := make([]client.Vtxo, 0, len(resp.Payload.SpentVtxos))
for _, v := range resp.Payload.SpentVtxos {
var expiresAt *time.Time
if v.ExpireAt != "" && v.ExpireAt != "0" {
expAt, err := strconv.Atoi(v.ExpireAt)
if err != nil {
return nil, nil, err
}
t := time.Unix(int64(expAt), 0)
expiresAt = &t
}
amount, err := strconv.Atoi(v.Amount)
if err != nil {
return nil, nil, err
}
spentVtxos = append(spentVtxos, client.Vtxo{
Outpoint: client.Outpoint{
Txid: v.Outpoint.Txid,
VOut: uint32(v.Outpoint.Vout),
},
Amount: uint64(amount),
RoundTxid: v.RoundTxid,
ExpiresAt: expiresAt,
SpentBy: v.SpentBy,
Pubkey: v.Pubkey,
})
}
return spendableVtxos, spentVtxos, nil return spendableVtxos, spentVtxos, nil
} }
@@ -676,14 +617,21 @@ func outpointsFromRest(restOutpoints []*models.V1Outpoint) []client.Outpoint {
func vtxosFromRest(restVtxos []*models.V1Vtxo) []client.Vtxo { func vtxosFromRest(restVtxos []*models.V1Vtxo) []client.Vtxo {
vtxos := make([]client.Vtxo, len(restVtxos)) vtxos := make([]client.Vtxo, len(restVtxos))
for i, v := range restVtxos { for i, v := range restVtxos {
var expiresAt *time.Time var expiresAt, createdAt time.Time
if v.ExpireAt != "" && v.ExpireAt != "0" { if v.ExpireAt != "" && v.ExpireAt != "0" {
expAt, err := strconv.Atoi(v.ExpireAt) expAt, err := strconv.Atoi(v.ExpireAt)
if err != nil { if err != nil {
return nil return nil
} }
t := time.Unix(int64(expAt), 0) expiresAt = time.Unix(int64(expAt), 0)
expiresAt = &t }
if v.CreatedAt != "" && v.CreatedAt != "0" {
creaAt, err := strconv.Atoi(v.CreatedAt)
if err != nil {
return nil
}
createdAt = time.Unix(int64(creaAt), 0)
} }
amount, err := strconv.Atoi(v.Amount) amount, err := strconv.Atoi(v.Amount)
@@ -703,6 +651,7 @@ func vtxosFromRest(restVtxos []*models.V1Vtxo) []client.Vtxo {
RedeemTx: v.RedeemTx, RedeemTx: v.RedeemTx,
IsOOR: v.IsOor, IsOOR: v.IsOor,
SpentBy: v.SpentBy, SpentBy: v.SpentBy,
CreatedAt: createdAt,
} }
} }
return vtxos return vtxos

View File

@@ -21,6 +21,9 @@ type V1Vtxo struct {
// amount // amount
Amount string `json:"amount,omitempty"` Amount string `json:"amount,omitempty"`
// created at
CreatedAt string `json:"createdAt,omitempty"`
// expire at // expire at
ExpireAt string `json:"expireAt,omitempty"` ExpireAt string `json:"expireAt,omitempty"`

View File

@@ -3,6 +3,7 @@ package arksdk
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os"
"strconv" "strconv"
"testing" "testing"
"time" "time"
@@ -12,488 +13,143 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestVtxosToTxs(t *testing.T) { type fixture struct {
tests := []struct { name string
name string ignoreTxs map[string]struct{}
fixture string spendableVtxos []client.Vtxo
want []sdktypes.Transaction spentVtxos []client.Vtxo
}{ expectedTxHistory []sdktypes.Transaction
{ }
name: "Alice Before Sending Async",
fixture: aliceBeforeSendingAsync,
want: []sdktypes.Transaction{},
},
{
name: "Alice After Sending Async",
fixture: aliceAfterSendingAsync,
want: []sdktypes.Transaction{
{
TransactionKey: sdktypes.TransactionKey{
RedeemTxid: "94fa598302f17f00c8881e742ec0ce2f8c8d16f3d54fe6ba0fb7d13a493d84ad",
},
Amount: 1000,
Type: sdktypes.TxSent,
CreatedAt: time.Unix(1726054898, 0),
},
},
},
{
name: "Bob Before Claiming Async",
fixture: bobBeforeClaimingAsync,
want: []sdktypes.Transaction{
{
TransactionKey: sdktypes.TransactionKey{
RedeemTxid: "94fa598302f17f00c8881e742ec0ce2f8c8d16f3d54fe6ba0fb7d13a493d84ad",
},
Amount: 1000,
Type: sdktypes.TxReceived,
CreatedAt: time.Unix(1726054898, 0),
},
{
TransactionKey: sdktypes.TransactionKey{
RedeemTxid: "766fc46ba5c2da41cd4c4bc0566e0f4e0f24c184c41acd3bead5cd7b11120367",
},
Amount: 2000,
Type: sdktypes.TxReceived,
CreatedAt: time.Unix(1726486359, 0),
},
},
},
{
name: "Bob After Claiming Async",
fixture: bobAfterClaimingAsync,
want: []sdktypes.Transaction{
{
TransactionKey: sdktypes.TransactionKey{
RedeemTxid: "94fa598302f17f00c8881e742ec0ce2f8c8d16f3d54fe6ba0fb7d13a493d84ad",
},
Amount: 1000,
Type: sdktypes.TxReceived,
CreatedAt: time.Unix(1726054898, 0),
},
{
TransactionKey: sdktypes.TransactionKey{
RedeemTxid: "766fc46ba5c2da41cd4c4bc0566e0f4e0f24c184c41acd3bead5cd7b11120367",
},
Amount: 2000,
Type: sdktypes.TxReceived,
CreatedAt: time.Unix(1726486359, 0),
},
},
},
{
name: "Bob After Sending Async",
fixture: bobAfterSendingAsync,
want: []sdktypes.Transaction{
{
TransactionKey: sdktypes.TransactionKey{
RedeemTxid: "94fa598302f17f00c8881e742ec0ce2f8c8d16f3d54fe6ba0fb7d13a493d84ad",
},
Amount: 1000,
Type: sdktypes.TxReceived,
CreatedAt: time.Unix(1726054898, 0),
},
{
TransactionKey: sdktypes.TransactionKey{
RedeemTxid: "766fc46ba5c2da41cd4c4bc0566e0f4e0f24c184c41acd3bead5cd7b11120367",
},
Amount: 2000,
Type: sdktypes.TxReceived,
CreatedAt: time.Unix(1726486359, 0),
},
{
TransactionKey: sdktypes.TransactionKey{
RedeemTxid: "23c3a885f0ea05f7bdf83f3bf7f8ac9dc3f791ad292f4e63a6f53fa5e4935ab0",
},
Amount: 2100,
Type: sdktypes.TxSent,
CreatedAt: time.Unix(1726503865, 0),
},
},
},
}
for _, tt := range tests { func TestVtxosToTxs(t *testing.T) {
fixtures, err := loadFixtures()
require.NoError(t, err)
for _, tt := range fixtures {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
vtxos, ignoreTxs, err := loadFixtures(tt.fixture) txHistory, err := vtxosToTxsCovenantless(tt.spendableVtxos, tt.spentVtxos)
if err != nil {
t.Fatalf("failed to load fixture: %s", err)
}
got, err := vtxosToTxsCovenantless(30, vtxos.spendable, vtxos.spent, ignoreTxs)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, got, len(tt.want)) require.Len(t, txHistory, len(tt.expectedTxHistory))
// Check each expected transaction, excluding CreatedAt // Check each expected transaction, excluding CreatedAt
for i, wantTx := range tt.want { for i, wantTx := range tt.expectedTxHistory {
gotTx := got[i] gotTx := txHistory[i]
require.Equal(t, wantTx.RoundTxid, gotTx.RoundTxid) require.Equal(t, wantTx.TransactionKey, gotTx.TransactionKey)
require.Equal(t, wantTx.RedeemTxid, gotTx.RedeemTxid)
require.Equal(t, int(wantTx.Amount), int(gotTx.Amount)) require.Equal(t, int(wantTx.Amount), int(gotTx.Amount))
require.Equal(t, wantTx.Type, gotTx.Type) require.Equal(t, wantTx.Type, gotTx.Type)
require.Equal(t, wantTx.Settled, gotTx.Settled)
require.Equal(t, wantTx.CreatedAt, gotTx.CreatedAt)
} }
}) })
} }
} }
type vtxos struct { type vtxo struct {
spendable []client.Vtxo Outpoint struct {
spent []client.Vtxo Txid string `json:"txid"`
VOut uint32 `json:"vout"`
} `json:"outpoint"`
Amount string `json:"amount"`
Spent bool `json:"spent"`
RoundTxid string `json:"roundTxid"`
SpentBy string `json:"spentBy"`
ExpiresAt string `json:"expireAt"`
Swept bool `json:"swept"`
RedeemTx string `json:"redeemTx"`
CreatedAt string `json:"createdAt"`
IsOOR bool `json:"isOor"`
} }
func loadFixtures(jsonStr string) (vtxos, map[string]struct{}, error) { type vtxos []vtxo
var data struct {
IgnoreTxs []string `json:"ignoreTxs"`
SpendableVtxos []struct {
Outpoint struct {
Txid string `json:"txid"`
Vout uint32 `json:"vout"`
} `json:"outpoint"`
Receiver struct {
Address string `json:"address"`
Amount string `json:"amount"`
} `json:"receiver"`
Spent bool `json:"spent"`
PoolTxid string `json:"poolTxid"`
SpentBy string `json:"spentBy"`
ExpireAt string `json:"expireAt"`
Swept bool `json:"swept"`
RedeemTx string `json:"redeemTx"`
} `json:"spendableVtxos"`
SpentVtxos []struct {
Outpoint struct {
Txid string `json:"txid"`
Vout uint32 `json:"vout"`
} `json:"outpoint"`
Receiver struct {
Address string `json:"address"`
Amount string `json:"amount"`
} `json:"receiver"`
Spent bool `json:"spent"`
PoolTxid string `json:"poolTxid"`
SpentBy string `json:"spentBy"`
ExpireAt string `json:"expireAt"`
Swept bool `json:"swept"`
RedeemTx string `json:"redeemTx"`
} `json:"spentVtxos"`
}
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { func (v vtxos) parse() []client.Vtxo {
return vtxos{}, nil, err list := make([]client.Vtxo, 0, len(v))
} for _, vv := range v {
list = append(list, client.Vtxo{
spendable := make([]client.Vtxo, len(data.SpendableVtxos))
for i, vtxo := range data.SpendableVtxos {
expireAt, err := parseTimestamp(vtxo.ExpireAt)
if err != nil {
return vtxos{}, nil, err
}
amount, err := parseAmount(vtxo.Receiver.Amount)
if err != nil {
return vtxos{}, nil, err
}
spendable[i] = client.Vtxo{
Outpoint: client.Outpoint{ Outpoint: client.Outpoint{
Txid: vtxo.Outpoint.Txid, Txid: vv.Outpoint.Txid,
VOut: vtxo.Outpoint.Vout, VOut: vv.Outpoint.VOut,
}, },
Amount: amount, Amount: parseAmount(vv.Amount),
RoundTxid: vtxo.PoolTxid, RoundTxid: vv.RoundTxid,
ExpiresAt: &expireAt, ExpiresAt: parseTimestamp(vv.ExpiresAt),
RedeemTx: vtxo.RedeemTx, CreatedAt: parseTimestamp(vv.CreatedAt),
SpentBy: vtxo.SpentBy, RedeemTx: vv.RedeemTx,
} SpentBy: vv.SpentBy,
IsOOR: vv.IsOOR,
})
} }
return list
spent := make([]client.Vtxo, len(data.SpentVtxos))
for i, vtxo := range data.SpentVtxos {
expireAt, err := parseTimestamp(vtxo.ExpireAt)
if err != nil {
return vtxos{}, nil, err
}
amount, err := parseAmount(vtxo.Receiver.Amount)
if err != nil {
return vtxos{}, nil, err
}
spent[i] = client.Vtxo{
Outpoint: client.Outpoint{
Txid: vtxo.Outpoint.Txid,
VOut: vtxo.Outpoint.Vout,
},
Amount: amount,
RoundTxid: vtxo.PoolTxid,
ExpiresAt: &expireAt,
RedeemTx: vtxo.RedeemTx,
SpentBy: vtxo.SpentBy,
}
}
vtxos := vtxos{
spendable: spendable,
spent: spent,
}
ignoreTxs := make(map[string]struct{})
for _, tx := range data.IgnoreTxs {
ignoreTxs[tx] = struct{}{}
}
return vtxos, ignoreTxs, nil
} }
func parseAmount(amountStr string) (uint64, error) { type tx struct {
amount, err := strconv.ParseUint(amountStr, 10, 64) RoundTxid string `json:"roundTxid"`
RedeemTxid string `json:"redeemTxid"`
Amount string `json:"amount"`
Type string `json:"type"`
Settled bool `json:"settled"`
CreatedAt string `json:"createdAt"`
}
type txs []tx
func (t txs) parse() []sdktypes.Transaction {
list := make([]sdktypes.Transaction, 0, len(t))
for _, tx := range t {
list = append(list, sdktypes.Transaction{
TransactionKey: sdktypes.TransactionKey{
RedeemTxid: tx.RedeemTxid,
RoundTxid: tx.RoundTxid,
},
Amount: parseAmount(tx.Amount),
Type: sdktypes.TxType(tx.Type),
Settled: tx.Settled,
CreatedAt: parseTimestamp(tx.CreatedAt),
},
)
}
return list
}
func loadFixtures() ([]fixture, error) {
data := make([]struct {
Name string `json:"name"`
IgnoreTxs []string `json:"ignoreTxs"`
SpendableVtxos vtxos `json:"spendableVtxos"`
SpentVtxos vtxos `json:"spentVtxos"`
ExpectedTxHistory txs `json:"expectedTxHistory"`
}, 0)
buf, err := os.ReadFile("test_data.json")
if err != nil { if err != nil {
return 0, err return nil, fmt.Errorf("failed to read fixtures: %s", err)
}
if err := json.Unmarshal(buf, &data); err != nil {
return nil, fmt.Errorf("failed to unmarshal fixtures: %s", err)
} }
return amount, nil fixtures := make([]fixture, 0, len(data))
} for _, r := range data {
indexedTxs := make(map[string]struct{})
func parseTimestamp(timestamp string) (time.Time, error) { for _, tx := range r.IgnoreTxs {
seconds, err := strconv.ParseInt(timestamp, 10, 64) indexedTxs[tx] = struct{}{}
if err != nil { }
return time.Time{}, fmt.Errorf("invalid timestamp format: %w", err) fixtures = append(fixtures, fixture{
name: r.Name,
ignoreTxs: indexedTxs,
spendableVtxos: r.SpendableVtxos.parse(),
spentVtxos: r.SpentVtxos.parse(),
expectedTxHistory: r.ExpectedTxHistory.parse(),
})
} }
return fixtures, nil
return time.Unix(seconds, 0), nil
} }
// bellow fixtures are used in bellow scenario: func parseAmount(amountStr string) uint64 {
// 1. Alice boards with 20OOO amount, _ := strconv.ParseUint(amountStr, 10, 64)
// 2. Alice sends 1000 to Bob return amount
// 3. Bob claims 1000 }
var (
aliceBeforeSendingAsync = `
{
"ignoreTxs": [
"377fa2fbd27c82bdbc095478384c88b6c75432c0ef464189e49c965194446cdf"
],
"spendableVtxos": [
{
"outpoint": {
"txid": "69ccb6520e0b91ac1cbaa459b16ec1e3ff5f6349990b0d149dd8e6c6485d316c",
"vout": 0
},
"receiver": {
"address": "tark1qwnakvl59d5wckz9lqhhdav0uvns6uu3zkc6hg65gh0kgh6wve9pwqa0qjq9ajm57ss4m7wutyhp3vexxzgkn2r5awtzytp8qfk8exfn4vm5d8ff",
"amount": "20000"
},
"spent": false,
"poolTxid": "377fa2fbd27c82bdbc095478384c88b6c75432c0ef464189e49c965194446cdf",
"spentBy": "",
"expireAt": "1726054928",
"swept": false
}
],
"spentVtxos": []
}`
aliceAfterSendingAsync = ` func parseTimestamp(timestamp string) time.Time {
{ seconds, _ := strconv.ParseInt(timestamp, 10, 64)
"ignoreTxs": [ return time.Unix(seconds, 0)
"377fa2fbd27c82bdbc095478384c88b6c75432c0ef464189e49c965194446cdf" }
],
"spendableVtxos": [
{
"outpoint": {
"txid": "94fa598302f17f00c8881e742ec0ce2f8c8d16f3d54fe6ba0fb7d13a493d84ad",
"vout": 1
},
"receiver": {
"address": "tark1qwnakvl59d5wckz9lqhhdav0uvns6uu3zkc6hg65gh0kgh6wve9pwqa0qjq9ajm57ss4m7wutyhp3vexxzgkn2r5awtzytp8qfk8exfn4vm5d8ff",
"amount": "19000"
},
"spent": false,
"poolTxid": "",
"spentBy": "",
"expireAt": "1726054928",
"swept": false,
"redeemTx": "cHNidP8BAIkCAAAAAWwxXUjG5tidFA0LmUljX//jwW6xWaS6HKyRCw5StsxpAAAAAAD/////AugDAAAAAAAAIlEgt2eR8LtqTP7yUcQtSydeGrRiHnVmHHnZwYjdC23G7MZwSQAAAAAAACJRIKfUzf/o9h+r0v9y4nmyOt9qO8EkDumQPQZGTbEv8fSFAAAAAAABASsgTgAAAAAAACJRIKfUzf/o9h+r0v9y4nmyOt9qO8EkDumQPQZGTbEv8fSFIgYDp9sz9Cto7FhF+C929Y/jJw1zkRWxq6NURd9kX05mShcYAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAQRSvBIBey3T0IV353FkuGLMmMJFpqHTrliIsJwJsfJkzq7J0B8bQ0j9842h5lUfOWcbj2TeoFx6OCpgoHIqWIBhHQAFqkBLiRmP3AZ8MS77s1QIWZswMV3L72D9gN0f0MbD6XHkmzZeC1clF3uzxr+13wsF0vcFe29Zl3e2gAhMNGYVCFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wKRtST8P7teUpSF4DAEbfJj5OIXITx5QGbZns/AtxqGyRSCn2zP0K2jsWEX4L3b1j+MnDXORFbGro1RF32RfTmZKF60grwSAXst09CFd+dxZLhizJjCRaah065YiLCcCbHyZM6uswCEWp9sz9Cto7FhF+C929Y/jJw1zkRWxq6NURd9kX05mShc5AbJ0B8bQ0j9842h5lUfOWcbj2TeoFx6OCpgoHIqWIBhHAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAARcgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsAAAAA="
}
],
"spentVtxos": [
{
"outpoint": {
"txid": "69ccb6520e0b91ac1cbaa459b16ec1e3ff5f6349990b0d149dd8e6c6485d316c",
"vout": 0
},
"receiver": {
"address": "tark1qwnakvl59d5wckz9lqhhdav0uvns6uu3zkc6hg65gh0kgh6wve9pwqa0qjq9ajm57ss4m7wutyhp3vexxzgkn2r5awtzytp8qfk8exfn4vm5d8ff",
"amount": "20000"
},
"spent": true,
"poolTxid": "377fa2fbd27c82bdbc095478384c88b6c75432c0ef464189e49c965194446cdf",
"spentBy": "94fa598302f17f00c8881e742ec0ce2f8c8d16f3d54fe6ba0fb7d13a493d84ad",
"expireAt": "1726054928",
"swept": false,
"redeemTx": ""
}
]
}`
bobBeforeClaimingAsync = `
{
"spendableVtxos": [
{
"outpoint": {
"txid": "94fa598302f17f00c8881e742ec0ce2f8c8d16f3d54fe6ba0fb7d13a493d84ad",
"vout": 0
},
"receiver": {
"address": "tark1qwnakvl59d5wckz9lqhhdav0uvns6uu3zkc6hg65gh0kgh6wve9pwqa8vzms5xcr7pqgt0sw88vc287dse5rw6fnxuk9f08frf8amxjcrya0tkgt",
"amount": "1000"
},
"spent": false,
"poolTxid": "",
"spentBy": "",
"expireAt": "1726054928",
"swept": false,
"redeemTx": "cHNidP8BAIkCAAAAAWwxXUjG5tidFA0LmUljX//jwW6xWaS6HKyRCw5StsxpAAAAAAD/////AugDAAAAAAAAIlEgt2eR8LtqTP7yUcQtSydeGrRiHnVmHHnZwYjdC23G7MZwSQAAAAAAACJRIKfUzf/o9h+r0v9y4nmyOt9qO8EkDumQPQZGTbEv8fSFAAAAAAABASsgTgAAAAAAACJRIKfUzf/o9h+r0v9y4nmyOt9qO8EkDumQPQZGTbEv8fSFIgYDp9sz9Cto7FhF+C929Y/jJw1zkRWxq6NURd9kX05mShcYAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAQRSvBIBey3T0IV353FkuGLMmMJFpqHTrliIsJwJsfJkzq7J0B8bQ0j9842h5lUfOWcbj2TeoFx6OCpgoHIqWIBhHQAFqkBLiRmP3AZ8MS77s1QIWZswMV3L72D9gN0f0MbD6XHkmzZeC1clF3uzxr+13wsF0vcFe29Zl3e2gAhMNGYVCFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wKRtST8P7teUpSF4DAEbfJj5OIXITx5QGbZns/AtxqGyRSCn2zP0K2jsWEX4L3b1j+MnDXORFbGro1RF32RfTmZKF60grwSAXst09CFd+dxZLhizJjCRaah065YiLCcCbHyZM6uswCEWp9sz9Cto7FhF+C929Y/jJw1zkRWxq6NURd9kX05mShc5AbJ0B8bQ0j9842h5lUfOWcbj2TeoFx6OCpgoHIqWIBhHAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAARcgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsAAAAA="
},
{
"outpoint": {
"txid": "766fc46ba5c2da41cd4c4bc0566e0f4e0f24c184c41acd3bead5cd7b11120367",
"vout": 0
},
"receiver": {
"address": "tark1qgw4gpt40zet7q399hv78z7pdak5sxlcgzhy6y6qq7hw3syeudc6xqsws4tegt5r88eahx7g5try2ua4n9rflsncpresjfwcrq80k0d3systnm98",
"amount": "2000"
},
"spent": false,
"poolTxid": "",
"spentBy": "",
"expireAt": "1726486389",
"swept": false,
"redeemTx": "cHNidP8BAIkCAAAAARH6LJRGP/pFIkD/o5bBp8fXAhjl8yjfN7MhJsxdt5lrAQAAAAD/////AtAHAAAAAAAAIlEguuBh3KQUVZp+NHV2sixQ/mrsngCuLCGXzsgJPC1FzY7ANQ8AAAAAACJRIP7uXXtl4jLUcVVQU+sX7WFXmx2H6iCMzn7gye0v1Y8JAAAAAAABAStYPg8AAAAAACJRIP7uXXtl4jLUcVVQU+sX7WFXmx2H6iCMzn7gye0v1Y8JIgYCHVQFdXiyvwIlLdnji8FvbUgb+ECuTRNAB67owJnjcaMYAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAQRSc1yjQ/vHRHev23fKGANLvbOhkNYmGtmRWt8fSszlOJUzRFbnfxd1fq9gIEpaI0vrZww8tlZ94iEL75QoaIbVqQJsPdLYf7fAoXO82VoqwYHu1WevE4g6LxUGBPzfd96q5EEZkoW5qqg+v5dWJUEY467Q6qZLFHwziUaB3KEY8yEpCFcBQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wO5D2Mh3x0XNGxFCS67GNughkENFodpFeVpZjn76chI8RSAdVAV1eLK/AiUt2eOLwW9tSBv4QK5NE0AHrujAmeNxo60gnNco0P7x0R3r9t3yhgDS72zoZDWJhrZkVrfH0rM5TiWswCEWHVQFdXiyvwIlLdnji8FvbUgb+ECuTRNAB67owJnjcaM5AUzRFbnfxd1fq9gIEpaI0vrZww8tlZ94iEL75QoaIbVqAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAARcgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsAAAAA="
}
],
"spentVtxos": []
}`
bobAfterClaimingAsync = `
{
"spendableVtxos": [
{
"outpoint": {
"txid": "11cba4cbb06290fb7426157efe439940e1e4143d51bdd20567d7bfd28f0d9090",
"vout": 0
},
"receiver": {
"address": "tark1qgw4gpt40zet7q399hv78z7pdak5sxlcgzhy6y6qq7hw3syeudc6xqsws4tegt5r88eahx7g5try2ua4n9rflsncpresjfwcrq80k0d3systnm98",
"amount": "3000"
},
"spent": false,
"poolTxid": "d6684a5b9e6939dccdf07d1f0eaf7fdd7b31de4d123e63e400d23de739800d4e",
"spentBy": "",
"expireAt": "1726503895",
"swept": false,
"redeemTx": ""
}
],
"spentVtxos": [
{
"outpoint": {
"txid": "94fa598302f17f00c8881e742ec0ce2f8c8d16f3d54fe6ba0fb7d13a493d84ad",
"vout": 0
},
"receiver": {
"address": "tark1qwnakvl59d5wckz9lqhhdav0uvns6uu3zkc6hg65gh0kgh6wve9pwqa8vzms5xcr7pqgt0sw88vc287dse5rw6fnxuk9f08frf8amxjcrya0tkgt",
"amount": "1000"
},
"spent": true,
"poolTxid": "",
"spentBy": "d6684a5b9e6939dccdf07d1f0eaf7fdd7b31de4d123e63e400d23de739800d4e",
"expireAt": "1726054928",
"swept": false,
"redeemTx": "cHNidP8BAIkCAAAAAWwxXUjG5tidFA0LmUljX//jwW6xWaS6HKyRCw5StsxpAAAAAAD/////AugDAAAAAAAAIlEgt2eR8LtqTP7yUcQtSydeGrRiHnVmHHnZwYjdC23G7MZwSQAAAAAAACJRIKfUzf/o9h+r0v9y4nmyOt9qO8EkDumQPQZGTbEv8fSFAAAAAAABASsgTgAAAAAAACJRIKfUzf/o9h+r0v9y4nmyOt9qO8EkDumQPQZGTbEv8fSFIgYDp9sz9Cto7FhF+C929Y/jJw1zkRWxq6NURd9kX05mShcYAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAQRSvBIBey3T0IV353FkuGLMmMJFpqHTrliIsJwJsfJkzq7J0B8bQ0j9842h5lUfOWcbj2TeoFx6OCpgoHIqWIBhHQAFqkBLiRmP3AZ8MS77s1QIWZswMV3L72D9gN0f0MbD6XHkmzZeC1clF3uzxr+13wsF0vcFe29Zl3e2gAhMNGYVCFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wKRtST8P7teUpSF4DAEbfJj5OIXITx5QGbZns/AtxqGyRSCn2zP0K2jsWEX4L3b1j+MnDXORFbGro1RF32RfTmZKF60grwSAXst09CFd+dxZLhizJjCRaah065YiLCcCbHyZM6uswCEWp9sz9Cto7FhF+C929Y/jJw1zkRWxq6NURd9kX05mShc5AbJ0B8bQ0j9842h5lUfOWcbj2TeoFx6OCpgoHIqWIBhHAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAARcgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsAAAAA="
},
{
"outpoint": {
"txid": "766fc46ba5c2da41cd4c4bc0566e0f4e0f24c184c41acd3bead5cd7b11120367",
"vout": 0
},
"receiver": {
"address": "tark1qgw4gpt40zet7q399hv78z7pdak5sxlcgzhy6y6qq7hw3syeudc6xqsws4tegt5r88eahx7g5try2ua4n9rflsncpresjfwcrq80k0d3systnm98",
"amount": "2000"
},
"spent": true,
"poolTxid": "",
"spentBy": "d6684a5b9e6939dccdf07d1f0eaf7fdd7b31de4d123e63e400d23de739800d4e",
"expireAt": "1726486389",
"swept": false,
"redeemTx": "cHNidP8BAIkCAAAAARH6LJRGP/pFIkD/o5bBp8fXAhjl8yjfN7MhJsxdt5lrAQAAAAD/////AtAHAAAAAAAAIlEguuBh3KQUVZp+NHV2sixQ/mrsngCuLCGXzsgJPC1FzY7ANQ8AAAAAACJRIP7uXXtl4jLUcVVQU+sX7WFXmx2H6iCMzn7gye0v1Y8JAAAAAAABAStYPg8AAAAAACJRIP7uXXtl4jLUcVVQU+sX7WFXmx2H6iCMzn7gye0v1Y8JIgYCHVQFdXiyvwIlLdnji8FvbUgb+ECuTRNAB67owJnjcaMYAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAQRSc1yjQ/vHRHev23fKGANLvbOhkNYmGtmRWt8fSszlOJUzRFbnfxd1fq9gIEpaI0vrZww8tlZ94iEL75QoaIbVqQJsPdLYf7fAoXO82VoqwYHu1WevE4g6LxUGBPzfd96q5EEZkoW5qqg+v5dWJUEY467Q6qZLFHwziUaB3KEY8yEpCFcBQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wO5D2Mh3x0XNGxFCS67GNughkENFodpFeVpZjn76chI8RSAdVAV1eLK/AiUt2eOLwW9tSBv4QK5NE0AHrujAmeNxo60gnNco0P7x0R3r9t3yhgDS72zoZDWJhrZkVrfH0rM5TiWswCEWHVQFdXiyvwIlLdnji8FvbUgb+ECuTRNAB67owJnjcaM5AUzRFbnfxd1fq9gIEpaI0vrZww8tlZ94iEL75QoaIbVqAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAARcgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsAAAAA="
}
]
}`
bobAfterSendingAsync = `
{
"spendableVtxos": [
{
"outpoint": {
"txid": "23c3a885f0ea05f7bdf83f3bf7f8ac9dc3f791ad292f4e63a6f53fa5e4935ab0",
"vout": 0
},
"receiver": {
"address": "tark1qwnakvl59d5wckz9lqhhdav0uvns6uu3zkc6hg65gh0kgh6wve9pwqa8vzms5xcr7pqgt0sw88vc287dse5rw6fnxuk9f08frf8amxjcrya0tkgt",
"amount": "900"
},
"spent": false,
"poolTxid": "",
"spentBy": "",
"expireAt": "1726503895",
"swept": false,
"redeemTx": "cHNidP8BAIkCAAAAAdOK9YzYw1ceJznqJxtRXGe0KeHj6CLcLtqLVwcbMCivAAAAAAD/////ArgLAAAAAAAAIlEgC39Vxhw3dIa4heHgFS6X4XwDl1mBggsKLVTBwF1h3qEgegEAAAAAACJRIMkktfIFxFNTtAmy3K0p+7JqVn2kcA0P6y2vJ1QX2zysAAAAAAABASughgEAAAAAACJRIMkktfIFxFNTtAmy3K0p+7JqVn2kcA0P6y2vJ1QX2zysIgYDjGeMfnNwCrU45iB3iRqiFdWTADaiJ968+w3ruFuq1F0YAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAQRTYEOuHJ0hyLBGzY8nSHpD2F1nby5/XQ5Sh2Je+cQ5Wsx0ZucLmB/LLspxMRN9JcJn3Q2KJRMhhg7415cCg1d0gQNSvgaBk/1WLYqQxCKxCfv8ViVJ7vjBxvNO5tc2FEDy27V9cIrfL1jPJoVrhgPZT0GwY7dkVZS7saIKI03CbipBCFcBQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wPKiQ0JM6aw2kcUByijEbOydM3gTIVCGN/69q+dmyxcqRSCMZ4x+c3AKtTjmIHeJGqIV1ZMANqIn3rz7Deu4W6rUXa0g2BDrhydIciwRs2PJ0h6Q9hdZ28uf10OUodiXvnEOVrOswCEWjGeMfnNwCrU45iB3iRqiFdWTADaiJ968+w3ruFuq1F05AR0ZucLmB/LLspxMRN9JcJn3Q2KJRMhhg7415cCg1d0gAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAARcgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsAAAAA="
}
],
"spentVtxos": [
{
"outpoint": {
"txid": "94fa598302f17f00c8881e742ec0ce2f8c8d16f3d54fe6ba0fb7d13a493d84ad",
"vout": 0
},
"receiver": {
"address": "tark1qwnakvl59d5wckz9lqhhdav0uvns6uu3zkc6hg65gh0kgh6wve9pwqa8vzms5xcr7pqgt0sw88vc287dse5rw6fnxuk9f08frf8amxjcrya0tkgt",
"amount": "1000"
},
"spent": true,
"poolTxid": "",
"spentBy": "d6684a5b9e6939dccdf07d1f0eaf7fdd7b31de4d123e63e400d23de739800d4e",
"expireAt": "1726054928",
"swept": false,
"redeemTx": "cHNidP8BAIkCAAAAAWwxXUjG5tidFA0LmUljX//jwW6xWaS6HKyRCw5StsxpAAAAAAD/////AugDAAAAAAAAIlEgt2eR8LtqTP7yUcQtSydeGrRiHnVmHHnZwYjdC23G7MZwSQAAAAAAACJRIKfUzf/o9h+r0v9y4nmyOt9qO8EkDumQPQZGTbEv8fSFAAAAAAABASsgTgAAAAAAACJRIKfUzf/o9h+r0v9y4nmyOt9qO8EkDumQPQZGTbEv8fSFIgYDp9sz9Cto7FhF+C929Y/jJw1zkRWxq6NURd9kX05mShcYAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAQRSvBIBey3T0IV353FkuGLMmMJFpqHTrliIsJwJsfJkzq7J0B8bQ0j9842h5lUfOWcbj2TeoFx6OCpgoHIqWIBhHQAFqkBLiRmP3AZ8MS77s1QIWZswMV3L72D9gN0f0MbD6XHkmzZeC1clF3uzxr+13wsF0vcFe29Zl3e2gAhMNGYVCFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wKRtST8P7teUpSF4DAEbfJj5OIXITx5QGbZns/AtxqGyRSCn2zP0K2jsWEX4L3b1j+MnDXORFbGro1RF32RfTmZKF60grwSAXst09CFd+dxZLhizJjCRaah065YiLCcCbHyZM6uswCEWp9sz9Cto7FhF+C929Y/jJw1zkRWxq6NURd9kX05mShc5AbJ0B8bQ0j9842h5lUfOWcbj2TeoFx6OCpgoHIqWIBhHAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAARcgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsAAAAA="
},
{
"outpoint": {
"txid": "766fc46ba5c2da41cd4c4bc0566e0f4e0f24c184c41acd3bead5cd7b11120367",
"vout": 0
},
"receiver": {
"address": "tark1qgw4gpt40zet7q399hv78z7pdak5sxlcgzhy6y6qq7hw3syeudc6xqsws4tegt5r88eahx7g5try2ua4n9rflsncpresjfwcrq80k0d3systnm98",
"amount": "2000"
},
"spent": true,
"poolTxid": "",
"spentBy": "d6684a5b9e6939dccdf07d1f0eaf7fdd7b31de4d123e63e400d23de739800d4e",
"expireAt": "1726486389",
"swept": false,
"pending": true,
"redeemTx": "cHNidP8BAIkCAAAAARH6LJRGP/pFIkD/o5bBp8fXAhjl8yjfN7MhJsxdt5lrAQAAAAD/////AtAHAAAAAAAAIlEguuBh3KQUVZp+NHV2sixQ/mrsngCuLCGXzsgJPC1FzY7ANQ8AAAAAACJRIP7uXXtl4jLUcVVQU+sX7WFXmx2H6iCMzn7gye0v1Y8JAAAAAAABAStYPg8AAAAAACJRIP7uXXtl4jLUcVVQU+sX7WFXmx2H6iCMzn7gye0v1Y8JIgYCHVQFdXiyvwIlLdnji8FvbUgb+ECuTRNAB67owJnjcaMYAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAQRSc1yjQ/vHRHev23fKGANLvbOhkNYmGtmRWt8fSszlOJUzRFbnfxd1fq9gIEpaI0vrZww8tlZ94iEL75QoaIbVqQJsPdLYf7fAoXO82VoqwYHu1WevE4g6LxUGBPzfd96q5EEZkoW5qqg+v5dWJUEY467Q6qZLFHwziUaB3KEY8yEpCFcBQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wO5D2Mh3x0XNGxFCS67GNughkENFodpFeVpZjn76chI8RSAdVAV1eLK/AiUt2eOLwW9tSBv4QK5NE0AHrujAmeNxo60gnNco0P7x0R3r9t3yhgDS72zoZDWJhrZkVrfH0rM5TiWswCEWHVQFdXiyvwIlLdnji8FvbUgb+ECuTRNAB67owJnjcaM5AUzRFbnfxd1fq9gIEpaI0vrZww8tlZ94iEL75QoaIbVqAAAAAFYAAIAAAACAAQAAgAAAAAAAAAAAARcgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsAAAAA="
},
{
"outpoint": {
"txid": "11cba4cbb06290fb7426157efe439940e1e4143d51bdd20567d7bfd28f0d9090",
"vout": 0
},
"receiver": {
"address": "tark1qgw4gpt40zet7q399hv78z7pdak5sxlcgzhy6y6qq7hw3syeudc6xqsws4tegt5r88eahx7g5try2ua4n9rflsncpresjfwcrq80k0d3systnm98",
"amount": "3000"
},
"spent": false,
"poolTxid": "d6684a5b9e6939dccdf07d1f0eaf7fdd7b31de4d123e63e400d23de739800d4e",
"spentBy": "23c3a885f0ea05f7bdf83f3bf7f8ac9dc3f791ad292f4e63a6f53fa5e4935ab0",
"expireAt": "1726503895",
"swept": false,
"redeemTx": ""
}
]
}`
)

View File

@@ -1679,7 +1679,7 @@ func (a *covenantArkClient) getOffchainBalance(
for _, vtxo := range vtxos { for _, vtxo := range vtxos {
balance += vtxo.Amount balance += vtxo.Amount
if vtxo.ExpiresAt != nil { if !vtxo.ExpiresAt.IsZero() {
expiration := vtxo.ExpiresAt.Unix() expiration := vtxo.ExpiresAt.Unix()
if _, ok := amountByExpiration[expiration]; !ok { if _, ok := amountByExpiration[expiration]; !ok {
@@ -1724,7 +1724,7 @@ func (a *covenantArkClient) getVtxos(
for i, vtxo := range spendableVtxos { for i, vtxo := range spendableVtxos {
if vtxo.Txid == vtxoTxid { if vtxo.Txid == vtxoTxid {
spendableVtxos[i].ExpiresAt = expiration spendableVtxos[i].ExpiresAt = *expiration
break break
} }
} }
@@ -1800,7 +1800,7 @@ func vtxosToTxsCovenant(
}, },
Amount: uint64(math.Abs(float64(amount))), Amount: uint64(math.Abs(float64(amount))),
Type: txType, Type: txType,
CreatedAt: getCreatedAtFromExpiry(roundLifetime, *v.ExpiresAt), CreatedAt: getCreatedAtFromExpiry(roundLifetime, v.ExpiresAt),
}) })
} }

View File

@@ -399,6 +399,7 @@ func (a *covenantlessArkClient) processTransactionEvent(
}, },
Amount: v.Amount, Amount: v.Amount,
ExpiresAt: v.ExpiresAt, ExpiresAt: v.ExpiresAt,
CreatedAt: v.CreatedAt,
RedeemTx: event.Round.Txid, RedeemTx: event.Round.Txid,
Pending: false, Pending: false,
SpentBy: v.SpentBy, SpentBy: v.SpentBy,
@@ -412,7 +413,7 @@ func (a *covenantlessArkClient) processTransactionEvent(
}, },
Amount: v.Amount, Amount: v.Amount,
Type: types.TxReceived, Type: types.TxReceived,
CreatedAt: time.Now(), //TODO is this ok? CreatedAt: v.CreatedAt,
}) })
} }
} }
@@ -477,6 +478,7 @@ func (a *covenantlessArkClient) processTransactionEvent(
}, },
Amount: v.Amount, Amount: v.Amount,
ExpiresAt: v.ExpiresAt, ExpiresAt: v.ExpiresAt,
CreatedAt: v.CreatedAt,
RedeemTx: event.Redeem.Txid, RedeemTx: event.Redeem.Txid,
Pending: true, Pending: true,
SpentBy: v.SpentBy, SpentBy: v.SpentBy,
@@ -492,7 +494,7 @@ func (a *covenantlessArkClient) processTransactionEvent(
}, },
Amount: inputAmount - outputAmount, Amount: inputAmount - outputAmount,
Type: types.TxSent, Type: types.TxSent,
CreatedAt: time.Now(), //TODO is this ok? CreatedAt: time.Now(),
} }
if err := a.store.TransactionStore(). if err := a.store.TransactionStore().
@@ -509,6 +511,7 @@ func (a *covenantlessArkClient) processTransactionEvent(
}, },
Amount: v.Amount, Amount: v.Amount,
ExpiresAt: v.ExpiresAt, ExpiresAt: v.ExpiresAt,
CreatedAt: v.CreatedAt,
RedeemTx: event.Redeem.Txid, RedeemTx: event.Redeem.Txid,
Pending: true, Pending: true,
SpentBy: v.SpentBy, SpentBy: v.SpentBy,
@@ -521,7 +524,7 @@ func (a *covenantlessArkClient) processTransactionEvent(
}, },
Amount: v.Amount, Amount: v.Amount,
Type: types.TxReceived, Type: types.TxReceived,
CreatedAt: time.Now(), //TODO is this ok? CreatedAt: v.CreatedAt,
} }
if err := a.store.TransactionStore(). if err := a.store.TransactionStore().
AddTransactions(context.Background(), []types.Transaction{tx}); err != nil { AddTransactions(context.Background(), []types.Transaction{tx}); err != nil {
@@ -1047,34 +1050,32 @@ func (a *covenantlessArkClient) Settle(ctx context.Context) (string, error) {
func (a *covenantlessArkClient) GetTransactionHistory( func (a *covenantlessArkClient) GetTransactionHistory(
ctx context.Context, ctx context.Context,
) ([]types.Transaction, error) { ) ([]types.Transaction, error) {
if a.Config.WithTransactionFeed {
return a.store.TransactionStore().GetAllTransactions(ctx)
}
if a.Config == nil { if a.Config == nil {
return nil, fmt.Errorf("client not initialized") return nil, fmt.Errorf("client not initialized")
} }
if a.Config.WithTransactionFeed {
return a.store.TransactionStore().GetAllTransactions(ctx)
}
spendableVtxos, spentVtxos, err := a.ListVtxos(ctx) spendableVtxos, spentVtxos, err := a.ListVtxos(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
boardingTxs, ignoreVtxos, err := a.getBoardingTxs(ctx) boardingTxs, _, err := a.getBoardingTxs(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
offchainTxs, err := vtxosToTxsCovenantless( offchainTxs, err := vtxosToTxsCovenantless(spendableVtxos, spentVtxos)
a.Config.RoundLifetime, spendableVtxos, spentVtxos, ignoreVtxos,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
txs := append(boardingTxs, offchainTxs...) txs := append(boardingTxs, offchainTxs...)
// Sort the slice by age // Sort the slice by age
sort.Slice(txs, func(i, j int) bool { sort.SliceStable(txs, func(i, j int) bool {
txi := txs[i] txi := txs[i]
txj := txs[j] txj := txs[j]
if txi.CreatedAt.Equal(txj.CreatedAt) { if txi.CreatedAt.Equal(txj.CreatedAt) {
@@ -1486,6 +1487,11 @@ func (a *covenantlessArkClient) handleRoundStream(
receivers []client.Output, receivers []client.Output,
roundEphemeralKey *secp256k1.PrivateKey, roundEphemeralKey *secp256k1.PrivateKey,
) (string, error) { ) (string, error) {
round, err := a.client.GetRound(ctx, "")
if err != nil {
return "", err
}
eventsCh, close, err := a.client.GetEventStream(ctx, paymentID) eventsCh, close, err := a.client.GetEventStream(ctx, paymentID)
if err != nil { if err != nil {
return "", err return "", err
@@ -1520,14 +1526,32 @@ func (a *covenantlessArkClient) handleRoundStream(
if notify.Err != nil { if notify.Err != nil {
return "", notify.Err return "", notify.Err
} }
if notify.Event == nil {
if step != roundFinalization {
continue
}
res, err := a.client.Ping(ctx, paymentID)
if err != nil {
return "", err
}
if e, ok := res.(client.RoundFinalizedEvent); ok {
log.Infof("round completed %s", e.Txid)
return e.Txid, nil
}
time.Sleep(time.Second)
}
switch event := notify.Event; event.(type) { switch event := notify.Event; event.(type) {
case client.RoundFinalizedEvent: case client.RoundFinalizedEvent:
if step != roundFinalization { if step != roundFinalization {
continue continue
} }
log.Infof("round completed %s", event.(client.RoundFinalizedEvent).Txid)
return event.(client.RoundFinalizedEvent).Txid, nil return event.(client.RoundFinalizedEvent).Txid, nil
case client.RoundFailedEvent: case client.RoundFailedEvent:
return "", fmt.Errorf("round failed: %s", event.(client.RoundFailedEvent).Reason) if event.(client.RoundFailedEvent).ID == round.ID {
return "", fmt.Errorf("round failed: %s", event.(client.RoundFailedEvent).Reason)
}
continue
case client.RoundSigningStartedEvent: case client.RoundSigningStartedEvent:
pingStop() pingStop()
if step != start { if step != start {
@@ -2170,7 +2194,7 @@ func (a *covenantlessArkClient) getOffchainBalance(
for _, vtxo := range vtxos { for _, vtxo := range vtxos {
balance += vtxo.Amount balance += vtxo.Amount
if vtxo.ExpiresAt != nil { if !vtxo.ExpiresAt.IsZero() {
expiration := vtxo.ExpiresAt.Unix() expiration := vtxo.ExpiresAt.Unix()
if _, ok := amountByExpiration[expiration]; !ok { if _, ok := amountByExpiration[expiration]; !ok {
@@ -2321,7 +2345,7 @@ func (a *covenantlessArkClient) getVtxos(
for i, vtxo := range spendableVtxos { for i, vtxo := range spendableVtxos {
if vtxo.Txid == vtxoTxid { if vtxo.Txid == vtxoTxid {
spendableVtxos[i].ExpiresAt = expiration spendableVtxos[i].ExpiresAt = *expiration
break break
} }
} }
@@ -2373,120 +2397,76 @@ func findVtxosBySpentBy(allVtxos []client.Vtxo, txid string) (vtxos []client.Vtx
} }
func vtxosToTxsCovenantless( func vtxosToTxsCovenantless(
roundLifetime int64, spendable, spent []client.Vtxo, ignoreVtxos map[string]struct{}, spendable, spent []client.Vtxo,
) ([]types.Transaction, error) { ) ([]types.Transaction, error) {
transactions := make([]types.Transaction, 0) txs := make([]types.Transaction, 0)
indexedTxs := make(map[string]types.Transaction) vtxosByRound := make(map[string][]client.Vtxo)
settledVtxos := make(map[string]struct{})
// First, loop over all vtxos to find those that have been settled
// (they have round txid instead of redeem tx)
for _, v := range append(spendable, spent...) { for _, v := range append(spendable, spent...) {
_, ok1 := ignoreVtxos[v.Txid] if _, ok := vtxosByRound[v.RoundTxid]; !ok {
_, ok2 := ignoreVtxos[v.RoundTxid] vtxosByRound[v.RoundTxid] = make([]client.Vtxo, 0)
if ok1 || ok2 {
continue
}
if len(v.RoundTxid) > 0 {
settledVtxos[v.RoundTxid] = struct{}{}
} }
vtxosByRound[v.RoundTxid] = append(vtxosByRound[v.RoundTxid], v)
} }
for _, v := range spent { for round := range vtxosByRound {
// If the vtxo is settled, add the record to the tx history. sort.SliceStable(vtxosByRound[round], func(i, j int) bool {
if _, ok := settledVtxos[v.SpentBy]; ok { return vtxosByRound[round][i].CreatedAt.Before(vtxosByRound[round][j].CreatedAt)
transactions = append(transactions, types.Transaction{ })
}
for _, vtxos := range vtxosByRound {
v := vtxos[0]
if v.IsOOR {
txs = append(txs, types.Transaction{
TransactionKey: types.TransactionKey{ TransactionKey: types.TransactionKey{
RedeemTxid: v.Txid, RedeemTxid: v.Txid,
}, },
Amount: v.Amount, Amount: v.Amount,
Type: types.TxReceived, Type: types.TxReceived,
CreatedAt: getCreatedAtFromExpiry(roundLifetime, *v.ExpiresAt), CreatedAt: v.CreatedAt,
Settled: true,
}) })
// Delete any duplicate in the indexed list.
delete(indexedTxs, v.SpentBy)
// Ignore the spendable vtxo created by the settlement.
ignoreVtxos[v.SpentBy] = struct{}{}
continue
} }
if len(vtxos) > 1 {
// If this vtxo spent another one => subtract the amount to find the sent amount. for _, v := range vtxos[1:] {
if tx, ok := indexedTxs[v.Txid]; ok { var tx types.Transaction
tx.Amount -= v.Amount if v.VOut > 0 {
if v.RedeemTx == "" { var spentAmount uint64
tx.RedeemTxid = "" for _, vv := range vtxos {
} else { if vv.SpentBy == v.Txid {
tx.RoundTxid = "" spentAmount += vv.Amount
}
}
tx = types.Transaction{
TransactionKey: types.TransactionKey{
RedeemTxid: v.Txid,
},
Amount: spentAmount - v.Amount,
Type: types.TxSent,
CreatedAt: v.CreatedAt,
}
} else {
tx = types.Transaction{
TransactionKey: types.TransactionKey{
RedeemTxid: v.Txid,
},
Amount: v.Amount,
Type: types.TxReceived,
CreatedAt: v.CreatedAt,
}
}
txs = append(txs, tx)
} }
indexedTxs[v.Txid] = tx
} }
// Add a transaction to the indexed list if not existing.
// This is an intermediate tx state that is updated in the next iterations.
tx, ok := indexedTxs[v.SpentBy]
if !ok {
indexedTxs[v.SpentBy] = types.Transaction{
TransactionKey: types.TransactionKey{
RedeemTxid: v.SpentBy,
RoundTxid: v.SpentBy,
},
Amount: v.Amount,
Type: types.TxSent,
CreatedAt: getCreatedAtFromExpiry(roundLifetime, *v.ExpiresAt),
}
continue
}
// Otherwise add the amount of this vtxo to the one of the tx in the indexed list.
tx.Amount += v.Amount
indexedTxs[v.SpentBy] = tx
} }
for _, v := range spendable { sort.SliceStable(txs, func(i, j int) bool {
// Ignore the vtxo eventually. txi := txs[i]
_, ok1 := ignoreVtxos[v.Txid] txj := txs[j]
_, ok2 := ignoreVtxos[v.RoundTxid] if txi.CreatedAt.Equal(txj.CreatedAt) {
if ok1 || ok2 { return txi.Type > txj.Type
continue
}
txid := v.RoundTxid
if txid == "" {
txid = v.Txid
} }
return txi.CreatedAt.After(txj.CreatedAt)
})
tx, ok := indexedTxs[txid] return txs, nil
// If there is no track of records, add a received tx record in the history.
if !ok {
redeemTxid := ""
if v.RoundTxid == "" {
redeemTxid = v.Txid
}
transactions = append(transactions, types.Transaction{
TransactionKey: types.TransactionKey{
RedeemTxid: redeemTxid,
RoundTxid: v.RoundTxid,
},
Amount: v.Amount,
Type: types.TxReceived,
CreatedAt: getCreatedAtFromExpiry(roundLifetime, *v.ExpiresAt),
})
continue
}
// Otherwise subtract the amount to find the actual spent amount.
tx.Amount -= v.Amount
if v.RedeemTx == "" {
tx.RedeemTxid = ""
} else {
tx.RoundTxid = ""
}
indexedTxs[txid] = tx
}
for _, tx := range indexedTxs {
transactions = append(transactions, tx)
}
return transactions, nil
} }

View File

@@ -128,7 +128,7 @@ func main() {
fmt.Println("") fmt.Println("")
log.Infof("alice is sending %d sats to bob offchain...", amount) log.Infof("alice is sending %d sats to bob offchain...", amount)
if _, err = aliceArkClient.SendOffChain(ctx, false, receivers); err != nil { if _, err = aliceArkClient.SendAsync(ctx, false, receivers); err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@@ -6,7 +6,6 @@ import (
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"fmt" "fmt"
"runtime/debug"
"sort" "sort"
"sync" "sync"
@@ -20,7 +19,7 @@ import (
"github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/vulpemventures/go-elements/address" "github.com/vulpemventures/go-elements/address"
"github.com/vulpemventures/go-elements/network" "github.com/vulpemventures/go-elements/network"
"golang.org/x/crypto/scrypt" "golang.org/x/crypto/pbkdf2"
) )
func CoinSelect( func CoinSelect(
@@ -37,11 +36,7 @@ func CoinSelect(
if sortByExpirationTime { if sortByExpirationTime {
// sort vtxos by expiration (older first) // sort vtxos by expiration (older first)
sort.SliceStable(vtxos, func(i, j int) bool { sort.SliceStable(vtxos, func(i, j int) bool {
if vtxos[i].ExpiresAt == nil || vtxos[j].ExpiresAt == nil { return vtxos[i].ExpiresAt.Before(vtxos[j].ExpiresAt)
return false
}
return vtxos[i].ExpiresAt.Before(*vtxos[j].ExpiresAt)
}) })
sort.SliceStable(boardingUtxos, func(i, j int) bool { sort.SliceStable(boardingUtxos, func(i, j int) bool {
@@ -190,12 +185,7 @@ func HashPassword(password []byte) []byte {
return hash[:] return hash[:]
} }
func EncryptAES128(privateKey, password []byte) ([]byte, error) { func EncryptAES256(privateKey, password []byte) ([]byte, error) {
// Due to https://github.com/golang/go/issues/7168.
// This call makes sure that memory is freed in case the GC doesn't do that
// right after the encryption/decryption.
defer debug.FreeOSMemory()
if len(privateKey) == 0 { if len(privateKey) == 0 {
return nil, fmt.Errorf("missing plaintext private key") return nil, fmt.Errorf("missing plaintext private key")
} }
@@ -227,9 +217,7 @@ func EncryptAES128(privateKey, password []byte) ([]byte, error) {
return ciphertext, nil return ciphertext, nil
} }
func DecryptAES128(encrypted, password []byte) ([]byte, error) { func DecryptAES256(encrypted, password []byte) ([]byte, error) {
defer debug.FreeOSMemory()
if len(encrypted) == 0 { if len(encrypted) == 0 {
return nil, fmt.Errorf("missing encrypted mnemonic") return nil, fmt.Errorf("missing encrypted mnemonic")
} }
@@ -275,12 +263,8 @@ func deriveKey(password, salt []byte) ([]byte, []byte, error) {
return nil, nil, err return nil, nil, err
} }
} }
// 2^20 = 1048576 recommended length for key-stretching iterations := 10000
// check the doc for other recommended values: keySize := 32
// https://godoc.org/golang.org/x/crypto/scrypt key := pbkdf2.Key(password, salt, iterations, keySize, sha256.New)
key, err := scrypt.Key(password, salt, 1048576, 8, 1, 32)
if err != nil {
return nil, nil, err
}
return key, salt, nil return key, salt, nil
} }

View File

@@ -0,0 +1,297 @@
[
{
"name": "alice before sending",
"ignoreTxs": [
"c16ae0d917ac400790da18456015975521bec6e1d1962ad728c0070808c564e8"
],
"spendableVtxos": [
{
"outpoint": {
"txid": "2646aea682389e1739a33a617d1f3ee28ccc7e4e16210936cece7a823e37527e",
"vout": 0
},
"spent": false,
"roundTxid": "c16ae0d917ac400790da18456015975521bec6e1d1962ad728c0070808c564e8",
"spentBy": "",
"expireAt": "1730934927",
"swept": false,
"isOor": false,
"redeemTx": "",
"amount": "20000",
"pubkey": "fc3ed4822401bc75858c6a7e08a974c68a777bcf87e6ba535d48afab7d00cf5f",
"createdAt": "1730330127"
}
],
"spentVtxos": [],
"expectedTxHistory": []
},
{
"name": "alice after sending",
"ignoreTxs": [
"c16ae0d917ac400790da18456015975521bec6e1d1962ad728c0070808c564e8"
],
"spendableVtxos": [
{
"outpoint": {
"txid": "33fd8ca9ea9cfb53802c42be10ae428573e19fb89484dfe536d06d43efa82034",
"vout": 1
},
"spent": false,
"roundTxid": "c16ae0d917ac400790da18456015975521bec6e1d1962ad728c0070808c564e8",
"spentBy": "",
"expireAt": "1730934927",
"swept": false,
"isOor": true,
"redeemTx": "cHNidP8BAIkCAAAAAX5SNz6Ces7ONgkhFk5+zIziPh99YTqjOReeOIKmrkYmAAAAAAD/////AugDAAAAAAAAIlEgqlhusFLr8eZ29t9OrzWRyQ1WqXmHGu+ptn5WGMt8DyVgSQAAAAAAACJRIPw+1IIkAbx1hYxqfgipdMaKd3vPh+a6U11Ir6t9AM9fAAAAAAABASsgTgAAAAAAACJRIPw+1IIkAbx1hYxqfgipdMaKd3vPh+a6U11Ir6t9AM9fQRRzba+JiJXvEqldJ7Squ3RSy3Tygj+kNcbZ9sdwtY13kLn0kC6mChU9UVqsaZC/ptUXmqKnA1BqwBIdRoXN3UIQQPXRlndrrsGBbJZ0P1+K+UWTytCU+O1AZbfg/APqOYkI+e7ne0BRtQVTKu2V8mEMydDRmpy5UCGcr9ZhfRRr6d1BFL+NVPnBYGBLoEcv5/9swwUPUfu0KQNTf5WWzvL0XQGlufSQLqYKFT1RWqxpkL+m1ReaoqcDUGrAEh1Ghc3dQhBANfxQ5evXPI16w88zj7VkcarvA6MUPKjTKmOTzAnYGHUb2GkQa6Ixdg+s/z+Nt5jMyL+KUsiLsuoFeat5dn6r3UIVwVCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrASdfU5FE/s1XZ2TstJV7kIKp/CP0Z2eTjaXuvl4qCX/NFIHNtr4mIle8SqV0ntKq7dFLLdPKCP6Q1xtn2x3C1jXeQrSC/jVT5wWBgS6BHL+f/bMMFD1H7tCkDU3+Vls7y9F0BpazAAAAA",
"amount": "18784",
"pubkey": "fc3ed4822401bc75858c6a7e08a974c68a777bcf87e6ba535d48afab7d00cf5f",
"createdAt": "1730330256"
}
],
"spentVtxos": [
{
"outpoint": {
"txid": "2646aea682389e1739a33a617d1f3ee28ccc7e4e16210936cece7a823e37527e",
"vout": 0
},
"spent": true,
"roundTxid": "c16ae0d917ac400790da18456015975521bec6e1d1962ad728c0070808c564e8",
"spentBy": "33fd8ca9ea9cfb53802c42be10ae428573e19fb89484dfe536d06d43efa82034",
"expireAt": "1730934927",
"swept": false,
"isOor": false,
"redeemTx": "",
"amount": "20000",
"pubkey": "fc3ed4822401bc75858c6a7e08a974c68a777bcf87e6ba535d48afab7d00cf5f",
"createdAt": "1730330127"
}
],
"expectedTxHistory": [
{
"redeemTxid": "33fd8ca9ea9cfb53802c42be10ae428573e19fb89484dfe536d06d43efa82034",
"amount": "1216",
"type": "SENT",
"createdAt": "1730330256"
}
]
},
{
"name": "bob before settling",
"spendableVtxos": [
{
"outpoint": {
"txid": "33fd8ca9ea9cfb53802c42be10ae428573e19fb89484dfe536d06d43efa82034",
"vout": 0
},
"spent": false,
"roundTxid": "c16ae0d917ac400790da18456015975521bec6e1d1962ad728c0070808c564e8",
"spentBy": "",
"expireAt": "1730934927",
"swept": false,
"isOor": true,
"redeemTx": "cHNidP8BAIkCAAAAAX5SNz6Ces7ONgkhFk5+zIziPh99YTqjOReeOIKmrkYmAAAAAAD/////AugDAAAAAAAAIlEgqlhusFLr8eZ29t9OrzWRyQ1WqXmHGu+ptn5WGMt8DyVgSQAAAAAAACJRIPw+1IIkAbx1hYxqfgipdMaKd3vPh+a6U11Ir6t9AM9fAAAAAAABASsgTgAAAAAAACJRIPw+1IIkAbx1hYxqfgipdMaKd3vPh+a6U11Ir6t9AM9fQRRzba+JiJXvEqldJ7Squ3RSy3Tygj+kNcbZ9sdwtY13kLn0kC6mChU9UVqsaZC/ptUXmqKnA1BqwBIdRoXN3UIQQPXRlndrrsGBbJZ0P1+K+UWTytCU+O1AZbfg/APqOYkI+e7ne0BRtQVTKu2V8mEMydDRmpy5UCGcr9ZhfRRr6d1BFL+NVPnBYGBLoEcv5/9swwUPUfu0KQNTf5WWzvL0XQGlufSQLqYKFT1RWqxpkL+m1ReaoqcDUGrAEh1Ghc3dQhBANfxQ5evXPI16w88zj7VkcarvA6MUPKjTKmOTzAnYGHUb2GkQa6Ixdg+s/z+Nt5jMyL+KUsiLsuoFeat5dn6r3UIVwVCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrASdfU5FE/s1XZ2TstJV7kIKp/CP0Z2eTjaXuvl4qCX/NFIHNtr4mIle8SqV0ntKq7dFLLdPKCP6Q1xtn2x3C1jXeQrSC/jVT5wWBgS6BHL+f/bMMFD1H7tCkDU3+Vls7y9F0BpazAAAAA",
"amount": "1000",
"pubkey": "aa586eb052ebf1e676f6df4eaf3591c90d56a979871aefa9b67e5618cb7c0f25",
"createdAt": "1730330256"
},
{
"outpoint": {
"txid": "884d85c0db6b52139c39337d54c1f20cd8c5c0d2e83109d69246a345ccc9d169",
"vout": 0
},
"spent": false,
"roundTxid": "a4e91c211398e0be0edad322fb74a739b1c77bb82b9e4ea94b0115b8e4dfe645",
"spentBy": "",
"expireAt": "1730935548",
"swept": false,
"isOor": true,
"redeemTx": "cHNidP8BAIkCAAAAAT7y41Cb5k0SMpEYaB/3NLlJ8leksHt08k6sK2gRlx3/AAAAAAD/////AtAHAAAAAAAAIlEgqlhusFLr8eZ29t9OrzWRyQ1WqXmHGu+ptn5WGMt8DyVoHgAAAAAAACJRIHnxG3UzOEn7H8oZrxQCVXCjoUVhUEBBgzDLu8ARqongAAAAAAABASsQJwAAAAAAACJRIHnxG3UzOEn7H8oZrxQCVXCjoUVhUEBBgzDLu8ARqongQRRzba+JiJXvEqldJ7Squ3RSy3Tygj+kNcbZ9sdwtY13kH1QsQK/Pk7/PqAmUThCuTCfbTo69ePAgzsvSuR97VgUQBSvpq/lJ7+uc8nyWwV5sCRukn5TnOybRHCjCOUPviykP6C+ue768mRDK6PxQ5FpNJhHmNLpfdTbIQwGCNIJr7pBFOchVKNhwXJqAhCx+u7ObLBb4YqW5vA1iW45rGgxtmP7fVCxAr8+Tv8+oCZROEK5MJ9tOjr148CDOy9K5H3tWBRALxMyiBhy6eGAHjj0OJ+LRFYI8PCIplSLl+SqfMLoSHZzsXkDIyDcLdV6w4Vvq4oBQN+lfKAX2IKZGB0WUGavn0IVwVCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrAL6zdBmWt8+odVYaSKdWl60i5qQGel8jvirsvt2ageslFIHNtr4mIle8SqV0ntKq7dFLLdPKCP6Q1xtn2x3C1jXeQrSDnIVSjYcFyagIQsfruzmywW+GKlubwNYluOaxoMbZj+6zAAAAA",
"amount": "2000",
"pubkey": "aa586eb052ebf1e676f6df4eaf3591c90d56a979871aefa9b67e5618cb7c0f25",
"createdAt": "1730330748"
}
],
"spentVtxos": [],
"expectedTxHistory": [
{
"redeemTxid": "884d85c0db6b52139c39337d54c1f20cd8c5c0d2e83109d69246a345ccc9d169",
"amount": "2000",
"type": "RECEIVED",
"createdAt": "1730330748",
"settled": false
},
{
"redeemTxid": "33fd8ca9ea9cfb53802c42be10ae428573e19fb89484dfe536d06d43efa82034",
"amount": "1000",
"type": "RECEIVED",
"createdAt": "1730330256",
"settled": false
}
]
},
{
"name": "bob after settling",
"spendableVtxos": [
{
"outpoint": {
"txid": "d9c95372c0c419fd007005edd54e21dabac0375a37fc5f17c313bc1e5f483af9",
"vout": 0
},
"spent": false,
"roundTxid": "7fd65ce87e0f9a7af583593d5b0124aabd65c97e05159525d0a98201d6ae95a4",
"spentBy": "",
"expireAt": "1730935835",
"swept": false,
"isOor": false,
"redeemTx": "",
"amount": "3000",
"pubkey": "aa586eb052ebf1e676f6df4eaf3591c90d56a979871aefa9b67e5618cb7c0f25",
"createdAt": "1730331035"
}
],
"spentVtxos": [
{
"outpoint": {
"txid": "33fd8ca9ea9cfb53802c42be10ae428573e19fb89484dfe536d06d43efa82034",
"vout": 0
},
"spent": true,
"roundTxid": "c16ae0d917ac400790da18456015975521bec6e1d1962ad728c0070808c564e8",
"spentBy": "7fd65ce87e0f9a7af583593d5b0124aabd65c97e05159525d0a98201d6ae95a4",
"expireAt": "1730934927",
"swept": false,
"isOor": true,
"redeemTx": "cHNidP8BAIkCAAAAAX5SNz6Ces7ONgkhFk5+zIziPh99YTqjOReeOIKmrkYmAAAAAAD/////AugDAAAAAAAAIlEgqlhusFLr8eZ29t9OrzWRyQ1WqXmHGu+ptn5WGMt8DyVgSQAAAAAAACJRIPw+1IIkAbx1hYxqfgipdMaKd3vPh+a6U11Ir6t9AM9fAAAAAAABASsgTgAAAAAAACJRIPw+1IIkAbx1hYxqfgipdMaKd3vPh+a6U11Ir6t9AM9fQRRzba+JiJXvEqldJ7Squ3RSy3Tygj+kNcbZ9sdwtY13kLn0kC6mChU9UVqsaZC/ptUXmqKnA1BqwBIdRoXN3UIQQPXRlndrrsGBbJZ0P1+K+UWTytCU+O1AZbfg/APqOYkI+e7ne0BRtQVTKu2V8mEMydDRmpy5UCGcr9ZhfRRr6d1BFL+NVPnBYGBLoEcv5/9swwUPUfu0KQNTf5WWzvL0XQGlufSQLqYKFT1RWqxpkL+m1ReaoqcDUGrAEh1Ghc3dQhBANfxQ5evXPI16w88zj7VkcarvA6MUPKjTKmOTzAnYGHUb2GkQa6Ixdg+s/z+Nt5jMyL+KUsiLsuoFeat5dn6r3UIVwVCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrASdfU5FE/s1XZ2TstJV7kIKp/CP0Z2eTjaXuvl4qCX/NFIHNtr4mIle8SqV0ntKq7dFLLdPKCP6Q1xtn2x3C1jXeQrSC/jVT5wWBgS6BHL+f/bMMFD1H7tCkDU3+Vls7y9F0BpazAAAAA",
"amount": "1000",
"pubkey": "aa586eb052ebf1e676f6df4eaf3591c90d56a979871aefa9b67e5618cb7c0f25",
"createdAt": "1730330256"
},
{
"outpoint": {
"txid": "884d85c0db6b52139c39337d54c1f20cd8c5c0d2e83109d69246a345ccc9d169",
"vout": 0
},
"spent": true,
"roundTxid": "a4e91c211398e0be0edad322fb74a739b1c77bb82b9e4ea94b0115b8e4dfe645",
"spentBy": "7fd65ce87e0f9a7af583593d5b0124aabd65c97e05159525d0a98201d6ae95a4",
"expireAt": "1730935548",
"swept": false,
"isOor": true,
"redeemTx": "cHNidP8BAIkCAAAAAT7y41Cb5k0SMpEYaB/3NLlJ8leksHt08k6sK2gRlx3/AAAAAAD/////AtAHAAAAAAAAIlEgqlhusFLr8eZ29t9OrzWRyQ1WqXmHGu+ptn5WGMt8DyVoHgAAAAAAACJRIHnxG3UzOEn7H8oZrxQCVXCjoUVhUEBBgzDLu8ARqongAAAAAAABASsQJwAAAAAAACJRIHnxG3UzOEn7H8oZrxQCVXCjoUVhUEBBgzDLu8ARqongQRRzba+JiJXvEqldJ7Squ3RSy3Tygj+kNcbZ9sdwtY13kH1QsQK/Pk7/PqAmUThCuTCfbTo69ePAgzsvSuR97VgUQBSvpq/lJ7+uc8nyWwV5sCRukn5TnOybRHCjCOUPviykP6C+ue768mRDK6PxQ5FpNJhHmNLpfdTbIQwGCNIJr7pBFOchVKNhwXJqAhCx+u7ObLBb4YqW5vA1iW45rGgxtmP7fVCxAr8+Tv8+oCZROEK5MJ9tOjr148CDOy9K5H3tWBRALxMyiBhy6eGAHjj0OJ+LRFYI8PCIplSLl+SqfMLoSHZzsXkDIyDcLdV6w4Vvq4oBQN+lfKAX2IKZGB0WUGavn0IVwVCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrAL6zdBmWt8+odVYaSKdWl60i5qQGel8jvirsvt2ageslFIHNtr4mIle8SqV0ntKq7dFLLdPKCP6Q1xtn2x3C1jXeQrSDnIVSjYcFyagIQsfruzmywW+GKlubwNYluOaxoMbZj+6zAAAAA",
"amount": "2000",
"pubkey": "aa586eb052ebf1e676f6df4eaf3591c90d56a979871aefa9b67e5618cb7c0f25",
"createdAt": "1730330748"
}
],
"expectedTxHistory": [
{
"redeemTxid": "884d85c0db6b52139c39337d54c1f20cd8c5c0d2e83109d69246a345ccc9d169",
"amount": "2000",
"type": "RECEIVED",
"createdAt": "1730330748",
"settled": false
},
{
"redeemTxid": "33fd8ca9ea9cfb53802c42be10ae428573e19fb89484dfe536d06d43efa82034",
"amount": "1000",
"type": "RECEIVED",
"createdAt": "1730330256",
"settled": false
}
]
},
{
"name": "bob after sending",
"spendableVtxos": [
{
"outpoint": {
"txid": "c59004f8c468a922216f513ec7d63d9b6a13571af0bacd51910709351d27fe55",
"vout": 1
},
"spent": false,
"roundTxid": "7fd65ce87e0f9a7af583593d5b0124aabd65c97e05159525d0a98201d6ae95a4",
"spentBy": "",
"expireAt": "1730935835",
"swept": false,
"isOor": true,
"redeemTx": "cHNidP8BAIkCAAAAAfk6SF8evBPDF1/8N1o3wLraIU7V7QVwAP0ZxMByU8nZAAAAAAD/////AjQIAAAAAAAAIlEgefEbdTM4SfsfyhmvFAJVcKOhRWFQQEGDMMu7wBGqieCsAgAAAAAAACJRIKpYbrBS6/HmdvbfTq81kckNVql5hxrvqbZ+VhjLfA8lAAAAAAABASu4CwAAAAAAACJRIKpYbrBS6/HmdvbfTq81kckNVql5hxrvqbZ+VhjLfA8lQRRzba+JiJXvEqldJ7Squ3RSy3Tygj+kNcbZ9sdwtY13kMkuxL2rXufbKxVtT1EaM9Vz7X2fpReM0c3VdBGWLTt6QOQzMhmzDjjLlb76u3ZS/xfu4DdmpxClsIAtAjvKhMycpjoPpLqdFMZkfRR3hM6rSUHpED+NY2UdqCyyh4EhZKVBFIdwPOfQj0BBcg2i+i3lRh1pA4SOHkW+q0rabgNGEdfiyS7Evate59srFW1PURoz1XPtfZ+lF4zRzdV0EZYtO3pAVlbcq0Z0Fh/BHSNd6IDksw8RC0fitTYPdnaWOmAlUHmH9d343v25QSc6q/2HdE8VoQi3+sQ6cS3Xm+EWBClZAUIVwFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrAUNUCehfUMhBKXlquGl4TQ7nsvjlxxe9WfEPi4eN3DDtFIHNtr4mIle8SqV0ntKq7dFLLdPKCP6Q1xtn2x3C1jXeQrSCHcDzn0I9AQXINovot5UYdaQOEjh5FvqtK2m4DRhHX4qzAAAAA",
"amount": "684",
"pubkey": "aa586eb052ebf1e676f6df4eaf3591c90d56a979871aefa9b67e5618cb7c0f25",
"createdAt": "1730331198"
}
],
"spentVtxos": [
{
"outpoint": {
"txid": "33fd8ca9ea9cfb53802c42be10ae428573e19fb89484dfe536d06d43efa82034",
"vout": 0
},
"spent": true,
"roundTxid": "c16ae0d917ac400790da18456015975521bec6e1d1962ad728c0070808c564e8",
"spentBy": "7fd65ce87e0f9a7af583593d5b0124aabd65c97e05159525d0a98201d6ae95a4",
"expireAt": "1730934927",
"swept": false,
"isOor": true,
"redeemTx": "cHNidP8BAIkCAAAAAX5SNz6Ces7ONgkhFk5+zIziPh99YTqjOReeOIKmrkYmAAAAAAD/////AugDAAAAAAAAIlEgqlhusFLr8eZ29t9OrzWRyQ1WqXmHGu+ptn5WGMt8DyVgSQAAAAAAACJRIPw+1IIkAbx1hYxqfgipdMaKd3vPh+a6U11Ir6t9AM9fAAAAAAABASsgTgAAAAAAACJRIPw+1IIkAbx1hYxqfgipdMaKd3vPh+a6U11Ir6t9AM9fQRRzba+JiJXvEqldJ7Squ3RSy3Tygj+kNcbZ9sdwtY13kLn0kC6mChU9UVqsaZC/ptUXmqKnA1BqwBIdRoXN3UIQQPXRlndrrsGBbJZ0P1+K+UWTytCU+O1AZbfg/APqOYkI+e7ne0BRtQVTKu2V8mEMydDRmpy5UCGcr9ZhfRRr6d1BFL+NVPnBYGBLoEcv5/9swwUPUfu0KQNTf5WWzvL0XQGlufSQLqYKFT1RWqxpkL+m1ReaoqcDUGrAEh1Ghc3dQhBANfxQ5evXPI16w88zj7VkcarvA6MUPKjTKmOTzAnYGHUb2GkQa6Ixdg+s/z+Nt5jMyL+KUsiLsuoFeat5dn6r3UIVwVCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrASdfU5FE/s1XZ2TstJV7kIKp/CP0Z2eTjaXuvl4qCX/NFIHNtr4mIle8SqV0ntKq7dFLLdPKCP6Q1xtn2x3C1jXeQrSC/jVT5wWBgS6BHL+f/bMMFD1H7tCkDU3+Vls7y9F0BpazAAAAA",
"amount": "1000",
"pubkey": "aa586eb052ebf1e676f6df4eaf3591c90d56a979871aefa9b67e5618cb7c0f25",
"createdAt": "1730330256"
},
{
"outpoint": {
"txid": "884d85c0db6b52139c39337d54c1f20cd8c5c0d2e83109d69246a345ccc9d169",
"vout": 0
},
"spent": true,
"roundTxid": "a4e91c211398e0be0edad322fb74a739b1c77bb82b9e4ea94b0115b8e4dfe645",
"spentBy": "7fd65ce87e0f9a7af583593d5b0124aabd65c97e05159525d0a98201d6ae95a4",
"expireAt": "1730935548",
"swept": false,
"isOor": true,
"redeemTx": "cHNidP8BAIkCAAAAAT7y41Cb5k0SMpEYaB/3NLlJ8leksHt08k6sK2gRlx3/AAAAAAD/////AtAHAAAAAAAAIlEgqlhusFLr8eZ29t9OrzWRyQ1WqXmHGu+ptn5WGMt8DyVoHgAAAAAAACJRIHnxG3UzOEn7H8oZrxQCVXCjoUVhUEBBgzDLu8ARqongAAAAAAABASsQJwAAAAAAACJRIHnxG3UzOEn7H8oZrxQCVXCjoUVhUEBBgzDLu8ARqongQRRzba+JiJXvEqldJ7Squ3RSy3Tygj+kNcbZ9sdwtY13kH1QsQK/Pk7/PqAmUThCuTCfbTo69ePAgzsvSuR97VgUQBSvpq/lJ7+uc8nyWwV5sCRukn5TnOybRHCjCOUPviykP6C+ue768mRDK6PxQ5FpNJhHmNLpfdTbIQwGCNIJr7pBFOchVKNhwXJqAhCx+u7ObLBb4YqW5vA1iW45rGgxtmP7fVCxAr8+Tv8+oCZROEK5MJ9tOjr148CDOy9K5H3tWBRALxMyiBhy6eGAHjj0OJ+LRFYI8PCIplSLl+SqfMLoSHZzsXkDIyDcLdV6w4Vvq4oBQN+lfKAX2IKZGB0WUGavn0IVwVCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrAL6zdBmWt8+odVYaSKdWl60i5qQGel8jvirsvt2ageslFIHNtr4mIle8SqV0ntKq7dFLLdPKCP6Q1xtn2x3C1jXeQrSDnIVSjYcFyagIQsfruzmywW+GKlubwNYluOaxoMbZj+6zAAAAA",
"amount": "2000",
"pubkey": "aa586eb052ebf1e676f6df4eaf3591c90d56a979871aefa9b67e5618cb7c0f25",
"createdAt": "1730330748"
},
{
"outpoint": {
"txid": "d9c95372c0c419fd007005edd54e21dabac0375a37fc5f17c313bc1e5f483af9",
"vout": 0
},
"spent": true,
"roundTxid": "7fd65ce87e0f9a7af583593d5b0124aabd65c97e05159525d0a98201d6ae95a4",
"spentBy": "c59004f8c468a922216f513ec7d63d9b6a13571af0bacd51910709351d27fe55",
"expireAt": "1730935835",
"swept": false,
"isOor": false,
"redeemTx": "",
"amount": "3000",
"pubkey": "aa586eb052ebf1e676f6df4eaf3591c90d56a979871aefa9b67e5618cb7c0f25",
"createdAt": "1730331035"
}
],
"expectedTxHistory": [
{
"redeemTxid": "c59004f8c468a922216f513ec7d63d9b6a13571af0bacd51910709351d27fe55",
"amount": "2316",
"type": "SENT",
"createdAt": "1730331198",
"settled": false
},
{
"redeemTxid": "884d85c0db6b52139c39337d54c1f20cd8c5c0d2e83109d69246a345ccc9d169",
"amount": "2000",
"type": "RECEIVED",
"createdAt": "1730330748",
"settled": false
},
{
"redeemTxid": "33fd8ca9ea9cfb53802c42be10ae428573e19fb89484dfe536d06d43efa82034",
"amount": "1000",
"type": "RECEIVED",
"createdAt": "1730330256",
"settled": false
}
]
}
]

View File

@@ -44,7 +44,8 @@ type Vtxo struct {
VtxoKey VtxoKey
Amount uint64 Amount uint64
RoundTxid string RoundTxid string
ExpiresAt *time.Time ExpiresAt time.Time
CreatedAt time.Time
RedeemTx string RedeemTx string
UnconditionalForfeitTxs []string UnconditionalForfeitTxs []string
Pending bool Pending bool

View File

@@ -47,7 +47,7 @@ func (w *singlekeyWallet) Create(
passwordHash := utils.HashPassword(pwd) passwordHash := utils.HashPassword(pwd)
pubkey := privateKey.PubKey() pubkey := privateKey.PubKey()
buf := privateKey.Serialize() buf := privateKey.Serialize()
encryptedPrivateKey, err := utils.EncryptAES128(buf, pwd) encryptedPrivateKey, err := utils.EncryptAES256(buf, pwd)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -104,7 +104,7 @@ func (w *singlekeyWallet) Unlock(
return false, fmt.Errorf("invalid password") return false, fmt.Errorf("invalid password")
} }
privateKeyBytes, err := utils.DecryptAES128(w.walletData.EncryptedPrvkey, pwd) privateKeyBytes, err := utils.DecryptAES256(w.walletData.EncryptedPrvkey, pwd)
if err != nil { if err != nil {
return false, err return false, err
} }

View File

@@ -91,7 +91,7 @@ func (s *configStore) GetData(ctx context.Context) (*types.Config, error) {
roundLifetime, _ := strconv.Atoi(s.store.Call("getItem", "round_lifetime").String()) roundLifetime, _ := strconv.Atoi(s.store.Call("getItem", "round_lifetime").String())
roundInterval, _ := strconv.Atoi(s.store.Call("getItem", "round_interval").String()) roundInterval, _ := strconv.Atoi(s.store.Call("getItem", "round_interval").String())
unilateralExitDelay, _ := strconv.Atoi(s.store.Call("getItem", "unilateral_exit_delay").String()) unilateralExitDelay, _ := strconv.Atoi(s.store.Call("getItem", "unilateral_exit_delay").String())
dust, _ := strconv.Atoi(s.store.Call("getItem", "min_relay_fee").String()) dust, _ := strconv.Atoi(s.store.Call("getItem", "dust").String())
withTxFeed, _ := strconv.ParseBool(s.store.Call("getItem", "with_transaction_feed").String()) withTxFeed, _ := strconv.ParseBool(s.store.Call("getItem", "with_transaction_feed").String())
return &types.Config{ return &types.Config{

View File

@@ -37,6 +37,7 @@ func init() {
js.Global().Set("getTransactionHistory", GetTransactionHistoryWrapper()) js.Global().Set("getTransactionHistory", GetTransactionHistoryWrapper())
js.Global().Set("log", LogWrapper()) js.Global().Set("log", LogWrapper())
js.Global().Set("dump", DumpWrapper()) js.Global().Set("dump", DumpWrapper())
js.Global().Set("listVtxos", ListVtxosWrapper())
js.Global().Set("getAspUrl", GetAspUrlWrapper()) js.Global().Set("getAspUrl", GetAspUrlWrapper())
js.Global().Set("getAspPubKeyHex", GetAspPubkeyWrapper()) js.Global().Set("getAspPubKeyHex", GetAspPubkeyWrapper())

View File

@@ -182,6 +182,27 @@ func DumpWrapper() js.Func {
}) })
} }
func ListVtxosWrapper() js.Func {
return JSPromise(func(args []js.Value) (interface{}, error) {
if arkSdkClient == nil {
return nil, errors.New("ARK SDK client is not initialized")
}
spendable, spent, err := arkSdkClient.ListVtxos(context.Background())
if err != nil {
return nil, err
}
rawList := map[string]interface{}{
"spendable": spendable,
"spent": spent,
}
result, err := json.Marshal(rawList)
if err != nil {
return nil, err
}
return js.ValueOf(string(result)), nil
})
}
func SendOnChainWrapper() js.Func { func SendOnChainWrapper() js.Func {
return JSPromise(func(args []js.Value) (interface{}, error) { return JSPromise(func(args []js.Value) (interface{}, error) {
if len(args) != 1 { if len(args) != 1 {
@@ -234,7 +255,7 @@ func SendAsyncWrapper() js.Func {
} }
withExpiryCoinselect := args[0].Bool() withExpiryCoinselect := args[0].Bool()
receivers, err := parseReceivers(args[0]) receivers, err := parseReceivers(args[1])
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -931,6 +931,8 @@ func (s *covenantService) getNewVtxos(round *domain.Round) []domain.Vtxo {
return nil return nil
} }
createdAt := time.Now().Unix()
leaves := round.CongestionTree.Leaves() leaves := round.CongestionTree.Leaves()
vtxos := make([]domain.Vtxo, 0) vtxos := make([]domain.Vtxo, 0)
for _, node := range leaves { for _, node := range leaves {
@@ -953,6 +955,7 @@ func (s *covenantService) getNewVtxos(round *domain.Round) []domain.Vtxo {
Pubkey: vtxoPubkey, Pubkey: vtxoPubkey,
Amount: uint64(out.Value), Amount: uint64(out.Value),
RoundTxid: round.Txid, RoundTxid: round.Txid,
CreatedAt: createdAt,
}) })
} }
} }

View File

@@ -271,6 +271,7 @@ func (s *covenantlessService) CompleteAsyncPayment(
ExpireAt: asyncPayData.expireAt, ExpireAt: asyncPayData.expireAt,
RoundTxid: asyncPayData.roundTxid, RoundTxid: asyncPayData.roundTxid,
RedeemTx: redeemTx, RedeemTx: redeemTx,
CreatedAt: time.Now().Unix(),
}) })
} }
@@ -1328,6 +1329,8 @@ func (s *covenantlessService) getNewVtxos(round *domain.Round) []domain.Vtxo {
return nil return nil
} }
createdAt := time.Now().Unix()
leaves := round.CongestionTree.Leaves() leaves := round.CongestionTree.Leaves()
vtxos := make([]domain.Vtxo, 0) vtxos := make([]domain.Vtxo, 0)
for _, node := range leaves { for _, node := range leaves {
@@ -1348,6 +1351,7 @@ func (s *covenantlessService) getNewVtxos(round *domain.Round) []domain.Vtxo {
Pubkey: hex.EncodeToString(schnorr.SerializePubKey(vtxoTapKey)), Pubkey: hex.EncodeToString(schnorr.SerializePubKey(vtxoTapKey)),
Amount: uint64(out.Value), Amount: uint64(out.Value),
RoundTxid: round.Txid, RoundTxid: round.Txid,
CreatedAt: createdAt,
}) })
} }
} }

View File

@@ -123,4 +123,5 @@ type Vtxo struct {
Swept bool Swept bool
ExpireAt int64 ExpireAt int64
RedeemTx string // empty if in-round vtxo RedeemTx string // empty if in-round vtxo
CreatedAt int64
} }

View File

@@ -52,6 +52,7 @@ CREATE TABLE IF NOT EXISTS vtxo (
redeemed BOOLEAN NOT NULL, redeemed BOOLEAN NOT NULL,
swept BOOLEAN NOT NULL, swept BOOLEAN NOT NULL,
expire_at INTEGER NOT NULL, expire_at INTEGER NOT NULL,
created_at INTEGER NOT NULL,
payment_id TEXT, payment_id TEXT,
redeem_tx TEXT, redeem_tx TEXT,
PRIMARY KEY (txid, vout), PRIMARY KEY (txid, vout),

View File

@@ -31,6 +31,7 @@ type PaymentVtxoVw struct {
Redeemed sql.NullBool Redeemed sql.NullBool
Swept sql.NullBool Swept sql.NullBool
ExpireAt sql.NullInt64 ExpireAt sql.NullInt64
CreatedAt sql.NullInt64
PaymentID sql.NullString PaymentID sql.NullString
RedeemTx sql.NullString RedeemTx sql.NullString
} }
@@ -97,6 +98,7 @@ type Vtxo struct {
Redeemed bool Redeemed bool
Swept bool Swept bool
ExpireAt int64 ExpireAt int64
CreatedAt int64
PaymentID sql.NullString PaymentID sql.NullString
RedeemTx sql.NullString RedeemTx sql.NullString
} }

View File

@@ -54,7 +54,7 @@ func (q *Queries) MarkVtxoAsSwept(ctx context.Context, arg MarkVtxoAsSweptParams
} }
const selectNotRedeemedVtxos = `-- name: SelectNotRedeemedVtxos :many const selectNotRedeemedVtxos = `-- name: SelectNotRedeemedVtxos :many
SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo
WHERE redeemed = false WHERE redeemed = false
` `
@@ -82,6 +82,7 @@ func (q *Queries) SelectNotRedeemedVtxos(ctx context.Context) ([]SelectNotRedeem
&i.Vtxo.Redeemed, &i.Vtxo.Redeemed,
&i.Vtxo.Swept, &i.Vtxo.Swept,
&i.Vtxo.ExpireAt, &i.Vtxo.ExpireAt,
&i.Vtxo.CreatedAt,
&i.Vtxo.PaymentID, &i.Vtxo.PaymentID,
&i.Vtxo.RedeemTx, &i.Vtxo.RedeemTx,
); err != nil { ); err != nil {
@@ -99,7 +100,7 @@ func (q *Queries) SelectNotRedeemedVtxos(ctx context.Context) ([]SelectNotRedeem
} }
const selectNotRedeemedVtxosWithPubkey = `-- name: SelectNotRedeemedVtxosWithPubkey :many const selectNotRedeemedVtxosWithPubkey = `-- name: SelectNotRedeemedVtxosWithPubkey :many
SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo
WHERE redeemed = false AND pubkey = ? WHERE redeemed = false AND pubkey = ?
` `
@@ -127,6 +128,7 @@ func (q *Queries) SelectNotRedeemedVtxosWithPubkey(ctx context.Context, pubkey s
&i.Vtxo.Redeemed, &i.Vtxo.Redeemed,
&i.Vtxo.Swept, &i.Vtxo.Swept,
&i.Vtxo.ExpireAt, &i.Vtxo.ExpireAt,
&i.Vtxo.CreatedAt,
&i.Vtxo.PaymentID, &i.Vtxo.PaymentID,
&i.Vtxo.RedeemTx, &i.Vtxo.RedeemTx,
); err != nil { ); err != nil {
@@ -207,7 +209,7 @@ SELECT round.id, round.starting_timestamp, round.ending_timestamp, round.ended,
round_payment_vw.id, round_payment_vw.round_id, round_payment_vw.id, round_payment_vw.round_id,
round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf, round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf,
payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.onchain_address, payment_receiver_vw.amount, payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.onchain_address, payment_receiver_vw.amount,
payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.created_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx
FROM round FROM round
LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id
LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id
@@ -271,6 +273,7 @@ func (q *Queries) SelectRoundWithRoundId(ctx context.Context, id string) ([]Sele
&i.PaymentVtxoVw.Redeemed, &i.PaymentVtxoVw.Redeemed,
&i.PaymentVtxoVw.Swept, &i.PaymentVtxoVw.Swept,
&i.PaymentVtxoVw.ExpireAt, &i.PaymentVtxoVw.ExpireAt,
&i.PaymentVtxoVw.CreatedAt,
&i.PaymentVtxoVw.PaymentID, &i.PaymentVtxoVw.PaymentID,
&i.PaymentVtxoVw.RedeemTx, &i.PaymentVtxoVw.RedeemTx,
); err != nil { ); err != nil {
@@ -292,7 +295,7 @@ SELECT round.id, round.starting_timestamp, round.ending_timestamp, round.ended,
round_payment_vw.id, round_payment_vw.round_id, round_payment_vw.id, round_payment_vw.round_id,
round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf, round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf,
payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.onchain_address, payment_receiver_vw.amount, payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.onchain_address, payment_receiver_vw.amount,
payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.created_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx
FROM round FROM round
LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id
LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id
@@ -356,6 +359,7 @@ func (q *Queries) SelectRoundWithRoundTxId(ctx context.Context, txid string) ([]
&i.PaymentVtxoVw.Redeemed, &i.PaymentVtxoVw.Redeemed,
&i.PaymentVtxoVw.Swept, &i.PaymentVtxoVw.Swept,
&i.PaymentVtxoVw.ExpireAt, &i.PaymentVtxoVw.ExpireAt,
&i.PaymentVtxoVw.CreatedAt,
&i.PaymentVtxoVw.PaymentID, &i.PaymentVtxoVw.PaymentID,
&i.PaymentVtxoVw.RedeemTx, &i.PaymentVtxoVw.RedeemTx,
); err != nil { ); err != nil {
@@ -377,7 +381,7 @@ SELECT round.id, round.starting_timestamp, round.ending_timestamp, round.ended,
round_payment_vw.id, round_payment_vw.round_id, round_payment_vw.id, round_payment_vw.round_id,
round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf, round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf,
payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.onchain_address, payment_receiver_vw.amount, payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.onchain_address, payment_receiver_vw.amount,
payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.created_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx
FROM round FROM round
LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id
LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id
@@ -441,6 +445,7 @@ func (q *Queries) SelectSweepableRounds(ctx context.Context) ([]SelectSweepableR
&i.PaymentVtxoVw.Redeemed, &i.PaymentVtxoVw.Redeemed,
&i.PaymentVtxoVw.Swept, &i.PaymentVtxoVw.Swept,
&i.PaymentVtxoVw.ExpireAt, &i.PaymentVtxoVw.ExpireAt,
&i.PaymentVtxoVw.CreatedAt,
&i.PaymentVtxoVw.PaymentID, &i.PaymentVtxoVw.PaymentID,
&i.PaymentVtxoVw.RedeemTx, &i.PaymentVtxoVw.RedeemTx,
); err != nil { ); err != nil {
@@ -458,7 +463,7 @@ func (q *Queries) SelectSweepableRounds(ctx context.Context) ([]SelectSweepableR
} }
const selectSweepableVtxos = `-- name: SelectSweepableVtxos :many const selectSweepableVtxos = `-- name: SelectSweepableVtxos :many
SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo
WHERE redeemed = false AND swept = false WHERE redeemed = false AND swept = false
` `
@@ -486,6 +491,7 @@ func (q *Queries) SelectSweepableVtxos(ctx context.Context) ([]SelectSweepableVt
&i.Vtxo.Redeemed, &i.Vtxo.Redeemed,
&i.Vtxo.Swept, &i.Vtxo.Swept,
&i.Vtxo.ExpireAt, &i.Vtxo.ExpireAt,
&i.Vtxo.CreatedAt,
&i.Vtxo.PaymentID, &i.Vtxo.PaymentID,
&i.Vtxo.RedeemTx, &i.Vtxo.RedeemTx,
); err != nil { ); err != nil {
@@ -507,7 +513,7 @@ SELECT round.id, round.starting_timestamp, round.ending_timestamp, round.ended,
round_payment_vw.id, round_payment_vw.round_id, round_payment_vw.id, round_payment_vw.round_id,
round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf, round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf,
payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.onchain_address, payment_receiver_vw.amount, payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.onchain_address, payment_receiver_vw.amount,
payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.created_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx
FROM round FROM round
LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id
LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id
@@ -571,6 +577,7 @@ func (q *Queries) SelectSweptRounds(ctx context.Context) ([]SelectSweptRoundsRow
&i.PaymentVtxoVw.Redeemed, &i.PaymentVtxoVw.Redeemed,
&i.PaymentVtxoVw.Swept, &i.PaymentVtxoVw.Swept,
&i.PaymentVtxoVw.ExpireAt, &i.PaymentVtxoVw.ExpireAt,
&i.PaymentVtxoVw.CreatedAt,
&i.PaymentVtxoVw.PaymentID, &i.PaymentVtxoVw.PaymentID,
&i.PaymentVtxoVw.RedeemTx, &i.PaymentVtxoVw.RedeemTx,
); err != nil { ); err != nil {
@@ -588,7 +595,7 @@ func (q *Queries) SelectSweptRounds(ctx context.Context) ([]SelectSweptRoundsRow
} }
const selectVtxoByOutpoint = `-- name: SelectVtxoByOutpoint :one const selectVtxoByOutpoint = `-- name: SelectVtxoByOutpoint :one
SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo
WHERE txid = ? AND vout = ? WHERE txid = ? AND vout = ?
` `
@@ -615,6 +622,7 @@ func (q *Queries) SelectVtxoByOutpoint(ctx context.Context, arg SelectVtxoByOutp
&i.Vtxo.Redeemed, &i.Vtxo.Redeemed,
&i.Vtxo.Swept, &i.Vtxo.Swept,
&i.Vtxo.ExpireAt, &i.Vtxo.ExpireAt,
&i.Vtxo.CreatedAt,
&i.Vtxo.PaymentID, &i.Vtxo.PaymentID,
&i.Vtxo.RedeemTx, &i.Vtxo.RedeemTx,
) )
@@ -622,7 +630,7 @@ func (q *Queries) SelectVtxoByOutpoint(ctx context.Context, arg SelectVtxoByOutp
} }
const selectVtxosByPoolTxid = `-- name: SelectVtxosByPoolTxid :many const selectVtxosByPoolTxid = `-- name: SelectVtxosByPoolTxid :many
SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo
WHERE pool_tx = ? WHERE pool_tx = ?
` `
@@ -650,6 +658,7 @@ func (q *Queries) SelectVtxosByPoolTxid(ctx context.Context, poolTx string) ([]S
&i.Vtxo.Redeemed, &i.Vtxo.Redeemed,
&i.Vtxo.Swept, &i.Vtxo.Swept,
&i.Vtxo.ExpireAt, &i.Vtxo.ExpireAt,
&i.Vtxo.CreatedAt,
&i.Vtxo.PaymentID, &i.Vtxo.PaymentID,
&i.Vtxo.RedeemTx, &i.Vtxo.RedeemTx,
); err != nil { ); err != nil {
@@ -838,8 +847,8 @@ func (q *Queries) UpsertTransaction(ctx context.Context, arg UpsertTransactionPa
} }
const upsertVtxo = `-- name: UpsertVtxo :exec const upsertVtxo = `-- name: UpsertVtxo :exec
INSERT INTO vtxo (txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, redeem_tx) INSERT INTO vtxo (txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, created_at, redeem_tx)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET
pubkey = EXCLUDED.pubkey, pubkey = EXCLUDED.pubkey,
amount = EXCLUDED.amount, amount = EXCLUDED.amount,
pool_tx = EXCLUDED.pool_tx, pool_tx = EXCLUDED.pool_tx,
@@ -848,21 +857,23 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET
redeemed = EXCLUDED.redeemed, redeemed = EXCLUDED.redeemed,
swept = EXCLUDED.swept, swept = EXCLUDED.swept,
expire_at = EXCLUDED.expire_at, expire_at = EXCLUDED.expire_at,
created_at = EXCLUDED.created_at,
redeem_tx = EXCLUDED.redeem_tx redeem_tx = EXCLUDED.redeem_tx
` `
type UpsertVtxoParams struct { type UpsertVtxoParams struct {
Txid string Txid string
Vout int64 Vout int64
Pubkey string Pubkey string
Amount int64 Amount int64
PoolTx string PoolTx string
SpentBy string SpentBy string
Spent bool Spent bool
Redeemed bool Redeemed bool
Swept bool Swept bool
ExpireAt int64 ExpireAt int64
RedeemTx sql.NullString CreatedAt int64
RedeemTx sql.NullString
} }
func (q *Queries) UpsertVtxo(ctx context.Context, arg UpsertVtxoParams) error { func (q *Queries) UpsertVtxo(ctx context.Context, arg UpsertVtxoParams) error {
@@ -877,6 +888,7 @@ func (q *Queries) UpsertVtxo(ctx context.Context, arg UpsertVtxoParams) error {
arg.Redeemed, arg.Redeemed,
arg.Swept, arg.Swept,
arg.ExpireAt, arg.ExpireAt,
arg.CreatedAt,
arg.RedeemTx, arg.RedeemTx,
) )
return err return err

View File

@@ -112,8 +112,8 @@ SELECT id FROM round WHERE starting_timestamp > ? AND starting_timestamp < ?;
SELECT id FROM round; SELECT id FROM round;
-- name: UpsertVtxo :exec -- name: UpsertVtxo :exec
INSERT INTO vtxo (txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, redeem_tx) INSERT INTO vtxo (txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, created_at, redeem_tx)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET
pubkey = EXCLUDED.pubkey, pubkey = EXCLUDED.pubkey,
amount = EXCLUDED.amount, amount = EXCLUDED.amount,
pool_tx = EXCLUDED.pool_tx, pool_tx = EXCLUDED.pool_tx,
@@ -122,6 +122,7 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET
redeemed = EXCLUDED.redeemed, redeemed = EXCLUDED.redeemed,
swept = EXCLUDED.swept, swept = EXCLUDED.swept,
expire_at = EXCLUDED.expire_at, expire_at = EXCLUDED.expire_at,
created_at = EXCLUDED.created_at,
redeem_tx = EXCLUDED.redeem_tx; redeem_tx = EXCLUDED.redeem_tx;
-- name: SelectSweepableVtxos :many -- name: SelectSweepableVtxos :many

View File

@@ -40,17 +40,18 @@ func (v *vxtoRepository) AddVtxos(ctx context.Context, vtxos []domain.Vtxo) erro
if err := querierWithTx.UpsertVtxo( if err := querierWithTx.UpsertVtxo(
ctx, queries.UpsertVtxoParams{ ctx, queries.UpsertVtxoParams{
Txid: vtxo.Txid, Txid: vtxo.Txid,
Vout: int64(vtxo.VOut), Vout: int64(vtxo.VOut),
Pubkey: vtxo.Pubkey, Pubkey: vtxo.Pubkey,
Amount: int64(vtxo.Amount), Amount: int64(vtxo.Amount),
PoolTx: vtxo.RoundTxid, PoolTx: vtxo.RoundTxid,
SpentBy: vtxo.SpentBy, SpentBy: vtxo.SpentBy,
Spent: vtxo.Spent, Spent: vtxo.Spent,
Redeemed: vtxo.Redeemed, Redeemed: vtxo.Redeemed,
Swept: vtxo.Swept, Swept: vtxo.Swept,
ExpireAt: vtxo.ExpireAt, ExpireAt: vtxo.ExpireAt,
RedeemTx: sql.NullString{String: vtxo.RedeemTx, Valid: true}, CreatedAt: vtxo.CreatedAt,
RedeemTx: sql.NullString{String: vtxo.RedeemTx, Valid: true},
}, },
); err != nil { ); err != nil {
return err return err
@@ -258,6 +259,7 @@ func rowToVtxo(row queries.Vtxo) domain.Vtxo {
Swept: row.Swept, Swept: row.Swept,
ExpireAt: row.ExpireAt, ExpireAt: row.ExpireAt,
RedeemTx: row.RedeemTx.String, RedeemTx: row.RedeemTx.String,
CreatedAt: row.CreatedAt,
} }
} }

View File

@@ -1222,7 +1222,6 @@ func extractSweepLeaf(input psbt.PInput) (sweepLeaf *psbt.TaprootTapLeafScript,
return nil, nil, 0, err return nil, nil, 0, err
} }
fmt.Println("closure", valid)
if valid && closure.Seconds > 0 { if valid && closure.Seconds > 0 {
sweepLeaf = leaf sweepLeaf = leaf
lifetime = int64(closure.Seconds) lifetime = int64(closure.Seconds)

View File

@@ -126,6 +126,7 @@ func (v vtxoList) toProto() []*arkv1.Vtxo {
RedeemTx: vv.RedeemTx, RedeemTx: vv.RedeemTx,
IsOor: len(vv.RedeemTx) > 0, IsOor: len(vv.RedeemTx) > 0,
Pubkey: vv.Pubkey, Pubkey: vv.Pubkey,
CreatedAt: vv.CreatedAt,
}) })
} }