feat: sync and backup wallet accounts

Changes applied here introduce:
- improvements to sync wallet accounts among devices (including all account types)
- backing up wallet accounts to and fetch them from waku (an information about received
wallet accounts is sent via `waku.backedup.wallet-account` signal to a client)
This commit is contained in:
Sale Djenic 2023-04-19 16:44:57 +02:00 committed by saledjenic
parent 0eff61c57a
commit f1e3ae5b46
12 changed files with 710 additions and 354 deletions

View File

@ -12,6 +12,7 @@ import (
"math/rand" "math/rand"
"os" "os"
"reflect" "reflect"
"runtime"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -77,6 +78,8 @@ const (
publicChat chatContext = "public-chat" publicChat chatContext = "public-chat"
privateChat chatContext = "private-chat" privateChat chatContext = "private-chat"
isMobileApp = runtime.GOOS == "android" || runtime.GOOS == "ios"
) )
const messageResendMinDelay = 30 const messageResendMinDelay = 30
@ -2504,6 +2507,54 @@ func (m *Messenger) DeleteAccount(address types.Address) error {
return m.syncWallets(accs, m.dispatchMessage) return m.syncWallets(accs, m.dispatchMessage)
} }
func (m *Messenger) prepareSyncWalletAccountsMessage(accs []*accounts.Account, clock uint64) *protobuf.SyncWalletAccounts {
accountMessages := make([]*protobuf.SyncWalletAccount, 0)
for _, acc := range accs {
if acc.Chat {
continue
}
// Once mobile app supports seed phrase and private key imported accounts we should remove the following `if` block
if isMobileApp {
if acc.Type != accounts.AccountTypeWatch &&
acc.Type != accounts.AccountTypeGenerated {
continue
}
}
var accountClock uint64
if acc.Clock == 0 {
accountClock = clock
} else {
accountClock = acc.Clock
}
syncMessage := &protobuf.SyncWalletAccount{
Clock: accountClock,
Address: acc.Address.Bytes(),
Wallet: acc.Wallet,
Chat: acc.Chat,
Type: acc.Type.String(),
Storage: acc.Storage,
Path: acc.Path,
PublicKey: acc.PublicKey,
Name: acc.Name,
Color: acc.Color,
Hidden: acc.Hidden,
Removed: acc.Removed,
Emoji: acc.Emoji,
DerivedFrom: acc.DerivedFrom,
KeyUid: acc.KeyUID,
KeypairName: acc.KeypairName,
LastUsedDerivationIndex: acc.LastUsedDerivationIndex,
}
accountMessages = append(accountMessages, syncMessage)
}
return &protobuf.SyncWalletAccounts{
Accounts: accountMessages,
}
}
// syncWallets syncs all wallets with paired devices // syncWallets syncs all wallets with paired devices
func (m *Messenger) syncWallets(accs []*accounts.Account, rawMessageHandler RawMessageHandler) error { func (m *Messenger) syncWallets(accs []*accounts.Account, rawMessageHandler RawMessageHandler) error {
if !m.hasPairedDevices() { if !m.hasPairedDevices() {
@ -2515,38 +2566,7 @@ func (m *Messenger) syncWallets(accs []*accounts.Account, rawMessageHandler RawM
clock, chat := m.getLastClockWithRelatedChat() clock, chat := m.getLastClockWithRelatedChat()
accountMessages := make([]*protobuf.SyncWalletAccount, 0) message := m.prepareSyncWalletAccountsMessage(accs, clock)
for _, acc := range accs {
if acc.Type != accounts.AccountTypeWatch &&
acc.Type != accounts.AccountTypeGenerated {
continue
}
var accountClock uint64
if acc.Clock == 0 {
accountClock = clock
} else {
accountClock = acc.Clock
}
syncMessage := &protobuf.SyncWalletAccount{
Clock: accountClock,
Address: acc.Address.Bytes(),
Wallet: acc.Wallet,
Chat: acc.Chat,
Type: acc.Type.String(),
Storage: acc.Storage,
Path: acc.Path,
PublicKey: acc.PublicKey,
Name: acc.Name,
Color: acc.Color,
Hidden: acc.Hidden,
Removed: acc.Removed,
}
accountMessages = append(accountMessages, syncMessage)
}
message := &protobuf.SyncWalletAccounts{
Accounts: accountMessages,
}
encodedMessage, err := proto.Marshal(message) encodedMessage, err := proto.Marshal(message)
if err != nil { if err != nil {

View File

@ -95,6 +95,11 @@ func (m *Messenger) BackupData(ctx context.Context) (uint64, error) {
return 0, errors[0] return 0, errors[0]
} }
syncWalletAccounts, err := m.backupWalletAccounts(clock)
if err != nil {
return 0, err
}
keycardsToBackup, err := m.prepareSyncAllKeycardsMessage(clock) keycardsToBackup, err := m.prepareSyncAllKeycardsMessage(clock)
if err != nil { if err != nil {
return 0, err return 0, err
@ -119,6 +124,10 @@ func (m *Messenger) BackupData(ctx context.Context) (uint64, error) {
DataNumber: uint32(0), DataNumber: uint32(0),
TotalNumber: uint32(len(settings)), TotalNumber: uint32(len(settings)),
}, },
WalletAccountsDetails: &protobuf.FetchingBackedUpDataDetails{
DataNumber: uint32(0),
TotalNumber: uint32(len(syncWalletAccounts.Accounts)),
},
KeycardsDetails: &protobuf.FetchingBackedUpDataDetails{ KeycardsDetails: &protobuf.FetchingBackedUpDataDetails{
DataNumber: uint32(0), DataNumber: uint32(0),
TotalNumber: uint32(1), TotalNumber: uint32(1),
@ -170,6 +179,17 @@ func (m *Messenger) BackupData(ctx context.Context) (uint64, error) {
} }
} }
// Update wallet accounts messages encode and dispatch
for i, d := range syncWalletAccounts.Accounts {
pb := backupDetailsOnly()
pb.WalletAccountsDetails.DataNumber = uint32(i + 1)
pb.WalletAccount = d
err = m.encodeAndDispatchBackupMessage(ctx, pb, chat.ID)
if err != nil {
return 0, err
}
}
// Update keycards message encode and dispatch // Update keycards message encode and dispatch
pb := backupDetailsOnly() pb := backupDetailsOnly()
pb.KeycardsDetails.DataNumber = 1 pb.KeycardsDetails.DataNumber = 1
@ -379,3 +399,12 @@ func (m *Messenger) backupProfile(ctx context.Context, clock uint64) ([]*protobu
return backupMessages, nil return backupMessages, nil
} }
func (m *Messenger) backupWalletAccounts(clock uint64) (*protobuf.SyncWalletAccounts, error) {
accounts, err := m.settings.GetAccounts()
if err != nil {
return nil, err
}
return m.prepareSyncWalletAccountsMessage(accounts, clock), nil
}

View File

@ -46,6 +46,11 @@ func (m *Messenger) HandleBackup(state *ReceivedMessageState, message protobuf.B
errors = append(errors, err) errors = append(errors, err)
} }
err = m.handleBackedUpWalletAccount(message.WalletAccount)
if err != nil {
errors = append(errors, err)
}
err = m.handleBackedUpKeycards(message.Keycards) err = m.handleBackedUpKeycards(message.Keycards)
if err != nil { if err != nil {
errors = append(errors, err) errors = append(errors, err)
@ -194,7 +199,28 @@ func (m *Messenger) handleBackedUpKeycards(message *protobuf.SyncAllKeycards) er
Keycards: allKeycards, Keycards: allKeycards,
} }
m.config.messengerSignalsHandler.SendWakuBackedUpSettings(&response) m.config.messengerSignalsHandler.SendWakuBackedUpKeycards(&response)
}
return nil
}
func (m *Messenger) handleBackedUpWalletAccount(message *protobuf.SyncWalletAccount) error {
if message == nil {
return nil
}
acc, err := m.handleSyncWalletAccount(message)
if err != nil {
return err
}
if m.config.messengerSignalsHandler != nil {
response := wakusync.WakuBackedUpDataResponse{
WalletAccount: acc,
}
m.config.messengerSignalsHandler.SendWakuBackedUpWalletAccount(&response)
} }
return nil return nil

View File

@ -636,6 +636,62 @@ func (s *MessengerBackupSuite) TestBackupCommunities() {
s.Require().Equal(clock, lastBackup) s.Require().Equal(clock, lastBackup)
} }
func (s *MessengerBackupSuite) TestBackupWalletAccounts() {
// Create bob1
bob1 := s.m
walletAccounts := getWalletAccountsForTest()
s.NoError(bob1.settings.SaveAccounts(walletAccounts))
bob1Accs, err := bob1.settings.GetAccounts()
s.Require().NoError(err, "bob1.settings.GetAccounts")
s.Len(bob1Accs, len(walletAccounts), "must have all wallet accounts")
// Create bob2
bob2, err := newMessengerWithKey(s.shh, bob1.identity, s.logger, nil)
s.Require().NoError(err)
_, err = bob2.Start()
s.Require().NoError(err)
// Backup
_, err = bob1.BackupData(context.Background())
s.Require().NoError(err)
// Wait for the message to reach its destination
_, err = WaitOnMessengerResponse(
bob2,
func(r *MessengerResponse) bool {
return r.BackupHandled
},
"no messages",
)
s.Require().NoError(err)
bob2Accs, err := bob2.settings.GetAccounts()
s.Require().NoError(err, "bob2.settings.GetAccounts")
s.Len(bob2Accs, len(walletAccounts), "must have all wallet accounts")
for _, syncedAcc := range bob2Accs {
if syncedAcc.Chat {
continue
}
found := false
for _, sentAcc := range walletAccounts {
if syncedAcc.Address == sentAcc.Address {
// Check account values match the expected values
s.Require().Equal(sentAcc.Address, syncedAcc.Address)
s.Require().Equal(sentAcc.Path, syncedAcc.Path)
s.Require().Equal(sentAcc.KeyUID, syncedAcc.KeyUID)
s.Require().Equal(sentAcc.Name, syncedAcc.Name)
s.Require().Equal(sentAcc.Color, syncedAcc.Color)
s.Require().Equal(sentAcc.Type, syncedAcc.Type)
s.Require().Equal(sentAcc.KeypairName, syncedAcc.KeypairName)
s.Require().Equal(sentAcc.DerivedFrom, syncedAcc.DerivedFrom)
found = true
}
}
s.Require().True(found)
}
}
func (s *MessengerBackupSuite) TestBackupKeycards() { func (s *MessengerBackupSuite) TestBackupKeycards() {
// Create bob1 // Create bob1
bob1 := s.m bob1 := s.m

View File

@ -56,6 +56,7 @@ type MessengerSignalsHandler interface {
SendWakuFetchingBackupProgress(response *wakusync.WakuBackedUpDataResponse) SendWakuFetchingBackupProgress(response *wakusync.WakuBackedUpDataResponse)
SendWakuBackedUpProfile(response *wakusync.WakuBackedUpDataResponse) SendWakuBackedUpProfile(response *wakusync.WakuBackedUpDataResponse)
SendWakuBackedUpSettings(response *wakusync.WakuBackedUpDataResponse) SendWakuBackedUpSettings(response *wakusync.WakuBackedUpDataResponse)
SendWakuBackedUpWalletAccount(response *wakusync.WakuBackedUpDataResponse)
SendWakuBackedUpKeycards(response *wakusync.WakuBackedUpDataResponse) SendWakuBackedUpKeycards(response *wakusync.WakuBackedUpDataResponse)
} }

View File

@ -6,7 +6,6 @@ import (
"database/sql" "database/sql"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"runtime"
"sync" "sync"
"time" "time"
@ -37,8 +36,14 @@ const (
requestAddressForTransactionDeclinedMessage = "Request address for transaction declined" requestAddressForTransactionDeclinedMessage = "Request address for transaction declined"
) )
var ErrMessageNotAllowed = errors.New("message from a non-contact") var (
var ErrMessageForWrongChatType = errors.New("message for the wrong chat type") ErrMessageNotAllowed = errors.New("message from a non-contact")
ErrMessageForWrongChatType = errors.New("message for the wrong chat type")
ErrNotWalletAccount = errors.New("an account is not a wallet account")
ErrWalletAccountNotSupportedForMobileApp = errors.New("handling account is not supported for mobile app")
ErrTryingToStoreOldWalletAccount = errors.New("trying to store an old wallet account")
ErrSomeFieldsMissingForWalletAccount = errors.New("some fields are missing for wallet account")
)
// HandleMembershipUpdate updates a Chat instance according to the membership updates. // HandleMembershipUpdate updates a Chat instance according to the membership updates.
// It retrieves chat, if exists, and merges membership updates from the message. // It retrieves chat, if exists, and merges membership updates from the message.
@ -2776,55 +2781,90 @@ func (m *Messenger) updateUnviewedCounts(chat *Chat, mentionedOrReplied bool) {
} }
} }
func (m *Messenger) HandleSyncWalletAccount(state *ReceivedMessageState, message protobuf.SyncWalletAccounts) error { func (m *Messenger) handleSyncWalletAccount(message *protobuf.SyncWalletAccount) (*accounts.Account, error) {
dbAccounts, err := m.settings.GetAccounts() if message.Chat {
if err != nil { return nil, ErrNotWalletAccount
return err }
accAddress := types.BytesToAddress(message.Address)
dbAccount, err := m.settings.GetAccountByAddress(accAddress)
if err != nil && err != sql.ErrNoRows {
return nil, err
} }
dbAccountMap := make(map[types.Address]*accounts.Account) // Once mobile app supports seed phrase and private key imported accounts we should remove the following `if` block
for _, acc := range dbAccounts { if isMobileApp {
dbAccountMap[acc.Address] = acc accType := accounts.AccountType(message.Type)
if accType != accounts.AccountTypeWatch &&
accType != accounts.AccountTypeGenerated {
return nil, ErrWalletAccountNotSupportedForMobileApp
}
} }
var accs []*accounts.Account if dbAccount != nil && message.Clock <= dbAccount.Clock {
for _, message := range message.Accounts { return nil, ErrTryingToStoreOldWalletAccount
dbAcc := dbAccountMap[types.BytesToAddress(message.Address)] }
if dbAcc != nil && message.Clock <= dbAcc.Clock {
continue
}
var acc *accounts.Account
if dbAcc != nil && message.Removed {
acc = &accounts.Account{
Address: types.BytesToAddress(message.Address),
Removed: true,
}
} else if !message.Removed {
acc = &accounts.Account{
Address: types.BytesToAddress(message.Address),
Wallet: message.Wallet,
Chat: message.Chat,
Type: accounts.AccountType(message.Type),
Storage: message.Storage,
PublicKey: types.HexBytes(message.PublicKey),
Path: message.Path,
Color: message.Color,
Hidden: message.Hidden,
Name: message.Name,
Clock: message.Clock,
}
var acc *accounts.Account
if dbAccount != nil && message.Removed {
acc = &accounts.Account{
Address: types.BytesToAddress(message.Address),
Removed: true,
}
} else if !message.Removed {
acc = &accounts.Account{
Address: types.BytesToAddress(message.Address),
Wallet: message.Wallet,
Chat: message.Chat,
Type: accounts.AccountType(message.Type),
Storage: message.Storage,
PublicKey: types.HexBytes(message.PublicKey),
Path: message.Path,
Color: message.Color,
Hidden: message.Hidden,
Name: message.Name,
Clock: message.Clock,
KeyUID: message.KeyUid,
Emoji: message.Emoji,
DerivedFrom: message.DerivedFrom,
KeypairName: message.KeypairName,
LastUsedDerivationIndex: message.LastUsedDerivationIndex,
} }
if runtime.GOOS != "android" && runtime.GOOS != "ios" { // Once mobile app supports seed phrase and private key imported accounts we should remove the following line, not entire if block
// For the desktop app we need to ignore accounts with empty `KeypairName` or empty `DerivedFrom` (except if an account if !isMobileApp {
// is not private key imported account or watch only account). Otherwise keypair items will be broken. // For the desktop app we need to ignore accounts:
// - with empty `KeypairName` (except if an account is WatchOnly account) or
// - with empty `DerivedFrom` (except if an account is not private key imported account or watch only account)
// Otherwise keypair items will be broken.
if acc.Type != accounts.AccountTypeWatch { if acc.Type != accounts.AccountTypeWatch {
if len(acc.KeypairName) == 0 || acc.Type != accounts.AccountTypeKey && len(acc.DerivedFrom) == 0 { if len(acc.KeypairName) == 0 || acc.Type != accounts.AccountTypeKey && len(acc.DerivedFrom) == 0 {
continue return nil, ErrSomeFieldsMissingForWalletAccount
} }
} }
} }
}
err = m.settings.SaveAccounts([]*accounts.Account{acc})
if err != nil {
return nil, err
}
return acc, nil
}
func (m *Messenger) HandleSyncWalletAccount(state *ReceivedMessageState, message protobuf.SyncWalletAccounts) error {
var accs []*accounts.Account
for _, accMsg := range message.Accounts {
acc, err := m.handleSyncWalletAccount(accMsg)
if err != nil {
if err == ErrNotWalletAccount ||
err == ErrWalletAccountNotSupportedForMobileApp ||
err == ErrTryingToStoreOldWalletAccount ||
err == ErrSomeFieldsMissingForWalletAccount {
continue
}
return err
}
accs = append(accs, acc) accs = append(accs, acc)
} }
@ -2833,24 +2873,20 @@ func (m *Messenger) HandleSyncWalletAccount(state *ReceivedMessageState, message
return nil return nil
} }
err = m.settings.SaveAccounts(accs) state.Response.Accounts = accs
if err != nil {
return err
}
latestDerivedPath, err := m.settings.GetLatestDerivedPath() if isMobileApp {
if err != nil { latestDerivedPath, err := m.settings.GetLatestDerivedPath()
return err if err != nil {
} return err
}
newPath := latestDerivedPath + uint(len(accs)) newPath := latestDerivedPath + uint(len(accs))
err = m.settings.SaveSettingField(settings.LatestDerivedPath, newPath) err = m.settings.SaveSettingField(settings.LatestDerivedPath, newPath)
if err != nil { if err != nil {
return err return err
} }
if err == nil {
state.Response.Accounts = accs
if state.Response.Settings == nil { if state.Response.Settings == nil {
state.Response.Settings = []*settings.SyncSettingField{} state.Response.Settings = []*settings.SyncSettingField{}
} }
@ -2863,7 +2899,7 @@ func (m *Messenger) HandleSyncWalletAccount(state *ReceivedMessageState, message
}) })
} }
return err return nil
} }
func (m *Messenger) HandleSyncContactRequestDecision(state *ReceivedMessageState, message protobuf.SyncContactRequestDecision) error { func (m *Messenger) HandleSyncContactRequestDecision(state *ReceivedMessageState, message protobuf.SyncContactRequestDecision) error {

View File

@ -65,19 +65,115 @@ func (s *MessengerSyncWalletSuite) newMessenger(shh types.Waku) *Messenger {
return messenger return messenger
} }
func (s *MessengerSyncWalletSuite) TestSyncWallets() { func getWalletAccountsForTest() []*accounts.Account {
defaultAccount := &accounts.Account{
Address: types.Address{0x11},
KeyUID: "0000000000000000000000000000000000000000000000000000000000000001",
Wallet: true,
Chat: false,
Path: "m/44'/60'/0'/0/0",
Name: "Default Account",
Color: "blue",
DerivedFrom: "0x0001",
KeypairName: "Profile Keypair",
LastUsedDerivationIndex: 0,
}
generatedFromDefaultAccount1 := &accounts.Account{
Address: types.Address{0x12},
Type: accounts.AccountTypeGenerated,
KeyUID: defaultAccount.KeyUID,
Path: "m/44'/60'/0'/0/1",
Name: "Generated Acc 1",
Color: "blue",
DerivedFrom: defaultAccount.DerivedFrom,
KeypairName: defaultAccount.KeypairName,
LastUsedDerivationIndex: 1,
}
generatedFromDefaultAccount2 := &accounts.Account{
Address: types.Address{0x13},
Type: accounts.AccountTypeGenerated,
KeyUID: defaultAccount.KeyUID,
Path: "m/44'/60'/0'/0/2",
Name: "Generated Acc 2",
Color: "blue",
DerivedFrom: defaultAccount.DerivedFrom,
KeypairName: defaultAccount.KeypairName,
LastUsedDerivationIndex: 2,
}
seedImportedAccount := &accounts.Account{
Address: types.Address{0x14},
Type: accounts.AccountTypeSeed,
KeyUID: "0000000000000000000000000000000000000000000000000000000000000002",
Path: "m/44'/60'/0'/0/0",
Name: "Seed Imported Account",
Color: "green",
DerivedFrom: "0x0002",
KeypairName: "Seed Keypair",
LastUsedDerivationIndex: 0,
}
generatedFromSeedImportedAccount1 := &accounts.Account{
Address: types.Address{0x15},
Type: accounts.AccountTypeSeed,
KeyUID: seedImportedAccount.KeyUID,
Path: "m/44'/60'/0'/0/1",
Name: "Generated Seed Account 1",
Color: "green",
DerivedFrom: seedImportedAccount.DerivedFrom,
KeypairName: seedImportedAccount.KeypairName,
LastUsedDerivationIndex: 1,
}
generatedFromSeedImportedAccount2 := &accounts.Account{
Address: types.Address{0x16},
Type: accounts.AccountTypeSeed,
KeyUID: seedImportedAccount.KeyUID,
Path: "m/44'/60'/0'/0/2",
Name: "Generated Seed Account 2",
Color: "green",
DerivedFrom: seedImportedAccount.DerivedFrom,
KeypairName: seedImportedAccount.KeypairName,
LastUsedDerivationIndex: 2,
}
keyImportedAccount := &accounts.Account{
Address: types.Address{0x17},
Type: accounts.AccountTypeKey,
KeyUID: "0000000000000000000000000000000000000000000000000000000000000003",
Path: "m",
Name: "Key Imported Account",
Color: "blue",
KeypairName: "Private Key Keypair",
}
watchOnlyAccount1 := &accounts.Account{
Address: types.Address{0x18},
Type: accounts.AccountTypeWatch,
Name: "Watch Only Account 1",
Color: "green",
}
watchOnlyAccount2 := &accounts.Account{
Address: types.Address{0x19},
Type: accounts.AccountTypeWatch,
Name: "Watch Only Account 1",
Color: "green",
}
return []*accounts.Account{
defaultAccount,
generatedFromDefaultAccount1,
generatedFromDefaultAccount2,
seedImportedAccount,
generatedFromSeedImportedAccount1,
generatedFromSeedImportedAccount2,
keyImportedAccount,
watchOnlyAccount1,
watchOnlyAccount2,
}
}
func (s *MessengerSyncWalletSuite) TestSyncWallets() {
mainAccount := &accounts.Account{ mainAccount := &accounts.Account{
Address: types.Address{0x01}, Address: types.Address{0x01},
Wallet: true, Wallet: false,
Chat: true, Chat: true,
} }
watchOnly1 := &accounts.Account{
Address: types.Address{0x02},
Name: "Alice watch only",
Color: "green",
Type: accounts.AccountTypeWatch,
}
// Create a main account on alice // Create a main account on alice
s.NoError(s.m.settings.SaveAccounts([]*accounts.Account{mainAccount})) s.NoError(s.m.settings.SaveAccounts([]*accounts.Account{mainAccount}))
@ -139,28 +235,25 @@ func (s *MessengerSyncWalletSuite) TestSyncWallets() {
err = s.m.EnableInstallation(alicesOtherDevice.installationID) err = s.m.EnableInstallation(alicesOtherDevice.installationID)
s.Require().NoError(err) s.Require().NoError(err)
// Create a watch-only acount on alice // Store wallet accounts on alice's device
s.NoError(s.m.settings.SaveAccounts([]*accounts.Account{watchOnly1})) walletAccounts := getWalletAccountsForTest()
expectedTotalNumOfAccounts := len(walletAccounts) + 1 // plus one for the Status profile account
s.NoError(s.m.settings.SaveAccounts(walletAccounts))
acc1, err = s.m.settings.GetAccounts() acc1, err = s.m.settings.GetAccounts()
s.Require().NoError(err, "alice.settings.GetAccounts") s.Require().NoError(err, "alice.settings.GetAccounts")
s.Len(acc1, 2, "Must have 2 accounts") s.Len(acc1, expectedTotalNumOfAccounts, "Must have all wallet accounts plus one for the Status profile account")
// Trigger's a sync between devices // Trigger's a sync between devices
err = s.m.SyncDevices(context.Background(), "ens-name", "profile-image", nil) err = s.m.SyncDevices(context.Background(), "ens-name", "profile-image", nil)
s.Require().NoError(err) s.Require().NoError(err)
err = tt.RetryWithBackOff(func() error { err = tt.RetryWithBackOff(func() error {
_, err := alicesOtherDevice.RetrieveAll() response, err := alicesOtherDevice.RetrieveAll()
if err != nil { if err != nil {
return err return err
} }
accs, err := alicesOtherDevice.settings.GetAccounts() if len(response.Accounts) != len(walletAccounts) {
if err != nil {
return err
}
if len(accs) != 2 {
return errors.New("no sync wallet account received") return errors.New("no sync wallet account received")
} }
return nil return nil
@ -169,46 +262,47 @@ func (s *MessengerSyncWalletSuite) TestSyncWallets() {
acc2, err = alicesOtherDevice.settings.GetAccounts() acc2, err = alicesOtherDevice.settings.GetAccounts()
s.Require().NoError(err, "alicesOtherDevice.settings.GetAccounts") s.Require().NoError(err, "alicesOtherDevice.settings.GetAccounts")
s.Len(acc2, 2, "Must have 2 accounts") s.Len(acc2, expectedTotalNumOfAccounts, "Must have all wallet accounts plus one for the Status profile account")
found := false for _, syncedAcc := range acc2 {
for _, acc := range acc2 { if syncedAcc.Chat {
if acc.Address == watchOnly1.Address { continue
// Check account values match the expected values
s.Require().Equal(watchOnly1.Address, acc.Address)
s.Require().Equal(watchOnly1.Name, acc.Name)
s.Require().Equal(watchOnly1.Color, acc.Color)
s.Require().Equal(watchOnly1.Type, acc.Type)
found = true
} }
found := false
for _, sentAcc := range walletAccounts {
if syncedAcc.Address == sentAcc.Address {
// Check account values match the expected values
s.Require().Equal(sentAcc.Address, syncedAcc.Address)
s.Require().Equal(sentAcc.Path, syncedAcc.Path)
s.Require().Equal(sentAcc.KeyUID, syncedAcc.KeyUID)
s.Require().Equal(sentAcc.Name, syncedAcc.Name)
s.Require().Equal(sentAcc.Color, syncedAcc.Color)
s.Require().Equal(sentAcc.Type, syncedAcc.Type)
s.Require().Equal(sentAcc.KeypairName, syncedAcc.KeypairName)
s.Require().Equal(sentAcc.DerivedFrom, syncedAcc.DerivedFrom)
found = true
}
}
s.Require().True(found)
} }
s.Require().True(found)
// Updates alice's watch only account attributes // Updates alice's accounts attributes
for _, acc := range walletAccounts {
watchOnly2 := &accounts.Account{ acc.Name = acc.Name + "New"
Address: types.Address{0x03}, acc.Color = "lightblue"
Name: "Alice watch only 2",
Color: "blue",
Type: accounts.AccountTypeWatch,
} }
s.Require().NoError(s.m.SaveAccounts([]*accounts.Account{watchOnly2})) s.Require().NoError(s.m.SaveAccounts(walletAccounts))
// Sync between devices is triggered automatically // Sync between devices is triggered automatically
// via watch account changes subscription // via watch account changes subscription
// Retrieve community link & community // Retrieve community link & community
err = tt.RetryWithBackOff(func() error { err = tt.RetryWithBackOff(func() error {
_, err := alicesOtherDevice.RetrieveAll() response, err := alicesOtherDevice.RetrieveAll()
if err != nil { if err != nil {
return err return err
} }
accs, err := alicesOtherDevice.settings.GetAccounts() if len(response.Accounts) != len(walletAccounts) {
if err != nil {
return err
}
if len(accs) != 3 {
return errors.New("no sync wallet account received") return errors.New("no sync wallet account received")
} }
return nil return nil
@ -217,18 +311,27 @@ func (s *MessengerSyncWalletSuite) TestSyncWallets() {
acc2, err = alicesOtherDevice.settings.GetAccounts() acc2, err = alicesOtherDevice.settings.GetAccounts()
s.Require().NoError(err, "alicesOtherDevice.settings.GetAccounts") s.Require().NoError(err, "alicesOtherDevice.settings.GetAccounts")
s.Len(acc2, 3, "Must have 2 accounts") s.Len(acc2, expectedTotalNumOfAccounts, "Must have all wallet accounts plus one for the Status profile account")
found = false for _, syncedAcc := range acc2 {
for _, acc := range acc2 { if syncedAcc.Chat {
if acc.Address == watchOnly2.Address { continue
// Check account values match the expected values
s.Require().Equal(watchOnly2.Address, acc.Address)
s.Require().Equal(watchOnly2.Name, acc.Name)
s.Require().Equal(watchOnly2.Color, acc.Color)
s.Require().Equal(watchOnly2.Type, acc.Type)
found = true
} }
found := false
for _, sentAcc := range walletAccounts {
if syncedAcc.Address == sentAcc.Address {
// Check account values match the expected values
s.Require().Equal(sentAcc.Address, syncedAcc.Address)
s.Require().Equal(sentAcc.Path, syncedAcc.Path)
s.Require().Equal(sentAcc.KeyUID, syncedAcc.KeyUID)
s.Require().Equal(sentAcc.Name, syncedAcc.Name)
s.Require().Equal(sentAcc.Color, syncedAcc.Color)
s.Require().Equal(sentAcc.Type, syncedAcc.Type)
s.Require().Equal(sentAcc.KeypairName, syncedAcc.KeypairName)
s.Require().Equal(sentAcc.DerivedFrom, syncedAcc.DerivedFrom)
found = true
}
}
s.Require().True(found)
} }
s.Require().True(found)
} }

View File

@ -205,17 +205,19 @@ type Backup struct {
Contacts []*SyncInstallationContactV2 `protobuf:"bytes,3,rep,name=contacts,proto3" json:"contacts,omitempty"` Contacts []*SyncInstallationContactV2 `protobuf:"bytes,3,rep,name=contacts,proto3" json:"contacts,omitempty"`
Communities []*SyncCommunity `protobuf:"bytes,4,rep,name=communities,proto3" json:"communities,omitempty"` Communities []*SyncCommunity `protobuf:"bytes,4,rep,name=communities,proto3" json:"communities,omitempty"`
// newly added details to be backed up to and fetched from waku // newly added details to be backed up to and fetched from waku
ContactsDetails *FetchingBackedUpDataDetails `protobuf:"bytes,5,opt,name=contactsDetails,proto3" json:"contactsDetails,omitempty"` ContactsDetails *FetchingBackedUpDataDetails `protobuf:"bytes,5,opt,name=contactsDetails,proto3" json:"contactsDetails,omitempty"`
CommunitiesDetails *FetchingBackedUpDataDetails `protobuf:"bytes,6,opt,name=communitiesDetails,proto3" json:"communitiesDetails,omitempty"` CommunitiesDetails *FetchingBackedUpDataDetails `protobuf:"bytes,6,opt,name=communitiesDetails,proto3" json:"communitiesDetails,omitempty"`
Profile *BackedUpProfile `protobuf:"bytes,7,opt,name=profile,proto3" json:"profile,omitempty"` Profile *BackedUpProfile `protobuf:"bytes,7,opt,name=profile,proto3" json:"profile,omitempty"`
ProfileDetails *FetchingBackedUpDataDetails `protobuf:"bytes,8,opt,name=profileDetails,proto3" json:"profileDetails,omitempty"` ProfileDetails *FetchingBackedUpDataDetails `protobuf:"bytes,8,opt,name=profileDetails,proto3" json:"profileDetails,omitempty"`
Setting *SyncSetting `protobuf:"bytes,9,opt,name=setting,proto3" json:"setting,omitempty"` Setting *SyncSetting `protobuf:"bytes,9,opt,name=setting,proto3" json:"setting,omitempty"`
SettingsDetails *FetchingBackedUpDataDetails `protobuf:"bytes,10,opt,name=settingsDetails,proto3" json:"settingsDetails,omitempty"` SettingsDetails *FetchingBackedUpDataDetails `protobuf:"bytes,10,opt,name=settingsDetails,proto3" json:"settingsDetails,omitempty"`
Keycards *SyncAllKeycards `protobuf:"bytes,11,opt,name=keycards,proto3" json:"keycards,omitempty"` Keycards *SyncAllKeycards `protobuf:"bytes,11,opt,name=keycards,proto3" json:"keycards,omitempty"`
KeycardsDetails *FetchingBackedUpDataDetails `protobuf:"bytes,12,opt,name=keycardsDetails,proto3" json:"keycardsDetails,omitempty"` KeycardsDetails *FetchingBackedUpDataDetails `protobuf:"bytes,12,opt,name=keycardsDetails,proto3" json:"keycardsDetails,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` WalletAccount *SyncWalletAccount `protobuf:"bytes,13,opt,name=walletAccount,proto3" json:"walletAccount,omitempty"`
XXX_unrecognized []byte `json:"-"` WalletAccountsDetails *FetchingBackedUpDataDetails `protobuf:"bytes,14,opt,name=walletAccountsDetails,proto3" json:"walletAccountsDetails,omitempty"`
XXX_sizecache int32 `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *Backup) Reset() { *m = Backup{} } func (m *Backup) Reset() { *m = Backup{} }
@ -327,6 +329,20 @@ func (m *Backup) GetKeycardsDetails() *FetchingBackedUpDataDetails {
return nil return nil
} }
func (m *Backup) GetWalletAccount() *SyncWalletAccount {
if m != nil {
return m.WalletAccount
}
return nil
}
func (m *Backup) GetWalletAccountsDetails() *FetchingBackedUpDataDetails {
if m != nil {
return m.WalletAccountsDetails
}
return nil
}
type MultiAccount struct { type MultiAccount struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
@ -1962,21 +1978,26 @@ func (m *SyncProfilePictures) GetPictures() []*SyncProfilePicture {
} }
type SyncWalletAccount struct { type SyncWalletAccount struct {
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"` Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
Address []byte `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` Address []byte `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
Wallet bool `protobuf:"varint,3,opt,name=wallet,proto3" json:"wallet,omitempty"` Wallet bool `protobuf:"varint,3,opt,name=wallet,proto3" json:"wallet,omitempty"`
Chat bool `protobuf:"varint,4,opt,name=chat,proto3" json:"chat,omitempty"` Chat bool `protobuf:"varint,4,opt,name=chat,proto3" json:"chat,omitempty"`
Type string `protobuf:"bytes,5,opt,name=type,proto3" json:"type,omitempty"` Type string `protobuf:"bytes,5,opt,name=type,proto3" json:"type,omitempty"`
Storage string `protobuf:"bytes,6,opt,name=storage,proto3" json:"storage,omitempty"` Storage string `protobuf:"bytes,6,opt,name=storage,proto3" json:"storage,omitempty"`
Path string `protobuf:"bytes,7,opt,name=path,proto3" json:"path,omitempty"` Path string `protobuf:"bytes,7,opt,name=path,proto3" json:"path,omitempty"`
PublicKey []byte `protobuf:"bytes,8,opt,name=publicKey,proto3" json:"publicKey,omitempty"` PublicKey []byte `protobuf:"bytes,8,opt,name=publicKey,proto3" json:"publicKey,omitempty"`
Name string `protobuf:"bytes,9,opt,name=name,proto3" json:"name,omitempty"` Name string `protobuf:"bytes,9,opt,name=name,proto3" json:"name,omitempty"`
Color string `protobuf:"bytes,10,opt,name=color,proto3" json:"color,omitempty"` Color string `protobuf:"bytes,10,opt,name=color,proto3" json:"color,omitempty"`
Hidden bool `protobuf:"varint,11,opt,name=hidden,proto3" json:"hidden,omitempty"` Hidden bool `protobuf:"varint,11,opt,name=hidden,proto3" json:"hidden,omitempty"`
Removed bool `protobuf:"varint,12,opt,name=removed,proto3" json:"removed,omitempty"` Removed bool `protobuf:"varint,12,opt,name=removed,proto3" json:"removed,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` Emoji string `protobuf:"bytes,13,opt,name=emoji,proto3" json:"emoji,omitempty"`
XXX_unrecognized []byte `json:"-"` DerivedFrom string `protobuf:"bytes,14,opt,name=derived_from,json=derivedFrom,proto3" json:"derived_from,omitempty"`
XXX_sizecache int32 `json:"-"` KeyUid string `protobuf:"bytes,15,opt,name=key_uid,json=keyUid,proto3" json:"key_uid,omitempty"`
KeypairName string `protobuf:"bytes,16,opt,name=keypair_name,json=keypairName,proto3" json:"keypair_name,omitempty"`
LastUsedDerivationIndex uint64 `protobuf:"varint,17,opt,name=last_used_derivation_index,json=lastUsedDerivationIndex,proto3" json:"last_used_derivation_index,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *SyncWalletAccount) Reset() { *m = SyncWalletAccount{} } func (m *SyncWalletAccount) Reset() { *m = SyncWalletAccount{} }
@ -2088,6 +2109,41 @@ func (m *SyncWalletAccount) GetRemoved() bool {
return false return false
} }
func (m *SyncWalletAccount) GetEmoji() string {
if m != nil {
return m.Emoji
}
return ""
}
func (m *SyncWalletAccount) GetDerivedFrom() string {
if m != nil {
return m.DerivedFrom
}
return ""
}
func (m *SyncWalletAccount) GetKeyUid() string {
if m != nil {
return m.KeyUid
}
return ""
}
func (m *SyncWalletAccount) GetKeypairName() string {
if m != nil {
return m.KeypairName
}
return ""
}
func (m *SyncWalletAccount) GetLastUsedDerivationIndex() uint64 {
if m != nil {
return m.LastUsedDerivationIndex
}
return 0
}
type SyncWalletAccounts struct { type SyncWalletAccounts struct {
Accounts []*SyncWalletAccount `protobuf:"bytes,1,rep,name=accounts,proto3" json:"accounts,omitempty"` Accounts []*SyncWalletAccount `protobuf:"bytes,1,rep,name=accounts,proto3" json:"accounts,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
@ -2953,185 +3009,192 @@ func init() {
} }
var fileDescriptor_d61ab7221f0b5518 = []byte{ var fileDescriptor_d61ab7221f0b5518 = []byte{
// 2877 bytes of a gzipped FileDescriptorProto // 2985 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x39, 0x4d, 0x73, 0x1b, 0xc7, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x19, 0x4d, 0x97, 0x1b, 0x47,
0xb1, 0xc6, 0x07, 0xf1, 0xd1, 0x00, 0x41, 0x70, 0x44, 0x49, 0x10, 0x45, 0x97, 0xa8, 0xb5, 0x5d, 0x31, 0xfa, 0x58, 0x7d, 0x94, 0xb4, 0x5a, 0x6d, 0x7b, 0x6d, 0xcb, 0x6b, 0xe7, 0xd9, 0x9e, 0x24,
0xd6, 0x7b, 0xe5, 0x47, 0xbd, 0x47, 0x3f, 0xc7, 0x8e, 0x6c, 0x97, 0x03, 0x01, 0x88, 0x45, 0x91, 0x2f, 0x86, 0x17, 0xd6, 0xe0, 0x10, 0x12, 0xec, 0xe4, 0x05, 0x59, 0x52, 0xe2, 0xf5, 0xda, 0xf2,
0x04, 0x99, 0x21, 0x21, 0xc7, 0xae, 0x54, 0x6d, 0x0d, 0x77, 0x47, 0xc4, 0x86, 0x8b, 0x5d, 0x64, 0xd2, 0xbb, 0xeb, 0x90, 0xc0, 0x7b, 0xf3, 0xda, 0x33, 0xed, 0x55, 0x67, 0x47, 0x33, 0x62, 0xba,
0x67, 0x40, 0x19, 0xbe, 0x25, 0xa7, 0x9c, 0x73, 0x49, 0x8e, 0x3e, 0x27, 0xb7, 0x54, 0xe5, 0x90, 0xb5, 0x8e, 0x72, 0x02, 0x4e, 0x9c, 0xb9, 0xc0, 0x31, 0x67, 0x8e, 0xbc, 0xc7, 0x81, 0x1b, 0x47,
0x5b, 0x8e, 0xb9, 0xe7, 0x98, 0x1c, 0x72, 0x4e, 0xe5, 0x07, 0xe4, 0x98, 0x9a, 0x9e, 0xd9, 0xc5, 0xee, 0x1c, 0x81, 0x3f, 0xc0, 0xe3, 0x07, 0x70, 0xe4, 0x75, 0x75, 0xcf, 0x68, 0x46, 0x2b, 0x2d,
0x2e, 0x08, 0x30, 0x54, 0xe5, 0x94, 0x13, 0xa6, 0x7b, 0xbb, 0x7b, 0x7b, 0xfa, 0xbb, 0x17, 0xb0, 0xf6, 0xe3, 0xc4, 0x49, 0x5d, 0x35, 0x55, 0xd5, 0xd5, 0xf5, 0xd1, 0x55, 0xd5, 0x82, 0xf5, 0x09,
0x3a, 0x66, 0x5e, 0xe4, 0x05, 0xe7, 0x3b, 0xe3, 0x28, 0x94, 0x21, 0xa9, 0xe0, 0xcf, 0xd9, 0xe4, 0x13, 0xb1, 0x08, 0x8f, 0x77, 0x26, 0x71, 0xa4, 0x22, 0x52, 0xc3, 0x9f, 0x67, 0xd3, 0xe7, 0xdb,
0xe5, 0xe6, 0x2d, 0x31, 0x0d, 0x1c, 0x5b, 0x70, 0x29, 0xbd, 0xe0, 0x5c, 0xe8, 0xc7, 0x9b, 0x16, 0x17, 0xe4, 0x2c, 0xf4, 0x5c, 0xc9, 0x95, 0x12, 0xe1, 0xb1, 0x34, 0x9f, 0xb7, 0x1d, 0x36, 0x99,
0x1b, 0x8f, 0x7d, 0xcf, 0x61, 0xd2, 0x0b, 0x03, 0x7b, 0xc4, 0x25, 0x73, 0x99, 0x64, 0xf6, 0x88, 0x04, 0xc2, 0x63, 0x4a, 0x44, 0xa1, 0x3b, 0xe6, 0x8a, 0xf9, 0x4c, 0x31, 0x77, 0xcc, 0xa5, 0x64,
0x0b, 0xc1, 0xce, 0xb9, 0xa6, 0xb1, 0x18, 0xdc, 0xff, 0x3e, 0x97, 0xce, 0xd0, 0x0b, 0xce, 0x9f, 0xc7, 0xdc, 0xd0, 0x38, 0x0c, 0xae, 0x7e, 0xc2, 0x95, 0x37, 0x12, 0xe1, 0xf1, 0x7d, 0xe6, 0x9d,
0x32, 0xe7, 0x82, 0xbb, 0x83, 0x71, 0x97, 0x49, 0xd6, 0xe5, 0x92, 0x79, 0xbe, 0x20, 0x0f, 0xa0, 0x70, 0xff, 0x68, 0xd2, 0x67, 0x8a, 0xf5, 0xb9, 0x62, 0x22, 0x90, 0xe4, 0x3a, 0x34, 0x90, 0x29,
0x86, 0x4c, 0xc1, 0x64, 0x74, 0xc6, 0xa3, 0x56, 0x6e, 0x3b, 0xf7, 0x68, 0x95, 0x82, 0x42, 0xf5, 0x9c, 0x8e, 0x9f, 0xf1, 0xb8, 0x53, 0xb8, 0x51, 0xb8, 0xb5, 0x4e, 0x41, 0xa3, 0x86, 0x88, 0x21,
0x11, 0x43, 0x1e, 0x42, 0x5d, 0x86, 0x92, 0xf9, 0x31, 0x45, 0x1e, 0x29, 0x6a, 0x88, 0xd3, 0x24, 0x37, 0xa1, 0xa9, 0x22, 0xc5, 0x82, 0x84, 0xa2, 0x88, 0x14, 0x0d, 0xc4, 0x19, 0x12, 0xe7, 0x17,
0xd6, 0x5f, 0x57, 0xa0, 0xa4, 0x64, 0x4f, 0xc6, 0x64, 0x03, 0x56, 0x1c, 0x3f, 0x74, 0x2e, 0x50, 0x55, 0xa8, 0x68, 0xd9, 0xd3, 0x09, 0xd9, 0x82, 0x35, 0x2f, 0x88, 0xbc, 0x13, 0x14, 0x54, 0xa6,
0x50, 0x91, 0x6a, 0x80, 0x34, 0x20, 0xef, 0xb9, 0xc8, 0x59, 0xa5, 0x79, 0xcf, 0x25, 0x9f, 0x41, 0x06, 0x20, 0x2d, 0x28, 0x0a, 0x1f, 0x39, 0xeb, 0xb4, 0x28, 0x7c, 0xf2, 0x31, 0xd4, 0xbc, 0x28,
0xc5, 0x09, 0x03, 0xc9, 0x1c, 0x29, 0x5a, 0x85, 0xed, 0xc2, 0xa3, 0xda, 0xee, 0x5b, 0x3b, 0xf1, 0x54, 0xcc, 0x53, 0xb2, 0x53, 0xba, 0x51, 0xba, 0xd5, 0xb8, 0xf3, 0xc6, 0x4e, 0x72, 0xd2, 0x9d,
0x4d, 0x77, 0x4e, 0xa6, 0x81, 0xb3, 0x17, 0x08, 0xc9, 0x7c, 0x1f, 0x2f, 0xd6, 0xd1, 0x94, 0x2f, 0x83, 0x59, 0xe8, 0xed, 0x86, 0x52, 0xb1, 0x20, 0xc0, 0x83, 0xf5, 0x0c, 0xe5, 0xd3, 0x3b, 0x34,
0x76, 0x69, 0xc2, 0x44, 0xbe, 0x0b, 0x35, 0x27, 0x1c, 0x8d, 0x26, 0x81, 0x27, 0x3d, 0x2e, 0x5a, 0x65, 0x22, 0x3f, 0x84, 0x86, 0x17, 0x8d, 0xc7, 0xd3, 0x50, 0x28, 0xc1, 0x65, 0xa7, 0x8c, 0x32,
0x45, 0x94, 0x71, 0x37, 0x2b, 0xa3, 0x63, 0x08, 0xa6, 0x34, 0x4d, 0x4b, 0x8e, 0x60, 0x2d, 0x16, 0x2e, 0xe7, 0x65, 0xf4, 0x2c, 0xc1, 0x8c, 0x66, 0x69, 0xc9, 0x13, 0xd8, 0x48, 0xc4, 0x58, 0x1b,
0x63, 0x6c, 0xd0, 0x5a, 0xd9, 0xce, 0x3d, 0xaa, 0xed, 0xbe, 0x33, 0x63, 0xbf, 0xc6, 0x60, 0x74, 0x74, 0xd6, 0x6e, 0x14, 0x6e, 0x35, 0xee, 0xbc, 0x35, 0x67, 0x3f, 0xc7, 0x60, 0x74, 0x91, 0x9b,
0x9e, 0x9b, 0x0c, 0x80, 0xa4, 0xe4, 0xc7, 0x32, 0x4b, 0xaf, 0x23, 0x73, 0x81, 0x00, 0xf2, 0x3e, 0x1c, 0x01, 0xc9, 0xc8, 0x4f, 0x64, 0x56, 0x5e, 0x45, 0xe6, 0x12, 0x01, 0xe4, 0x5d, 0xa8, 0x4e,
0x94, 0xc7, 0x51, 0xf8, 0xd2, 0xf3, 0x79, 0xab, 0x8c, 0xb2, 0xee, 0xcd, 0x64, 0xc5, 0x32, 0x8e, 0xe2, 0xe8, 0xb9, 0x08, 0x78, 0xa7, 0x8a, 0xb2, 0xae, 0xcc, 0x65, 0x25, 0x32, 0xf6, 0x0d, 0x01,
0x35, 0x01, 0x8d, 0x29, 0xc9, 0x21, 0x34, 0xcc, 0x31, 0xd6, 0xa3, 0xf2, 0x3a, 0x7a, 0xcc, 0x31, 0x4d, 0x28, 0xc9, 0x63, 0x68, 0xd9, 0x65, 0xa2, 0x47, 0xed, 0x55, 0xf4, 0x58, 0x60, 0x26, 0xb7,
0x93, 0xc7, 0x50, 0x36, 0x11, 0xd7, 0xaa, 0xa2, 0x9c, 0xdb, 0x59, 0x13, 0x9f, 0xe8, 0x87, 0x34, 0xa1, 0x6a, 0x23, 0xae, 0x53, 0x47, 0x39, 0x17, 0xf3, 0x26, 0x3e, 0x30, 0x1f, 0x69, 0x42, 0xa5,
0xa6, 0x52, 0xc6, 0x8d, 0x43, 0x34, 0x56, 0x00, 0x5e, 0xcb, 0xb8, 0x73, 0xdc, 0xe4, 0x03, 0xa8, 0x8d, 0x9b, 0x84, 0x68, 0xa2, 0x00, 0xbc, 0x92, 0x71, 0x17, 0xb8, 0xc9, 0x7b, 0x50, 0x3b, 0xe1,
0x5c, 0xf0, 0xa9, 0xc3, 0x22, 0x57, 0xb4, 0x6a, 0xf3, 0x66, 0x50, 0x2a, 0xb4, 0x7d, 0x7f, 0xdf, 0x33, 0x8f, 0xc5, 0xbe, 0xec, 0x34, 0x16, 0xcd, 0xa0, 0x55, 0xe8, 0x06, 0xc1, 0x9e, 0x25, 0xa0,
0x10, 0xd0, 0x84, 0x54, 0xe9, 0x11, 0x9f, 0x63, 0x3d, 0xea, 0xaf, 0xa5, 0xc7, 0x1c, 0xb7, 0xf5, 0x29, 0xa9, 0xd6, 0x23, 0x59, 0x27, 0x7a, 0x34, 0x5f, 0x49, 0x8f, 0x05, 0x6e, 0xd2, 0x85, 0xf5,
0xf7, 0x22, 0xd4, 0x0f, 0x27, 0xbe, 0xf4, 0xda, 0x8e, 0x13, 0x4e, 0x02, 0x49, 0x08, 0x14, 0x03, 0x17, 0x2c, 0x08, 0xb8, 0xea, 0x7a, 0x5e, 0x34, 0x0d, 0x55, 0x67, 0x1d, 0xc5, 0x5d, 0xcd, 0x2b,
0x36, 0xe2, 0x18, 0xe7, 0x55, 0x8a, 0x67, 0xb2, 0x05, 0x55, 0xe9, 0x8d, 0xb8, 0x90, 0x6c, 0x34, 0xf3, 0x59, 0x96, 0x84, 0xe6, 0x39, 0xc8, 0x4f, 0xe1, 0x62, 0x0e, 0x91, 0x6a, 0xd6, 0x7a, 0x15,
0xc6, 0x68, 0x2f, 0xd0, 0x19, 0x42, 0x3d, 0xf5, 0x5c, 0x1e, 0x48, 0xcf, 0x09, 0x83, 0x56, 0x01, 0xcd, 0x96, 0xcb, 0x70, 0xfe, 0x55, 0x86, 0xe6, 0xe3, 0x69, 0xa0, 0x44, 0xb2, 0x1b, 0x81, 0x72,
0xd9, 0x66, 0x08, 0xf2, 0x19, 0x80, 0x13, 0xfa, 0x61, 0x64, 0x0f, 0x99, 0x18, 0x9a, 0x80, 0xde, 0xc8, 0xc6, 0x1c, 0xf3, 0xb0, 0x4e, 0x71, 0x4d, 0xae, 0x41, 0x5d, 0x89, 0x31, 0x97, 0x8a, 0x8d,
0x9e, 0x29, 0x9b, 0x7e, 0xf7, 0x4e, 0x47, 0x11, 0x3e, 0x63, 0x62, 0x48, 0xab, 0x4e, 0x7c, 0x24, 0x27, 0x98, 0x8d, 0x25, 0x3a, 0x47, 0xe8, 0xaf, 0xc2, 0xe7, 0xa1, 0x12, 0x5e, 0x14, 0x76, 0x4a,
0xf7, 0x54, 0x4e, 0x29, 0x01, 0x9e, 0x8b, 0x01, 0x5d, 0xa0, 0x65, 0x84, 0xf7, 0x5c, 0xf2, 0x6e, 0xc8, 0x36, 0x47, 0x90, 0x8f, 0x01, 0xbc, 0x28, 0x88, 0x62, 0x77, 0xc4, 0xe4, 0xc8, 0x26, 0xdc,
0x62, 0x0d, 0xdb, 0x94, 0x17, 0x0c, 0xcf, 0x2a, 0x6d, 0x18, 0xf4, 0xb1, 0xc6, 0x92, 0xbb, 0x50, 0x8d, 0xb9, 0xca, 0xd9, 0xbd, 0x77, 0x7a, 0x9a, 0xf0, 0x01, 0x93, 0x23, 0x5a, 0xf7, 0x92, 0x25,
0xbe, 0xe0, 0x53, 0x7b, 0xe2, 0xb9, 0x18, 0x73, 0x55, 0x5a, 0xba, 0xe0, 0xd3, 0x81, 0xe7, 0x92, 0xb9, 0xa2, 0x73, 0x5e, 0x0b, 0x10, 0x3e, 0x26, 0x5c, 0x89, 0x56, 0x11, 0xde, 0xf5, 0xc9, 0xdb,
0x4f, 0xa0, 0xe4, 0x8d, 0xd8, 0x39, 0x57, 0xf1, 0xa4, 0x34, 0x7b, 0x7b, 0x89, 0x66, 0x7b, 0x78, 0xa9, 0xb7, 0x5c, 0x7b, 0xfd, 0x61, 0xfa, 0xd4, 0x69, 0xcb, 0xa2, 0xf7, 0x0d, 0x96, 0x5c, 0x86,
0x1f, 0x39, 0xdd, 0x53, 0xc4, 0xd4, 0xf0, 0x90, 0xc7, 0x70, 0xcb, 0x99, 0x08, 0x19, 0x8e, 0xbc, 0xea, 0x09, 0x9f, 0xb9, 0x53, 0xe1, 0x63, 0x4e, 0xd4, 0x69, 0xe5, 0x84, 0xcf, 0x8e, 0x84, 0x4f,
0x6f, 0x74, 0xa9, 0x42, 0xc5, 0x30, 0xa4, 0xaa, 0x94, 0x64, 0x1e, 0xe1, 0xd5, 0x36, 0x1f, 0x42, 0x3e, 0x84, 0x8a, 0x18, 0xb3, 0x63, 0xae, 0xe3, 0x5d, 0x6b, 0xf6, 0xe6, 0x0a, 0xcd, 0x76, 0xf1,
0x35, 0xb9, 0xa3, 0x2a, 0x29, 0x5e, 0xe0, 0xf2, 0xaf, 0x5b, 0xb9, 0xed, 0xc2, 0xa3, 0x02, 0xd5, 0x3c, 0x6a, 0xb6, 0xab, 0x89, 0xa9, 0xe5, 0x21, 0xb7, 0xe1, 0x82, 0x37, 0x95, 0x2a, 0x1a, 0x8b,
0xc0, 0xe6, 0x9f, 0x73, 0xb0, 0x9a, 0x79, 0x5b, 0x5a, 0xf9, 0x5c, 0x46, 0xf9, 0xd8, 0x55, 0xf9, 0xaf, 0xcd, 0x55, 0x8a, 0x8a, 0x61, 0xc8, 0xd7, 0x29, 0xc9, 0x7d, 0xc2, 0xa3, 0x6d, 0xdf, 0x84,
0x94, 0xab, 0x5a, 0x50, 0x1e, 0xb3, 0xa9, 0x1f, 0x32, 0x17, 0x5d, 0x51, 0xa7, 0x31, 0xa8, 0x5e, 0x7a, 0x7a, 0x46, 0x7d, 0xe5, 0x89, 0xd0, 0xe7, 0x5f, 0x75, 0x0a, 0x37, 0x4a, 0xb7, 0x4a, 0xd4,
0xf7, 0xca, 0x73, 0xa5, 0xf2, 0x81, 0x32, 0xa2, 0x06, 0xc8, 0x1d, 0x28, 0x0d, 0xb9, 0x77, 0x3e, 0x00, 0xdb, 0x7f, 0x2b, 0xc0, 0x7a, 0x6e, 0xb7, 0xac, 0xf2, 0x85, 0x9c, 0xf2, 0x89, 0xab, 0x8a,
0x94, 0xc6, 0xb6, 0x06, 0x22, 0x9b, 0x50, 0x51, 0x09, 0x23, 0xbc, 0x6f, 0x38, 0xda, 0xb4, 0x40, 0x19, 0x57, 0x75, 0xa0, 0x3a, 0x61, 0xb3, 0x20, 0x62, 0x3e, 0xba, 0xa2, 0x49, 0x13, 0x50, 0x6f,
0x13, 0x98, 0xbc, 0x05, 0xab, 0x11, 0x9e, 0x6c, 0xc9, 0xa2, 0x73, 0x2e, 0xd1, 0xa6, 0x05, 0x5a, 0xf7, 0x42, 0xf8, 0x4a, 0xfb, 0x40, 0x1b, 0xd1, 0x00, 0xe4, 0x12, 0x54, 0x46, 0x5c, 0x1c, 0x8f,
0xd7, 0xc8, 0x53, 0xc4, 0xcd, 0x0a, 0x66, 0x25, 0x55, 0x30, 0xad, 0x3f, 0xe5, 0xe0, 0xd6, 0x41, 0x94, 0xb5, 0xad, 0x85, 0xc8, 0x36, 0xd4, 0x74, 0x42, 0x4b, 0xf1, 0x35, 0x47, 0x9b, 0x96, 0x68,
0xe8, 0x30, 0xdf, 0x78, 0xe6, 0xd8, 0x28, 0xf7, 0x01, 0x14, 0x2f, 0xf8, 0x54, 0xa0, 0x29, 0x6a, 0x0a, 0x93, 0x37, 0x60, 0x3d, 0xc6, 0x95, 0xab, 0x58, 0x7c, 0xcc, 0x15, 0xda, 0xb4, 0x44, 0x9b,
0xbb, 0x0f, 0x67, 0x5e, 0x58, 0x40, 0xbc, 0xb3, 0xcf, 0xa7, 0x14, 0xc9, 0xc9, 0x13, 0xa8, 0x8f, 0x06, 0x79, 0x88, 0xb8, 0xf9, 0x85, 0x5e, 0xcb, 0x5c, 0xe8, 0xce, 0x5f, 0x0b, 0x70, 0xe1, 0x51,
0x94, 0x9b, 0x98, 0x76, 0x13, 0x5a, 0xa2, 0xb6, 0x7b, 0x67, 0xb1, 0x13, 0x69, 0x86, 0x56, 0xdd, 0xe4, 0xb1, 0xc0, 0x7a, 0x66, 0xdf, 0x2a, 0xf7, 0x1e, 0x94, 0x4f, 0xf8, 0x4c, 0xa2, 0x29, 0x1a,
0x70, 0xcc, 0x84, 0x78, 0x15, 0x46, 0xae, 0x89, 0xda, 0x04, 0xde, 0xfc, 0x1f, 0x28, 0xec, 0xf3, 0x77, 0x6e, 0xce, 0xbd, 0xb0, 0x84, 0x78, 0x67, 0x8f, 0xcf, 0x28, 0x92, 0x93, 0xbb, 0xd0, 0x1c,
0xe9, 0xc2, 0x5c, 0x20, 0x50, 0x54, 0x4d, 0x04, 0x5f, 0x55, 0xa7, 0x78, 0xb6, 0x7e, 0x9f, 0x83, 0x6b, 0x37, 0x31, 0x9b, 0x5c, 0x45, 0xcc, 0x88, 0x4b, 0xcb, 0x9d, 0x48, 0x73, 0xb4, 0xfa, 0x84,
0xdb, 0x19, 0x45, 0x39, 0x8f, 0x9e, 0x71, 0xdf, 0x0f, 0x55, 0x84, 0x9a, 0xc8, 0xb4, 0x2f, 0x79, 0x13, 0x26, 0xe5, 0x8b, 0x28, 0xf6, 0x6d, 0xd4, 0xa6, 0xf0, 0xf6, 0x77, 0xa0, 0xb4, 0xc7, 0x67,
0x24, 0xbc, 0x30, 0x40, 0x61, 0x2b, 0xb4, 0x61, 0xd0, 0x2f, 0x34, 0x56, 0x39, 0x79, 0xcc, 0x39, 0x4b, 0x73, 0x81, 0x40, 0x59, 0x17, 0x39, 0xdc, 0xaa, 0x49, 0x71, 0xed, 0xfc, 0xa9, 0x00, 0x17,
0x06, 0xb9, 0x96, 0x5c, 0x52, 0xe0, 0x9e, 0x8b, 0x7d, 0x8c, 0x5f, 0x7a, 0x0e, 0xb7, 0x51, 0x15, 0x73, 0x8a, 0x72, 0x1e, 0x3f, 0xe0, 0x41, 0x10, 0xe9, 0x08, 0xb5, 0x91, 0xe9, 0x9e, 0xf2, 0x58,
0xad, 0x29, 0x68, 0x54, 0x5f, 0x29, 0x34, 0x23, 0x90, 0xd3, 0x31, 0x47, 0xef, 0x26, 0x04, 0xa7, 0x8a, 0x28, 0x44, 0x61, 0x6b, 0xb4, 0x65, 0xd1, 0x4f, 0x0d, 0x56, 0x3b, 0x79, 0xc2, 0x39, 0x06,
0xd3, 0x31, 0x66, 0xaf, 0xf0, 0xce, 0x03, 0x26, 0x27, 0x11, 0x47, 0x2f, 0xd7, 0xe9, 0x0c, 0x61, 0xb9, 0x91, 0x5c, 0xd1, 0xe0, 0xae, 0x8f, 0x75, 0x96, 0x9f, 0x0a, 0x8f, 0xbb, 0xa8, 0x8a, 0xd1,
0x7d, 0x9b, 0x83, 0xa6, 0x52, 0x3b, 0xdd, 0x99, 0x96, 0x74, 0xbb, 0x77, 0x61, 0xcd, 0x4b, 0x51, 0x14, 0x0c, 0x6a, 0xa8, 0x15, 0x9a, 0x13, 0xa8, 0xd9, 0x84, 0xa3, 0x77, 0x53, 0x82, 0xc3, 0xd9,
0xd9, 0x49, 0xeb, 0x6b, 0xa4, 0xd1, 0x19, 0x9d, 0x51, 0xa5, 0xc2, 0x15, 0x95, 0x62, 0xc3, 0x16, 0x04, 0xb3, 0x57, 0x8a, 0xe3, 0x90, 0xa9, 0x69, 0xcc, 0xd1, 0xcb, 0x4d, 0x3a, 0x47, 0x38, 0xdf,
0xb3, 0x91, 0x1b, 0x9b, 0x68, 0x05, 0x5b, 0x71, 0x0c, 0x5a, 0x7f, 0xcb, 0xc1, 0xdd, 0x25, 0xcd, 0x14, 0xa0, 0xad, 0xd5, 0xce, 0x56, 0xce, 0x15, 0xd5, 0xf8, 0x6d, 0xd8, 0x10, 0x19, 0x2a, 0x37,
0xf3, 0x86, 0x7d, 0xf9, 0x2d, 0x58, 0x35, 0x1d, 0xc0, 0xc6, 0xd4, 0x35, 0x2a, 0xd5, 0x0d, 0x52, 0x2d, 0xcd, 0xad, 0x2c, 0x3a, 0xa7, 0x33, 0xaa, 0x54, 0x3a, 0xa3, 0x52, 0x62, 0xd8, 0x72, 0x3e,
0xe7, 0xd9, 0x3d, 0xa8, 0xf0, 0x40, 0xd8, 0x29, 0xc5, 0xca, 0x3c, 0x10, 0x68, 0xe3, 0x87, 0x50, 0x72, 0x13, 0x13, 0xad, 0x61, 0xab, 0x90, 0x80, 0xce, 0x3f, 0x0b, 0x70, 0x79, 0x45, 0x71, 0x7f,
0xf7, 0x99, 0x90, 0xf6, 0x64, 0xec, 0x32, 0xc9, 0x75, 0x1d, 0x2a, 0xd2, 0x9a, 0xc2, 0x0d, 0x34, 0xc9, 0xbe, 0xe1, 0x0d, 0x58, 0xb7, 0x15, 0xca, 0xc5, 0xd4, 0xb5, 0x2a, 0x35, 0x2d, 0xd2, 0xe4,
0x4a, 0xdd, 0x59, 0x4c, 0x85, 0xe4, 0x23, 0x5b, 0xb2, 0x73, 0xd5, 0x26, 0x0b, 0xea, 0xce, 0x1a, 0xd9, 0x15, 0xa8, 0xf1, 0x50, 0xba, 0x19, 0xc5, 0xaa, 0x3c, 0x94, 0x68, 0xe3, 0x9b, 0xd0, 0x0c,
0x75, 0xca, 0xce, 0x05, 0x79, 0x07, 0x1a, 0xbe, 0x8a, 0x11, 0x3b, 0xf0, 0x9c, 0x0b, 0x7c, 0x89, 0x98, 0x54, 0xee, 0x74, 0xe2, 0x33, 0xc5, 0xcd, 0x3d, 0x54, 0xa6, 0x0d, 0x8d, 0x3b, 0x32, 0x28,
0x2e, 0x45, 0xab, 0x88, 0xed, 0x1b, 0xa4, 0xf5, 0xd3, 0x12, 0xdc, 0x5b, 0x3a, 0x29, 0x90, 0xff, 0x7d, 0x66, 0x39, 0x93, 0x8a, 0x8f, 0x5d, 0xc5, 0x8e, 0x75, 0x19, 0x2f, 0xe9, 0x33, 0x1b, 0xd4,
0x85, 0x8d, 0xb4, 0x22, 0x36, 0xf2, 0xfa, 0x53, 0x73, 0x7b, 0x92, 0x52, 0xe8, 0x40, 0x3f, 0xf9, 0x21, 0x3b, 0x96, 0xe4, 0x2d, 0x68, 0x05, 0x3a, 0x46, 0xdc, 0x50, 0x78, 0x27, 0xb8, 0x89, 0xb9,
0x0f, 0x36, 0x85, 0xf2, 0x2d, 0x73, 0x5d, 0xee, 0x62, 0x41, 0xad, 0x50, 0x0d, 0xa8, 0x38, 0x39, 0x8a, 0xd6, 0x11, 0x3b, 0xb4, 0x48, 0xe7, 0x97, 0x15, 0xb8, 0xb2, 0xb2, 0x93, 0x21, 0xdf, 0x85,
0x53, 0x4e, 0xe6, 0x2e, 0xb6, 0xe0, 0x0a, 0x8d, 0x41, 0x45, 0x3f, 0x9a, 0x28, 0x9d, 0x6a, 0x9a, 0xad, 0xac, 0x22, 0x2e, 0xf2, 0x06, 0x33, 0x7b, 0x7a, 0x92, 0x51, 0xe8, 0x91, 0xf9, 0xf2, 0x7f,
0x1e, 0x01, 0x45, 0x1f, 0xf1, 0x51, 0x78, 0xc9, 0x5d, 0x6c, 0x95, 0x15, 0x1a, 0x83, 0x64, 0x1b, 0x6c, 0x0a, 0xed, 0x5b, 0xe6, 0xfb, 0xdc, 0xc7, 0x0b, 0xb5, 0x46, 0x0d, 0xa0, 0xe3, 0xe4, 0x99,
0xea, 0x43, 0x26, 0x6c, 0x14, 0x6b, 0x4f, 0x44, 0x6b, 0x15, 0x1f, 0xc3, 0x90, 0x89, 0xb6, 0x42, 0x76, 0x32, 0xf7, 0xb1, 0x45, 0xa8, 0xd1, 0x04, 0xd4, 0xf4, 0xe3, 0xa9, 0xd6, 0xa9, 0x61, 0xe8,
0x0d, 0xb0, 0xc0, 0x5f, 0xf2, 0xc8, 0x7b, 0x19, 0x8f, 0xa2, 0x42, 0x32, 0x39, 0x11, 0xad, 0x06, 0x11, 0xd0, 0xf4, 0x31, 0x1f, 0x47, 0xa7, 0xdc, 0xc7, 0x52, 0x5e, 0xa3, 0x09, 0x48, 0x6e, 0x40,
0xd6, 0x3b, 0x92, 0x7e, 0x74, 0x82, 0x4f, 0x70, 0xa8, 0x8c, 0x26, 0x42, 0xc6, 0x94, 0x6b, 0x48, 0x73, 0xc4, 0xa4, 0x8b, 0x62, 0xdd, 0xa9, 0xc4, 0xd2, 0x5c, 0xa3, 0x30, 0x62, 0xb2, 0xab, 0x51,
0x59, 0x43, 0x9c, 0x21, 0xf9, 0x14, 0xee, 0x9b, 0x49, 0xcb, 0x8e, 0xf8, 0x4f, 0x26, 0x5c, 0x48, 0x47, 0x78, 0xc1, 0x9f, 0xf2, 0x58, 0x3c, 0x4f, 0x5a, 0x65, 0xa9, 0x98, 0x9a, 0x9a, 0xc2, 0x5b,
0xed, 0x45, 0x64, 0xe1, 0xad, 0x26, 0x72, 0xb4, 0x0c, 0x09, 0xd5, 0x14, 0xe8, 0x4c, 0xc5, 0xcf, 0xa2, 0x24, 0xfb, 0xe9, 0x00, 0xbf, 0x60, 0xd3, 0x1b, 0x4f, 0xa5, 0x4a, 0x28, 0x37, 0x90, 0xb2,
0x97, 0xb3, 0xeb, 0x34, 0x58, 0x5f, 0xca, 0xde, 0xc1, 0xcc, 0xf8, 0x0c, 0xb6, 0xe6, 0xd9, 0x95, 0x81, 0x38, 0x4b, 0xf2, 0x11, 0x5c, 0xb5, 0x9d, 0xa0, 0x1b, 0xf3, 0x9f, 0x4f, 0xb9, 0x54, 0xc6,
0x39, 0x24, 0x37, 0xaf, 0x27, 0xc8, 0x7f, 0x2f, 0xcb, 0x4f, 0x91, 0x42, 0xbf, 0x7f, 0xb9, 0x00, 0x8b, 0xc8, 0xc2, 0x3b, 0x6d, 0xe4, 0xe8, 0x58, 0x12, 0x6a, 0x28, 0xd0, 0x99, 0x9a, 0x9f, 0xaf,
0xad, 0xc0, 0xad, 0xe5, 0x02, 0xb4, 0x06, 0x0f, 0xa1, 0xee, 0x7a, 0x62, 0xec, 0xb3, 0xa9, 0x8e, 0x66, 0x37, 0x69, 0xb0, 0xb9, 0x92, 0xbd, 0x87, 0x99, 0xf1, 0x31, 0x5c, 0x5b, 0x64, 0xd7, 0xe6,
0xaf, 0x0d, 0x74, 0x7d, 0xcd, 0xe0, 0x54, 0x8c, 0x59, 0xaf, 0xae, 0xe6, 0x7b, 0x3c, 0x9e, 0x2c, 0x50, 0xdc, 0x6e, 0x4f, 0x90, 0xff, 0x4a, 0x9e, 0x9f, 0x22, 0x85, 0xd9, 0x7f, 0xb5, 0x00, 0xa3,
0xce, 0xf7, 0x2b, 0x41, 0x9d, 0x5f, 0x10, 0xd4, 0xf3, 0x91, 0x5b, 0xb8, 0x12, 0xb9, 0xd6, 0x53, 0xc0, 0x85, 0xd5, 0x02, 0x8c, 0x06, 0x37, 0xa1, 0xe9, 0x0b, 0x39, 0x09, 0xd8, 0xcc, 0xc4, 0xd7,
0xd8, 0x9c, 0x7f, 0xf1, 0xf1, 0xe4, 0xcc, 0xf7, 0x9c, 0xce, 0x90, 0xdd, 0xb0, 0xd6, 0x58, 0xbf, 0x16, 0xba, 0xbe, 0x61, 0x71, 0x3a, 0xc6, 0x9c, 0x17, 0x67, 0xf3, 0x3d, 0x69, 0x4f, 0x96, 0xe7,
0x2b, 0xc0, 0x6a, 0x66, 0x4c, 0xff, 0x97, 0x7c, 0x75, 0x4c, 0xcc, 0x07, 0x50, 0x1b, 0x47, 0xde, 0xfb, 0x99, 0xa0, 0x2e, 0x2e, 0x09, 0xea, 0xc5, 0xc8, 0x2d, 0x9d, 0x89, 0x5c, 0xe7, 0x3e, 0x6c,
0x25, 0x93, 0xdc, 0xbe, 0xe0, 0x53, 0xd3, 0xbd, 0xc1, 0xa0, 0x54, 0x37, 0xda, 0x56, 0x55, 0x55, 0x2f, 0x6e, 0xbc, 0x3f, 0x7d, 0x16, 0x08, 0xaf, 0x37, 0x62, 0x2f, 0x79, 0xd7, 0x38, 0x7f, 0x2c,
0x38, 0x91, 0x37, 0x56, 0x7a, 0x61, 0x5e, 0xd6, 0x69, 0x1a, 0xa5, 0x9a, 0xf9, 0x8f, 0x43, 0x2f, 0xc1, 0x7a, 0x6e, 0x8c, 0xf8, 0xaf, 0x7c, 0x4d, 0x4c, 0xcc, 0xeb, 0xd0, 0x98, 0xc4, 0xe2, 0x94,
0x30, 0x59, 0x59, 0xa1, 0x06, 0x52, 0xad, 0x4e, 0xc7, 0x2a, 0x77, 0xb1, 0x99, 0x57, 0x68, 0x02, 0x29, 0xee, 0x9e, 0xf0, 0x99, 0xad, 0xde, 0x60, 0x51, 0xba, 0x1a, 0xdd, 0xd0, 0xb7, 0xaa, 0xf4,
0xcf, 0x92, 0xa6, 0x9c, 0x4e, 0x9a, 0x23, 0x68, 0x1a, 0xef, 0x0a, 0x5b, 0x86, 0xb6, 0x92, 0x63, 0x62, 0x31, 0xd1, 0x7a, 0x61, 0x5e, 0x36, 0x69, 0x16, 0xa5, 0x8b, 0xf9, 0x97, 0x91, 0x08, 0x6d,
0x26, 0xa4, 0x77, 0x96, 0x2d, 0x23, 0x86, 0xfc, 0x34, 0x7c, 0x1e, 0x7a, 0x01, 0x6d, 0x44, 0x19, 0x56, 0xd6, 0xa8, 0x85, 0x74, 0xa9, 0x33, 0xb1, 0xca, 0x7d, 0x2c, 0xe6, 0x35, 0x9a, 0xc2, 0xf3,
0x98, 0x7c, 0x0c, 0x95, 0x78, 0x04, 0x36, 0x23, 0xf7, 0x83, 0x25, 0x82, 0xcc, 0xec, 0x2d, 0x68, 0xa4, 0xa9, 0x66, 0x93, 0xe6, 0x09, 0xb4, 0xad, 0x77, 0xa5, 0xab, 0x22, 0x57, 0xcb, 0xb1, 0x1d,
0xc2, 0xa0, 0x3a, 0x18, 0x0f, 0x9c, 0x68, 0x3a, 0x96, 0x49, 0xd2, 0xcf, 0x10, 0xd8, 0xdf, 0xc6, 0xd2, 0x5b, 0xab, 0x86, 0x25, 0x4b, 0x7e, 0x18, 0x3d, 0x8c, 0x44, 0x48, 0x5b, 0x71, 0x0e, 0x26,
0xdc, 0x91, 0x6c, 0x96, 0xfa, 0x33, 0x84, 0x6a, 0x5a, 0x86, 0x54, 0x25, 0x30, 0x0e, 0x19, 0x75, 0xf7, 0xa0, 0x96, 0xb4, 0xe8, 0x76, 0x24, 0xb8, 0xbe, 0x42, 0x90, 0x9d, 0x0d, 0x24, 0x4d, 0x19,
0xb4, 0x5c, 0x63, 0x86, 0xde, 0xe7, 0x53, 0x61, 0xfd, 0xac, 0x00, 0xf7, 0xaf, 0xb9, 0x91, 0xf1, 0x74, 0x05, 0xe3, 0xa1, 0x17, 0xcf, 0x26, 0x2a, 0x4d, 0xfa, 0x39, 0x02, 0xeb, 0xdb, 0x84, 0x7b,
0x57, 0x2e, 0xf1, 0xd7, 0x9b, 0x00, 0x63, 0x8c, 0x0d, 0x74, 0x97, 0xf6, 0x7f, 0x55, 0x63, 0x94, 0x8a, 0xcd, 0x53, 0x7f, 0x8e, 0xd0, 0x45, 0xcb, 0x92, 0xea, 0x04, 0xc6, 0x26, 0xa3, 0x89, 0x96,
0xb7, 0x12, 0xa7, 0x17, 0xd2, 0x4e, 0xbf, 0xa6, 0xb0, 0xde, 0x85, 0xb2, 0x33, 0x64, 0x32, 0x1e, 0x6b, 0xcd, 0xd1, 0x7b, 0x7c, 0x26, 0x9d, 0x5f, 0x95, 0xe0, 0xea, 0x39, 0x27, 0xb2, 0xfe, 0x2a,
0x73, 0xab, 0xb4, 0xa4, 0xc0, 0x3d, 0x57, 0xc5, 0x6d, 0xbc, 0x46, 0x4d, 0xd5, 0xd3, 0x92, 0x76, 0xa4, 0xfe, 0x7a, 0x1d, 0x60, 0x82, 0xb1, 0x81, 0xee, 0x32, 0xfe, 0xaf, 0x1b, 0x8c, 0xf6, 0x56,
0x7c, 0x82, 0xdb, 0x43, 0x27, 0xea, 0xf4, 0x2d, 0xeb, 0x97, 0x21, 0x40, 0x2e, 0x80, 0x44, 0xfc, 0xea, 0xf4, 0x52, 0xd6, 0xe9, 0xe7, 0x5c, 0xac, 0x97, 0xa1, 0xea, 0x8d, 0x98, 0x4a, 0xda, 0xdc,
0x92, 0x33, 0x9f, 0xbb, 0xaa, 0xc8, 0x45, 0x5c, 0x88, 0x64, 0xd0, 0xfd, 0xe4, 0x46, 0x6e, 0xdc, 0x3a, 0xad, 0x68, 0x70, 0xd7, 0xd7, 0x71, 0x9b, 0x8c, 0x79, 0x33, 0xfd, 0xb5, 0x62, 0x1c, 0x9f,
0xa1, 0x86, 0xbf, 0x1d, 0xb3, 0xf7, 0x02, 0x19, 0x4d, 0xe9, 0x7a, 0x34, 0x8f, 0xdf, 0xec, 0xc2, 0xe2, 0x76, 0xd1, 0x89, 0x26, 0x7d, 0xab, 0x66, 0x33, 0x04, 0xc8, 0x09, 0x90, 0x98, 0x9f, 0x72,
0x9d, 0xc5, 0xc4, 0xa4, 0x09, 0x05, 0x65, 0x21, 0x3d, 0x44, 0xa9, 0xa3, 0x52, 0xf7, 0x92, 0xf9, 0x16, 0x70, 0x5f, 0x5f, 0x72, 0x31, 0x97, 0x32, 0x6d, 0x74, 0x3f, 0x7c, 0x29, 0x37, 0xee, 0x50,
0x13, 0x6e, 0xa2, 0x5f, 0x03, 0x4f, 0xf2, 0x1f, 0xe5, 0xac, 0x5f, 0xe4, 0xa1, 0x39, 0x9f, 0x81, 0xcb, 0xdf, 0x4d, 0xd8, 0x07, 0xa1, 0x8a, 0x67, 0x74, 0x33, 0x5e, 0xc4, 0x6f, 0xf7, 0xe1, 0xd2,
0xe4, 0xd3, 0xd4, 0x56, 0x7d, 0x65, 0x40, 0x5c, 0xd2, 0x2b, 0x53, 0x3b, 0xf5, 0xe7, 0x50, 0x37, 0x72, 0x62, 0xd2, 0x86, 0x92, 0xb6, 0x90, 0x69, 0xa2, 0xf4, 0x52, 0xab, 0x7b, 0xca, 0x82, 0x29,
0x8e, 0x52, 0x06, 0x15, 0xad, 0xfc, 0xfc, 0xa4, 0xbf, 0x3c, 0xe5, 0x69, 0x6d, 0x9c, 0x9c, 0x05, 0xb7, 0xd1, 0x6f, 0x80, 0xbb, 0xc5, 0x0f, 0x0a, 0xce, 0x6f, 0x8a, 0xd0, 0x5e, 0xcc, 0x40, 0xf2,
0xf9, 0x18, 0xca, 0xf1, 0xa0, 0x59, 0xc0, 0x10, 0xbe, 0x46, 0x8d, 0x78, 0xe6, 0x8c, 0x39, 0xfe, 0x51, 0x66, 0xea, 0x3f, 0xd3, 0x20, 0xae, 0xa8, 0x95, 0x99, 0x99, 0xff, 0x53, 0x68, 0x5a, 0x47,
0x8d, 0xcd, 0xde, 0xfa, 0x10, 0xd6, 0xf0, 0xa9, 0x52, 0xc8, 0xb4, 0xae, 0x9b, 0x95, 0xa2, 0x4f, 0x69, 0x83, 0xca, 0x4e, 0x71, 0xb1, 0xd3, 0x5f, 0x9d, 0xf2, 0xb4, 0x31, 0x49, 0xd7, 0x92, 0xdc,
0x60, 0x23, 0x66, 0x3c, 0xd4, 0xdf, 0x4e, 0x04, 0xe5, 0xec, 0xa6, 0xdc, 0xdf, 0x83, 0x3b, 0xb8, 0x83, 0x6a, 0xd2, 0x68, 0x96, 0x30, 0x84, 0xcf, 0x51, 0x23, 0xe9, 0x39, 0x13, 0x8e, 0xff, 0xe1,
0x88, 0x3a, 0xd2, 0xbb, 0xf4, 0xe4, 0xb4, 0xc3, 0x03, 0xc9, 0xa3, 0x6b, 0xf8, 0x9b, 0x50, 0xf0, 0xe5, 0xc1, 0x79, 0x1f, 0x36, 0xf0, 0xab, 0x56, 0xc8, 0x96, 0xae, 0x97, 0xbb, 0x8a, 0x3e, 0x84,
0x5c, 0x6d, 0xde, 0x3a, 0x55, 0x47, 0xab, 0xab, 0xcb, 0x69, 0x56, 0x42, 0xdb, 0x71, 0x38, 0xe6, 0xad, 0x84, 0xf1, 0xb1, 0x79, 0xdb, 0x91, 0x94, 0xb3, 0x97, 0xe5, 0xfe, 0x11, 0x5c, 0xc2, 0x41,
0xed, 0x4d, 0xa5, 0xf4, 0x74, 0x5e, 0x66, 0xa5, 0x74, 0x3d, 0x31, 0xf2, 0x84, 0x78, 0x0d, 0x31, 0xd9, 0x53, 0xe2, 0x54, 0xa8, 0x59, 0x8f, 0x87, 0x8a, 0xc7, 0xe7, 0xf0, 0xb7, 0xa1, 0x24, 0x7c,
0xdf, 0xe6, 0xa0, 0xae, 0xe4, 0x3c, 0x0d, 0xc3, 0x8b, 0x11, 0x8b, 0x2e, 0x96, 0x33, 0x4e, 0x22, 0x63, 0xde, 0x26, 0xd5, 0x4b, 0xa7, 0x6f, 0xae, 0xd3, 0xbc, 0x84, 0xae, 0xe7, 0x71, 0xcc, 0xdb,
0xdf, 0x98, 0x41, 0x1d, 0x93, 0x61, 0xb5, 0x90, 0x1a, 0x56, 0xef, 0x43, 0x15, 0x1b, 0x8d, 0xad, 0x97, 0x95, 0x32, 0x30, 0x79, 0x99, 0x97, 0xd2, 0x17, 0x72, 0x2c, 0xa4, 0x7c, 0x05, 0x31, 0xdf,
0x68, 0x75, 0x22, 0x57, 0x10, 0x31, 0x88, 0xfc, 0xf4, 0xc4, 0xb1, 0x92, 0x9d, 0x38, 0xde, 0x04, 0x14, 0xa0, 0xa9, 0xe5, 0xdc, 0x8f, 0xa2, 0x93, 0x31, 0x8b, 0x4f, 0x56, 0x33, 0x4e, 0xe3, 0xc0,
0x70, 0xb9, 0xcf, 0xd5, 0xe4, 0xc6, 0x24, 0x26, 0x72, 0x91, 0x56, 0x0d, 0xa6, 0x2d, 0xad, 0xe7, 0x9a, 0x41, 0x2f, 0xd3, 0x66, 0xb5, 0x94, 0x69, 0x56, 0xaf, 0x42, 0x1d, 0x0b, 0x8d, 0xab, 0x69,
0x3a, 0xf8, 0x3b, 0x3e, 0x67, 0xd1, 0x33, 0x4f, 0xc8, 0x30, 0x9a, 0xa6, 0xcb, 0x42, 0x2e, 0x53, 0x4d, 0x22, 0xd7, 0x10, 0x71, 0x14, 0x07, 0xd9, 0x8e, 0x63, 0x2d, 0xdf, 0x71, 0xbc, 0x0e, 0xe0,
0x16, 0xde, 0x04, 0x70, 0x14, 0xa1, 0x96, 0x95, 0xd7, 0xb2, 0x0c, 0xa6, 0x2d, 0xad, 0x3f, 0xe6, 0xf3, 0x80, 0xeb, 0xce, 0x8d, 0x29, 0x4c, 0xe4, 0x32, 0xad, 0x5b, 0x4c, 0x57, 0x39, 0x0f, 0x4d,
0x80, 0x28, 0x61, 0xe6, 0x53, 0xca, 0xb1, 0xe7, 0xa8, 0x71, 0x7f, 0xe1, 0x4a, 0x93, 0xda, 0x19, 0xf0, 0xf7, 0x02, 0xce, 0xe2, 0x07, 0x42, 0xaa, 0x28, 0x9e, 0x65, 0xaf, 0x85, 0x42, 0xee, 0x5a,
0xf3, 0x4b, 0x76, 0xc6, 0x02, 0x4e, 0xe4, 0x57, 0x76, 0xc6, 0x22, 0xa2, 0xe3, 0x9d, 0xf1, 0x3e, 0x78, 0x1d, 0xc0, 0xd3, 0x84, 0x46, 0x56, 0xd1, 0xc8, 0xb2, 0x98, 0xae, 0x72, 0xfe, 0x52, 0x00,
0x54, 0xb1, 0x05, 0xe3, 0xd2, 0xa8, 0x67, 0x78, 0x5c, 0x1a, 0x4f, 0x16, 0x2e, 0x8d, 0x25, 0x24, 0xa2, 0x85, 0xd9, 0xa7, 0x9e, 0x7d, 0xe1, 0xe9, 0x76, 0x7f, 0xe9, 0x48, 0x93, 0x99, 0x19, 0x8b,
0x58, 0xb2, 0x34, 0x96, 0xd3, 0x4b, 0xe3, 0x10, 0x6e, 0x5d, 0xbd, 0x89, 0x58, 0xbe, 0x17, 0x7f, 0x2b, 0x66, 0xc6, 0x12, 0x76, 0xe4, 0x67, 0x66, 0xc6, 0x32, 0xa2, 0x93, 0x99, 0xf1, 0x2a, 0xd4,
0x04, 0x95, 0xb1, 0x21, 0x32, 0xc9, 0xbe, 0x95, 0xcd, 0xb3, 0xac, 0x24, 0x9a, 0x50, 0x5b, 0xbf, 0xb1, 0x04, 0xe3, 0xd0, 0x68, 0x7a, 0x78, 0x1c, 0x1a, 0x0f, 0x96, 0x0e, 0x8d, 0x15, 0x24, 0x58,
0xc9, 0xc3, 0xba, 0x22, 0xf8, 0x82, 0xf9, 0x3e, 0x97, 0xd7, 0xcf, 0x1c, 0x2d, 0x28, 0x9b, 0xa2, 0x31, 0x34, 0x56, 0xb3, 0x43, 0xe3, 0x08, 0x2e, 0x9c, 0x3d, 0x89, 0x5c, 0x3d, 0x17, 0x7f, 0x00,
0x1a, 0x5b, 0xcd, 0x80, 0xca, 0x3e, 0xaf, 0x50, 0x00, 0x9a, 0xad, 0x42, 0x0d, 0xa4, 0x6c, 0xaf, 0xb5, 0x89, 0x25, 0xb2, 0xc9, 0x7e, 0x2d, 0x9f, 0x67, 0x79, 0x49, 0x34, 0xa5, 0x76, 0xfe, 0x51,
0x7c, 0x87, 0x56, 0xab, 0x50, 0x3c, 0x2b, 0x1c, 0xee, 0x48, 0xba, 0xe4, 0xe3, 0x59, 0x49, 0x56, 0x82, 0xcd, 0x33, 0xef, 0x31, 0x2b, 0x02, 0xa5, 0x03, 0x55, 0x7b, 0xa9, 0x26, 0x56, 0xb3, 0xa0,
0xbe, 0x57, 0x73, 0x8c, 0xfe, 0x9c, 0x11, 0x83, 0x8a, 0x7a, 0xcc, 0xe4, 0xd0, 0x8c, 0xcb, 0x78, 0xb6, 0x8f, 0x79, 0x6c, 0x41, 0xb3, 0xd5, 0xa8, 0x85, 0xb4, 0xed, 0xb5, 0xef, 0xd0, 0x6a, 0x35,
0x56, 0xed, 0x2f, 0xe9, 0x3a, 0xb8, 0x6c, 0xd7, 0xd3, 0x6d, 0x28, 0xf6, 0x77, 0x35, 0xe5, 0x6f, 0x8a, 0x6b, 0x8d, 0xc3, 0x19, 0xc9, 0x5c, 0xf9, 0xb8, 0xd6, 0x92, 0xb5, 0xef, 0x75, 0x1f, 0x63,
0x75, 0x1f, 0xfc, 0x50, 0x01, 0x88, 0xd4, 0x00, 0x7a, 0xd5, 0x73, 0x5d, 0x1e, 0x98, 0x1e, 0x6a, 0x9e, 0x33, 0x12, 0x50, 0x53, 0x4f, 0x98, 0x1a, 0xd9, 0x76, 0x19, 0xd7, 0xba, 0xfc, 0xa5, 0x55,
0xa0, 0xe5, 0xf3, 0xb3, 0x75, 0xa8, 0x23, 0x2c, 0x63, 0x2c, 0x41, 0x3e, 0x84, 0x8a, 0xa9, 0x79, 0x07, 0x87, 0xed, 0x66, 0xb6, 0x0c, 0x25, 0xfe, 0xae, 0x67, 0xfc, 0xad, 0xcf, 0x83, 0x0f, 0x15,
0x71, 0xb5, 0xbe, 0x9f, 0xb5, 0x7e, 0x86, 0x9e, 0x26, 0xc4, 0xd6, 0x3f, 0x72, 0x3a, 0xfc, 0x4f, 0x80, 0x48, 0x03, 0xa0, 0x57, 0x85, 0xef, 0xf3, 0xd0, 0xd6, 0x50, 0x0b, 0x9d, 0xd3, 0x3f, 0x6f,
0xd8, 0x65, 0xd2, 0x43, 0xd2, 0x56, 0xce, 0x65, 0xad, 0xbc, 0xe8, 0xeb, 0xc7, 0x16, 0x54, 0x5f, 0xc1, 0x1a, 0x1f, 0x47, 0x5f, 0x0a, 0x6c, 0x9c, 0xeb, 0xd4, 0x00, 0xd8, 0xdf, 0xf1, 0x58, 0x9c,
0xb2, 0xcb, 0x70, 0x12, 0x79, 0x92, 0x1b, 0xe3, 0xcf, 0x10, 0xd7, 0xe4, 0xe5, 0x43, 0xa8, 0xeb, 0x72, 0xdf, 0x7d, 0x1e, 0x47, 0x63, 0x6c, 0x96, 0x75, 0x7f, 0x67, 0x70, 0x9f, 0xc4, 0xd1, 0x38,
0xa9, 0xd0, 0x4e, 0x87, 0x5f, 0x4d, 0xe3, 0xf4, 0xd8, 0xfa, 0xdf, 0xb0, 0xee, 0x0c, 0x99, 0x17, 0xeb, 0xb9, 0x8d, 0x9c, 0xe7, 0x6e, 0x42, 0xf3, 0x84, 0xcf, 0xf4, 0x68, 0x6c, 0x4a, 0x64, 0xdb,
0xd8, 0x62, 0x18, 0x46, 0x12, 0x3b, 0xb8, 0xfe, 0x08, 0x59, 0xa5, 0x6b, 0xf8, 0xe0, 0x44, 0xe1, 0xf0, 0x5a, 0x1c, 0x96, 0xc9, 0x7b, 0xb0, 0x6d, 0xba, 0x38, 0xc9, 0x7d, 0x17, 0x85, 0xda, 0x61,
0x55, 0x27, 0x17, 0xaa, 0x86, 0xf0, 0x40, 0x18, 0x9b, 0xab, 0xa3, 0x8a, 0x55, 0x4f, 0xd8, 0x92, 0x14, 0x9f, 0x52, 0x36, 0xd1, 0x43, 0x97, 0xb1, 0xa7, 0x93, 0xdc, 0xef, 0xa7, 0xdf, 0x77, 0xf5,
0x0b, 0x69, 0xe6, 0x97, 0x92, 0x27, 0x4e, 0xb9, 0x90, 0xcf, 0x8b, 0x95, 0x62, 0x73, 0xc5, 0xfa, 0x67, 0xe7, 0xb1, 0xc9, 0x89, 0x9c, 0x7b, 0x25, 0x79, 0x1f, 0x6a, 0xf6, 0x96, 0x4e, 0xea, 0xcb,
0x65, 0x0e, 0x6e, 0x2f, 0x1c, 0x82, 0x96, 0xc4, 0xde, 0xfc, 0x48, 0xa0, 0x6d, 0x90, 0x19, 0x09, 0xb9, 0xcf, 0x73, 0x29, 0xb1, 0xf3, 0xef, 0x82, 0x49, 0xd8, 0x03, 0x76, 0x9a, 0x56, 0xbd, 0x6c,
0x7a, 0xf0, 0x60, 0xa8, 0x4b, 0x88, 0xcd, 0x22, 0x67, 0xe8, 0x5d, 0x72, 0x5b, 0x4c, 0xc6, 0x63, 0x5c, 0x14, 0xf2, 0x71, 0xb1, 0xec, 0xbd, 0xe6, 0x1a, 0xd4, 0x9f, 0xb3, 0xd3, 0x68, 0x1a, 0x0b,
0xa5, 0x3b, 0x0f, 0xd8, 0x99, 0x6f, 0x06, 0xe0, 0x0a, 0xdd, 0x32, 0x64, 0x6d, 0x4d, 0x75, 0xa2, 0xc5, 0x6d, 0xb8, 0xcc, 0x11, 0xe7, 0xdc, 0x24, 0x37, 0xa1, 0x69, 0xfa, 0x58, 0x37, 0x9b, 0x30,
0x89, 0x7a, 0x9a, 0xc6, 0xfa, 0x6d, 0x4e, 0x37, 0x9f, 0x53, 0xb5, 0xc1, 0xa8, 0x9d, 0x88, 0x47, 0x0d, 0x83, 0x33, 0x8d, 0xf6, 0xb7, 0x61, 0xd3, 0x1b, 0x31, 0x11, 0xba, 0x72, 0x14, 0xc5, 0x0a,
0x37, 0xdc, 0xb9, 0x3f, 0x85, 0x92, 0x59, 0x82, 0xd4, 0x7b, 0x1a, 0xf3, 0x83, 0x63, 0x4a, 0xe0, 0x0d, 0x6a, 0x9e, 0x75, 0xeb, 0x74, 0x03, 0x3f, 0x1c, 0x68, 0xbc, 0x36, 0xaa, 0xd4, 0xb7, 0x1e,
0xce, 0xe9, 0x6c, 0x3d, 0xa2, 0x86, 0xc9, 0x7a, 0x02, 0xb5, 0x14, 0x9a, 0xd4, 0xa0, 0x3c, 0xe8, 0x0f, 0xa5, 0x8d, 0x12, 0xbd, 0xd4, 0x3e, 0x12, 0xd2, 0x55, 0x5c, 0x2a, 0xdb, 0x71, 0x55, 0x84,
0xef, 0xf7, 0x8f, 0xbe, 0xe8, 0x37, 0xdf, 0x50, 0xc0, 0x29, 0x1d, 0x9c, 0x9c, 0xf6, 0xba, 0xcd, 0x3c, 0xe4, 0x52, 0x3d, 0x2c, 0xd7, 0xca, 0xed, 0x35, 0xe7, 0xb7, 0x05, 0xb8, 0xb8, 0xb4, 0x6d,
0x1c, 0x59, 0x87, 0xd5, 0x41, 0x1f, 0xc1, 0x2f, 0x8e, 0xe8, 0xe9, 0xb3, 0x2f, 0x9b, 0x79, 0xeb, 0x5b, 0x91, 0x2d, 0x8b, 0x4d, 0x8c, 0xb1, 0x41, 0xae, 0x89, 0x19, 0xc0, 0xf5, 0x91, 0xb9, 0xf4,
0xdb, 0x82, 0x5e, 0x20, 0x5e, 0xa4, 0x16, 0x34, 0x33, 0xd8, 0x2c, 0x51, 0x9e, 0x40, 0xf1, 0x65, 0x5c, 0x16, 0x7b, 0x23, 0x71, 0xca, 0x5d, 0x39, 0x9d, 0x4c, 0xb4, 0xee, 0x3c, 0x64, 0xcf, 0x02,
0x14, 0x8e, 0xe2, 0x60, 0x52, 0x67, 0x75, 0x21, 0x19, 0x9a, 0xaa, 0x9f, 0x97, 0xa1, 0x0a, 0x2e, 0xdb, 0xb2, 0xd7, 0xe8, 0x35, 0x4b, 0xd6, 0x35, 0x54, 0x07, 0x86, 0x68, 0x60, 0x68, 0x9c, 0x3f,
0x67, 0xa8, 0x62, 0x37, 0x38, 0x8f, 0x87, 0xb7, 0x19, 0x42, 0xb9, 0xc4, 0x8c, 0xbc, 0xba, 0x20, 0x14, 0x4c, 0xb9, 0x3c, 0xd4, 0x33, 0x97, 0x9e, 0xe2, 0x78, 0xfc, 0x92, 0xaf, 0x04, 0x1f, 0x41,
0x9b, 0xbd, 0x38, 0xc1, 0xb5, 0xf1, 0x8b, 0x53, 0xc4, 0xc5, 0x38, 0x0c, 0x44, 0x9c, 0xd8, 0x09, 0xc5, 0x8e, 0x6d, 0x7a, 0x9f, 0xd6, 0x62, 0xab, 0x9b, 0x11, 0xb8, 0x73, 0x38, 0x1f, 0xe8, 0xa8,
0xac, 0xaa, 0x79, 0xc4, 0xc7, 0xbe, 0xa7, 0x99, 0x75, 0xfc, 0x55, 0x0d, 0xa6, 0x2d, 0x09, 0x5f, 0x65, 0x72, 0xee, 0x42, 0x23, 0x83, 0x26, 0x0d, 0xa8, 0x1e, 0x0d, 0xf7, 0x86, 0x4f, 0x3e, 0x1b,
0xbc, 0x88, 0x56, 0xd0, 0xb2, 0xff, 0x9f, 0xb5, 0xec, 0x82, 0x5b, 0xef, 0xbc, 0xb8, 0xb2, 0xaa, 0xb6, 0x5f, 0xd3, 0xc0, 0x21, 0x3d, 0x3a, 0x38, 0x1c, 0xf4, 0xdb, 0x05, 0xb2, 0x09, 0xeb, 0x47,
0x2e, 0x5c, 0x5f, 0xb5, 0x0f, 0xab, 0xc9, 0x08, 0xf0, 0x43, 0x20, 0x57, 0x39, 0xaf, 0xf8, 0xe2, 0x43, 0x04, 0x3f, 0x7b, 0x42, 0x0f, 0x1f, 0x7c, 0xde, 0x2e, 0x3a, 0xdf, 0x94, 0xcc, 0xc8, 0xf3,
0xb8, 0xd7, 0xef, 0xee, 0xf5, 0x3f, 0x6f, 0xe6, 0x48, 0x1d, 0x2a, 0xed, 0x4e, 0xa7, 0x77, 0xac, 0x34, 0x33, 0x52, 0xda, 0x56, 0x6c, 0x85, 0xf2, 0x04, 0xca, 0x98, 0x5e, 0x36, 0x98, 0xf4, 0x5a,
0x3c, 0x93, 0x57, 0x50, 0xb7, 0xd7, 0x39, 0xd8, 0xeb, 0xf7, 0xba, 0xcd, 0x82, 0x82, 0x3a, 0xed, 0x1f, 0x48, 0x45, 0xb6, 0x4e, 0x15, 0x55, 0xa4, 0x83, 0xcb, 0x1b, 0xe9, 0xd8, 0x0d, 0x8f, 0x93,
0x7e, 0xa7, 0x77, 0xd0, 0xeb, 0x36, 0x8b, 0xd6, 0x5f, 0x72, 0x7a, 0x36, 0xe8, 0x64, 0xf6, 0xc4, 0x76, 0x73, 0x8e, 0xd0, 0x2e, 0xb1, 0x4d, 0xba, 0x29, 0x21, 0x76, 0x92, 0x4f, 0x71, 0x5d, 0x7c,
0x2e, 0x77, 0x3c, 0xb1, 0xfc, 0x03, 0xd4, 0x16, 0x54, 0x8d, 0x3d, 0xf7, 0xe2, 0x48, 0x9b, 0x21, 0x23, 0x8b, 0xb9, 0x9c, 0x44, 0xa1, 0x4c, 0xae, 0xa2, 0x14, 0xd6, 0xf5, 0x27, 0xe6, 0x93, 0x40,
0xc8, 0x8f, 0x60, 0xcd, 0x35, 0xfc, 0x76, 0x26, 0xf2, 0xde, 0x9f, 0x9f, 0xb2, 0x16, 0xbd, 0x72, 0x18, 0x66, 0x13, 0x7f, 0x75, 0x8b, 0xe9, 0x2a, 0xc2, 0x97, 0x8f, 0xce, 0x35, 0xb4, 0xec, 0xf7,
0x27, 0x3e, 0x18, 0xf3, 0x34, 0xdc, 0x0c, 0x6c, 0xbd, 0x07, 0x8d, 0x2c, 0x45, 0xe6, 0xb2, 0x6f, 0xf3, 0x96, 0x5d, 0x72, 0xea, 0x9d, 0xa7, 0x67, 0x86, 0xeb, 0xa5, 0x03, 0xb7, 0xf1, 0x61, 0x3d,
0x64, 0x2e, 0x9b, 0xb3, 0x7e, 0x9e, 0x87, 0xb5, 0xb9, 0x3f, 0x33, 0x96, 0xf7, 0xab, 0xf9, 0x8d, 0x6d, 0x5a, 0x7e, 0x02, 0xe4, 0x2c, 0xe7, 0x19, 0x5f, 0xec, 0x0f, 0x86, 0xfd, 0xdd, 0xe1, 0xa7,
0x38, 0x7f, 0x65, 0x23, 0x26, 0xef, 0x01, 0x49, 0x93, 0xd8, 0xe9, 0xd5, 0xa2, 0x99, 0x22, 0xd4, 0xed, 0x02, 0x69, 0x42, 0xad, 0xdb, 0xeb, 0x0d, 0xf6, 0xb5, 0x67, 0x8a, 0x1a, 0xea, 0x0f, 0x7a,
0xb5, 0x2a, 0xdd, 0x00, 0x8b, 0xaf, 0xd3, 0x00, 0xc9, 0x0f, 0x60, 0x43, 0x84, 0x8e, 0xc7, 0x7c, 0x8f, 0x76, 0x87, 0x83, 0x7e, 0xbb, 0xa4, 0xa1, 0x5e, 0x77, 0xd8, 0x1b, 0x3c, 0x1a, 0xf4, 0xdb,
0xdb, 0xf7, 0x82, 0x8b, 0xe4, 0x6f, 0xb9, 0xd6, 0x0a, 0x4a, 0x99, 0x5b, 0xd9, 0x4e, 0x90, 0xf2, 0x65, 0xe7, 0xef, 0x05, 0xd3, 0xcd, 0xf4, 0x72, 0x93, 0x6d, 0x9f, 0x7b, 0x42, 0xae, 0x7e, 0x32,
0xc0, 0x0b, 0x2e, 0xe2, 0xff, 0x4b, 0x88, 0x98, 0x47, 0x09, 0x4b, 0x00, 0x50, 0xf6, 0xca, 0xcc, 0xbb, 0x06, 0x75, 0x6b, 0xcf, 0xdd, 0x24, 0xd2, 0xe6, 0x08, 0xf2, 0x33, 0xd8, 0xf0, 0x2d, 0xbf,
0x9f, 0xe9, 0x59, 0x23, 0x97, 0x9d, 0x35, 0xf6, 0xa1, 0x66, 0xfe, 0xe0, 0x3b, 0x55, 0x0d, 0x31, 0x9b, 0x8b, 0xbc, 0x77, 0x17, 0xfb, 0xc2, 0x65, 0x5b, 0xee, 0x24, 0x0b, 0x6b, 0x9e, 0x96, 0x9f,
0x8f, 0xae, 0xfb, 0xaf, 0xd9, 0x1b, 0xdb, 0xb3, 0xbf, 0x04, 0x0f, 0xcd, 0x3f, 0x82, 0x46, 0xe8, 0x83, 0x9d, 0x77, 0xa0, 0x95, 0xa7, 0xc8, 0x1d, 0xf6, 0xb5, 0xdc, 0x61, 0x0b, 0xce, 0xaf, 0x8b,
0x8e, 0x62, 0xa0, 0x69, 0x6e, 0xeb, 0xd7, 0x39, 0x68, 0x28, 0x15, 0x53, 0x6f, 0xfe, 0x0e, 0xd4, 0xb0, 0xb1, 0xf0, 0xf7, 0xd0, 0xea, 0x0a, 0xbb, 0x38, 0xc3, 0x17, 0xcf, 0xcc, 0xf0, 0xe4, 0x1d,
0xa2, 0x04, 0x8a, 0x5b, 0xd3, 0xc6, 0x4c, 0xfe, 0x8c, 0x94, 0xa6, 0x09, 0xc9, 0x2e, 0x6c, 0x88, 0x20, 0x59, 0x12, 0x37, 0x3b, 0x0c, 0xb5, 0x33, 0x84, 0xe6, 0xae, 0xca, 0x96, 0xec, 0xf2, 0xab,
0xc9, 0x59, 0xdc, 0xde, 0x9e, 0x8b, 0x30, 0x78, 0x3a, 0x95, 0x3c, 0x6e, 0xfa, 0x0b, 0x9f, 0x91, 0x94, 0x6c, 0xf2, 0x63, 0xd8, 0x92, 0x91, 0x27, 0x58, 0xe0, 0x06, 0x22, 0x3c, 0x49, 0xff, 0xe8,
0xf7, 0x60, 0x3d, 0x36, 0xdd, 0x8c, 0x41, 0x6f, 0xf4, 0x57, 0x1f, 0x58, 0xbf, 0xca, 0x41, 0x4d, 0xec, 0xac, 0xa1, 0x94, 0x85, 0x21, 0xf3, 0x00, 0x29, 0x1f, 0x89, 0xf0, 0x24, 0xf9, 0x07, 0x8a,
0x29, 0x6b, 0xfe, 0xef, 0xc1, 0x11, 0x34, 0x09, 0x12, 0x75, 0x5c, 0xd8, 0xeb, 0xee, 0x40, 0xc9, 0xc8, 0x45, 0x94, 0x74, 0x24, 0x00, 0x65, 0x2f, 0x6c, 0xc7, 0x9c, 0xed, 0x8e, 0x0a, 0xf9, 0xee,
0x7c, 0x06, 0x33, 0x53, 0x86, 0xf9, 0x0a, 0x96, 0x0a, 0xb3, 0x62, 0x26, 0xcc, 0xb6, 0xa0, 0x3a, 0x68, 0x0f, 0x1a, 0xf6, 0x2f, 0xd3, 0x43, 0x5d, 0xc2, 0x8b, 0xe8, 0xba, 0x6f, 0xcd, 0x77, 0xec,
0xdb, 0x02, 0x57, 0x70, 0x30, 0x9e, 0x21, 0x66, 0x19, 0x57, 0x4a, 0x8f, 0x5e, 0x7f, 0x30, 0x03, 0xce, 0xff, 0x64, 0x7d, 0x6c, 0xff, 0x63, 0xb5, 0x42, 0x77, 0x34, 0x03, 0xcd, 0x72, 0x3b, 0xbf,
0x91, 0x51, 0x4d, 0xcd, 0xe0, 0x61, 0x40, 0x9e, 0x40, 0x89, 0xe1, 0x09, 0x75, 0x6c, 0xec, 0x5a, 0x2f, 0x40, 0x4b, 0xab, 0x98, 0xd9, 0xf9, 0x07, 0xd0, 0x88, 0x53, 0x28, 0x29, 0x4d, 0x5b, 0x73,
0xd9, 0xb8, 0xc8, 0x10, 0xef, 0xe8, 0x1f, 0x6a, 0x38, 0xc8, 0xdb, 0xb0, 0x1a, 0xfa, 0xae, 0x21, 0xf9, 0x73, 0x52, 0x9a, 0x25, 0x24, 0x77, 0x60, 0x4b, 0x4e, 0x9f, 0x25, 0xe5, 0xed, 0xa1, 0x8c,
0x19, 0x24, 0x1d, 0x23, 0x8b, 0x24, 0x8f, 0xf1, 0x12, 0x0a, 0x32, 0xab, 0xd6, 0xed, 0x85, 0xaf, 0xc2, 0xfb, 0x33, 0xc5, 0x93, 0x36, 0x65, 0xe9, 0x37, 0xf2, 0x0e, 0x6c, 0x26, 0xa6, 0x9b, 0x33,
0xa0, 0x31, 0x95, 0xea, 0xa0, 0x25, 0xa3, 0xdd, 0x3a, 0xac, 0xee, 0xf7, 0xbe, 0xec, 0xb4, 0x69, 0x98, 0x37, 0x88, 0xb3, 0x1f, 0x9c, 0xdf, 0x15, 0xa0, 0xa1, 0x95, 0xb5, 0xff, 0xa0, 0x61, 0xd3,
0xd7, 0x6e, 0x77, 0xbb, 0x98, 0x9c, 0x04, 0x1a, 0xed, 0x4e, 0xe7, 0x68, 0xd0, 0x3f, 0x3d, 0x31, 0x9c, 0x06, 0x89, 0x5e, 0x2e, 0xad, 0x75, 0x97, 0xa0, 0x62, 0x1f, 0xee, 0x6c, 0x5f, 0x64, 0xdf,
0xb8, 0x1c, 0xb9, 0x05, 0x6b, 0x31, 0x59, 0xb7, 0x77, 0xd0, 0xd3, 0x25, 0x6b, 0x03, 0x9a, 0x09, 0xed, 0x32, 0x61, 0x56, 0xce, 0x85, 0xd9, 0x35, 0xa8, 0xcf, 0xe7, 0xd6, 0x35, 0x6c, 0xe5, 0xe7,
0x21, 0xed, 0x1d, 0x1e, 0xbd, 0xc0, 0xd2, 0x05, 0x50, 0x3a, 0x38, 0xea, 0xec, 0xab, 0xc2, 0xa5, 0x88, 0x79, 0xc6, 0x55, 0xb2, 0xcd, 0xe2, 0x9f, 0x8b, 0xa6, 0x85, 0xb3, 0xaa, 0xe9, 0xa9, 0x21,
0xf2, 0x7c, 0xd0, 0x37, 0xd0, 0x0a, 0x59, 0x83, 0xda, 0x60, 0xaf, 0x6b, 0x0f, 0x8e, 0xbb, 0x6d, 0x0a, 0xc9, 0x5d, 0xa8, 0x30, 0x5c, 0xa1, 0x8e, 0xad, 0x3b, 0x4e, 0x3e, 0x2e, 0x72, 0xc4, 0x3b,
0x25, 0xa0, 0x44, 0x9a, 0x50, 0xef, 0xb7, 0x0f, 0x7b, 0x76, 0xe7, 0x59, 0xbb, 0xff, 0x79, 0xaf, 0xe6, 0x87, 0x5a, 0x0e, 0xf2, 0x26, 0xac, 0x47, 0x81, 0x6f, 0x49, 0x8e, 0xd2, 0x8a, 0x91, 0x47,
0xdb, 0x2c, 0x5b, 0x5f, 0xe9, 0x06, 0x9a, 0xfa, 0x3f, 0x8f, 0xfc, 0x5f, 0xea, 0xcf, 0x3f, 0x1d, 0x92, 0xdb, 0x78, 0x08, 0x0d, 0xd9, 0xe1, 0xf0, 0xe2, 0xd2, 0x2d, 0x68, 0x42, 0xa5, 0x2b, 0x68,
0x87, 0x4b, 0xae, 0x37, 0xfb, 0xe3, 0x2f, 0x71, 0x4f, 0x3e, 0xed, 0x9e, 0x13, 0x3d, 0x36, 0x5c, 0xc5, 0x6a, 0xb7, 0x09, 0xeb, 0x7b, 0x83, 0xcf, 0x7b, 0x5d, 0xda, 0x77, 0xbb, 0xfd, 0x3e, 0x26,
0x49, 0x44, 0x1c, 0x2b, 0xf9, 0xd7, 0x32, 0x1e, 0xf3, 0xd5, 0x79, 0xc1, 0x66, 0xb3, 0xf0, 0x1b, 0x27, 0x81, 0x56, 0xb7, 0xd7, 0x7b, 0x72, 0x34, 0x3c, 0x3c, 0xb0, 0xb8, 0x02, 0xb9, 0x00, 0x1b,
0xc5, 0xd3, 0xd5, 0xaf, 0x6a, 0x3b, 0x8f, 0x3f, 0x8e, 0xf5, 0x39, 0x2b, 0xe1, 0xe9, 0xfd, 0x7f, 0x09, 0x59, 0x7f, 0xf0, 0x68, 0x60, 0xae, 0xac, 0x2d, 0x68, 0xa7, 0x84, 0x74, 0xf0, 0xf8, 0xc9,
0x06, 0x00, 0x00, 0xff, 0xff, 0x4c, 0x7b, 0xbf, 0x10, 0xc2, 0x1f, 0x00, 0x00, 0x53, 0xbc, 0xba, 0x00, 0x2a, 0x8f, 0x9e, 0xf4, 0xf6, 0xf4, 0xc5, 0xa5, 0xf3, 0xfc, 0x68, 0x68,
0xa1, 0x35, 0xb2, 0x01, 0x8d, 0xa3, 0xdd, 0xbe, 0x7b, 0xb4, 0xdf, 0xef, 0x6a, 0x01, 0x15, 0xd2,
0x86, 0xe6, 0xb0, 0xfb, 0x78, 0xe0, 0xf6, 0x1e, 0x74, 0x87, 0x9f, 0x0e, 0xfa, 0xed, 0xaa, 0xf3,
0x85, 0x29, 0xa0, 0x99, 0x7f, 0x48, 0xc9, 0xf7, 0x32, 0x7f, 0xa7, 0x9a, 0x38, 0x5c, 0x71, 0xbc,
0xf9, 0x5f, 0xa9, 0xa9, 0x7b, 0x8a, 0x59, 0xf7, 0x1c, 0x98, 0xb6, 0xe1, 0x4c, 0x22, 0x62, 0x23,
0xcc, 0xbf, 0x52, 0xc9, 0x60, 0xa2, 0xd7, 0x4b, 0x66, 0xb1, 0xa5, 0xaf, 0x2a, 0xf7, 0xd7, 0xbf,
0x68, 0xec, 0xdc, 0xbe, 0x97, 0xe8, 0xf3, 0xac, 0x82, 0xab, 0x77, 0xff, 0x13, 0x00, 0x00, 0xff,
0xff, 0x61, 0x1a, 0x00, 0xa2, 0x14, 0x21, 0x00, 0x00,
} }

View File

@ -28,6 +28,8 @@ message Backup {
FetchingBackedUpDataDetails settingsDetails = 10; FetchingBackedUpDataDetails settingsDetails = 10;
SyncAllKeycards keycards = 11; SyncAllKeycards keycards = 11;
FetchingBackedUpDataDetails keycardsDetails = 12; FetchingBackedUpDataDetails keycardsDetails = 12;
SyncWalletAccount walletAccount = 13;
FetchingBackedUpDataDetails walletAccountsDetails = 14;
} }
message MultiAccount { message MultiAccount {
@ -228,6 +230,11 @@ message SyncWalletAccount {
string color = 10; string color = 10;
bool hidden = 11; bool hidden = 11;
bool removed = 12; bool removed = 12;
string emoji = 13;
string derived_from = 14;
string key_uid = 15;
string keypair_name = 16;
uint64 last_used_derivation_index = 17;
} }
message SyncWalletAccounts { message SyncWalletAccounts {

View File

@ -3,6 +3,7 @@ package wakusync
import ( import (
"encoding/json" "encoding/json"
"github.com/status-im/status-go/multiaccounts/accounts"
"github.com/status-im/status-go/multiaccounts/keypairs" "github.com/status-im/status-go/multiaccounts/keypairs"
"github.com/status-im/status-go/multiaccounts/settings" "github.com/status-im/status-go/multiaccounts/settings"
"github.com/status-im/status-go/protocol/protobuf" "github.com/status-im/status-go/protocol/protobuf"
@ -13,6 +14,7 @@ type WakuBackedUpDataResponse struct {
Profile *BackedUpProfile Profile *BackedUpProfile
Setting *settings.SyncSettingField Setting *settings.SyncSettingField
Keycards []*keypairs.KeyPair Keycards []*keypairs.KeyPair
WalletAccount *accounts.Account
} }
func (sfwr *WakuBackedUpDataResponse) MarshalJSON() ([]byte, error) { func (sfwr *WakuBackedUpDataResponse) MarshalJSON() ([]byte, error) {
@ -21,10 +23,12 @@ func (sfwr *WakuBackedUpDataResponse) MarshalJSON() ([]byte, error) {
Profile *BackedUpProfile `json:"backedUpProfile,omitempty"` Profile *BackedUpProfile `json:"backedUpProfile,omitempty"`
Setting *settings.SyncSettingField `json:"backedUpSettings,omitempty"` Setting *settings.SyncSettingField `json:"backedUpSettings,omitempty"`
Keycards []*keypairs.KeyPair `json:"backedUpKeycards,omitempty"` Keycards []*keypairs.KeyPair `json:"backedUpKeycards,omitempty"`
WalletAccount *accounts.Account `json:"backedUpWalletAccount,omitempty"`
}{ }{
Profile: sfwr.Profile, Profile: sfwr.Profile,
Setting: sfwr.Setting, Setting: sfwr.Setting,
Keycards: sfwr.Keycards, Keycards: sfwr.Keycards,
WalletAccount: sfwr.WalletAccount,
} }
responseItem.FetchingDataProgress = sfwr.FetchingBackedUpDataDetails() responseItem.FetchingDataProgress = sfwr.FetchingBackedUpDataDetails()

View File

@ -157,6 +157,10 @@ func (m *MessengerSignalsHandler) SendWakuBackedUpSettings(response *wakusync.Wa
signal.SendWakuBackedUpSettings(response) signal.SendWakuBackedUpSettings(response)
} }
func (m *MessengerSignalsHandler) SendWakuBackedUpWalletAccount(response *wakusync.WakuBackedUpDataResponse) {
signal.SendWakuBackedUpWalletAccount(response)
}
func (m *MessengerSignalsHandler) SendWakuBackedUpKeycards(response *wakusync.WakuBackedUpDataResponse) { func (m *MessengerSignalsHandler) SendWakuBackedUpKeycards(response *wakusync.WakuBackedUpDataResponse) {
signal.SendWakuBackedUpKeycards(response) signal.SendWakuBackedUpKeycards(response)
} }

View File

@ -12,6 +12,9 @@ const (
// EventWakuBackedUpSettings is emitted while applying fetched settings from waku // EventWakuBackedUpSettings is emitted while applying fetched settings from waku
EventWakuBackedUpSettings = "waku.backedup.settings" EventWakuBackedUpSettings = "waku.backedup.settings"
// EventWakuBackedUpWalletAccount is emitted while applying fetched wallet account data from waku
EventWakuBackedUpWalletAccount = "waku.backedup.wallet-account" // #nosec G101
// EventWakuBackedUpKeycards is emitted while applying fetched keycard data from waku // EventWakuBackedUpKeycards is emitted while applying fetched keycard data from waku
EventWakuBackedUpKeycards = "waku.backedup.keycards" EventWakuBackedUpKeycards = "waku.backedup.keycards"
) )
@ -28,6 +31,10 @@ func SendWakuBackedUpSettings(obj json.Marshaler) {
send(EventWakuBackedUpSettings, obj) send(EventWakuBackedUpSettings, obj)
} }
func SendWakuBackedUpWalletAccount(obj json.Marshaler) {
send(EventWakuBackedUpWalletAccount, obj)
}
func SendWakuBackedUpKeycards(obj json.Marshaler) { func SendWakuBackedUpKeycards(obj json.Marshaler) {
send(EventWakuBackedUpKeycards, obj) send(EventWakuBackedUpKeycards, obj)
} }