diff --git a/DashSync/shared/DashSync.xcdatamodeld/.xccurrentversion b/DashSync/shared/DashSync.xcdatamodeld/.xccurrentversion
index 5cbe4fe8d..9697cdadc 100644
--- a/DashSync/shared/DashSync.xcdatamodeld/.xccurrentversion
+++ b/DashSync/shared/DashSync.xcdatamodeld/.xccurrentversion
@@ -3,6 +3,6 @@
_XCCurrentVersionName
- DashSync 20.xcdatamodel
+ DashSync 21.xcdatamodel
diff --git a/DashSync/shared/DashSync.xcdatamodeld/DashSync 21.xcdatamodel/contents b/DashSync/shared/DashSync.xcdatamodeld/DashSync 21.xcdatamodel/contents
new file mode 100644
index 000000000..e8661f27e
--- /dev/null
+++ b/DashSync/shared/DashSync.xcdatamodeld/DashSync 21.xcdatamodel/contents
@@ -0,0 +1,529 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataClass.h b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataClass.h
new file mode 100644
index 000000000..f543fb53c
--- /dev/null
+++ b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataClass.h
@@ -0,0 +1,43 @@
+//
+// Created by Vladimir Pirogov
+// Copyright © 2024 Dash Core Group. All rights reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "DSSpecialTransactionEntity+CoreDataClass.h"
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface DSAssetLockTransactionEntity : DSSpecialTransactionEntity
+@end
+
+@interface DSAssetLockTransactionEntity (CoreDataGeneratedAccessors)
+
+- (void)insertObject:(DSTxOutputEntity *)value inCreditOutputsAtIndex:(NSUInteger)idx;
+- (void)removeObjectFromCreditOutputsAtIndex:(NSUInteger)idx;
+- (void)insertCreditOutputs:(NSArray *)value atIndexes:(NSIndexSet *)indexes;
+- (void)removeCreditOutputsAtIndexes:(NSIndexSet *)indexes;
+- (void)replaceObjectInCreditOutputsAtIndex:(NSUInteger)idx withObject:(DSTxOutputEntity *)value;
+- (void)replaceCreditOutputsAtIndexes:(NSIndexSet *)indexes withOutputs:(NSArray *)values;
+- (void)addCreditOutputsObject:(DSTxOutputEntity *)value;
+- (void)removeCreditOutputsObject:(DSTxOutputEntity *)value;
+- (void)addCreditOutputs:(NSOrderedSet *)values;
+- (void)removeCreditOutputs:(NSOrderedSet *)values;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#import "DSAssetLockTransactionEntity+CoreDataProperties.h"
diff --git a/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataClass.m b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataClass.m
new file mode 100644
index 000000000..6a1624362
--- /dev/null
+++ b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataClass.m
@@ -0,0 +1,77 @@
+//
+// Created by Vladimir Pirogov
+// Copyright © 2024 Dash Core Group. All rights reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "DSAddressEntity+CoreDataClass.h"
+#import "DSAssetLockTransaction.h"
+#import "DSAssetLockTransactionEntity+CoreDataClass.h"
+#import "DSChain+Protected.h"
+#import "DSChainEntity+CoreDataClass.h"
+#import "DSKeyManager.h"
+#import "DSTransactionFactory.h"
+#import "DSTransactionOutput.h"
+#import "DSTxOutputEntity+CoreDataClass.h"
+#import "NSData+Dash.h"
+#import "NSManagedObject+Sugar.h"
+#import "NSString+Dash.h"
+
+@implementation DSAssetLockTransactionEntity
+
+- (instancetype)setAttributesFromTransaction:(DSTransaction *)transaction {
+ [self.managedObjectContext performBlockAndWait:^{
+ [super setAttributesFromTransaction:transaction];
+ DSAssetLockTransaction *tx = (DSAssetLockTransaction *)transaction;
+ self.specialTransactionVersion = tx.specialTransactionVersion;
+ NSMutableOrderedSet *creditOutputs = [self mutableOrderedSetValueForKey:@"creditOutputs"];
+ while (creditOutputs.count < tx.creditOutputs.count) {
+ [creditOutputs addObject:[DSTxOutputEntity managedObjectInBlockedContext:self.managedObjectContext]];
+ }
+ while (creditOutputs.count > tx.creditOutputs.count) {
+
+ [self removeObjectFromCreditOutputsAtIndex:creditOutputs.count - 1];
+ }
+ NSUInteger idx = 0;
+ for (DSTxOutputEntity *e in creditOutputs) {
+ [e setAttributesFromTransaction:tx outputIndex:idx++ forTransactionEntity:self];
+ }
+ }];
+
+ return self;
+}
+
+- (DSTransaction *)transactionForChain:(DSChain *)chain {
+ DSAssetLockTransaction *tx = (DSAssetLockTransaction *)[super transactionForChain:chain];
+ tx.type = DSTransactionType_AssetLock;
+ [self.managedObjectContext performBlockAndWait:^{
+ tx.specialTransactionVersion = self.specialTransactionVersion;
+ for (DSTxOutputEntity *e in self.creditOutputs) {
+ NSString *address = e.address;
+ if (!address && e.script) {
+ address = [DSKeyManager addressWithScriptPubKey:e.script forChain:tx.chain];
+ }
+ DSTransactionOutput *transactionOutput = [DSTransactionOutput transactionOutputWithAmount:e.value address:address outScript:e.script onChain:tx.chain];
+ [tx.creditOutputs addObject:transactionOutput];
+ }
+ }];
+
+ return tx;
+}
+
+- (Class)transactionClass {
+ return [DSAssetLockTransactionEntity class];
+}
+
+@end
diff --git a/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataProperties.h b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataProperties.h
new file mode 100644
index 000000000..fafef85b5
--- /dev/null
+++ b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataProperties.h
@@ -0,0 +1,31 @@
+//
+// Created by Vladimir Pirogov
+// Copyright © 2024 Dash Core Group. All rights reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "DSAssetLockTransactionEntity+CoreDataClass.h"
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface DSAssetLockTransactionEntity (CoreDataProperties)
+
++ (NSFetchRequest *)fetchRequest;
+
+@property (nonatomic, retain) NSOrderedSet *creditOutputs;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataProperties.m b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataProperties.m
new file mode 100644
index 000000000..3b8e838d9
--- /dev/null
+++ b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataProperties.m
@@ -0,0 +1,28 @@
+//
+// Created by Vladimir Pirogov
+// Copyright © 2024 Dash Core Group. All rights reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "DSAssetLockTransactionEntity+CoreDataProperties.h"
+
+@implementation DSAssetLockTransactionEntity (CoreDataProperties)
+
++ (NSFetchRequest *)fetchRequest {
+ return [NSFetchRequest fetchRequestWithEntityName:@"DSAssetLockTransactionEntity"];
+}
+
+@dynamic creditOutputs;
+
+@end
diff --git a/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataClass.h b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataClass.h
new file mode 100644
index 000000000..da8899d08
--- /dev/null
+++ b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataClass.h
@@ -0,0 +1,29 @@
+//
+// Created by Vladimir Pirogov
+// Copyright © 2024 Dash Core Group. All rights reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "DSSpecialTransactionEntity+CoreDataClass.h"
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface DSAssetUnlockTransactionEntity : DSSpecialTransactionEntity
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#import "DSAssetUnlockTransactionEntity+CoreDataProperties.h"
diff --git a/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataClass.m b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataClass.m
new file mode 100644
index 000000000..aa67b7306
--- /dev/null
+++ b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataClass.m
@@ -0,0 +1,64 @@
+//
+// Created by Vladimir Pirogov
+// Copyright © 2024 Dash Core Group. All rights reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "DSAddressEntity+CoreDataClass.h"
+#import "DSAssetUnlockTransaction.h"
+#import "DSAssetUnlockTransactionEntity+CoreDataClass.h"
+#import "DSChain+Protected.h"
+#import "DSChainEntity+CoreDataClass.h"
+#import "DSTransaction.h"
+#import "DSTransactionFactory.h"
+#import "NSData+Dash.h"
+#import "NSManagedObject+Sugar.h"
+
+@implementation DSAssetUnlockTransactionEntity
+
+- (instancetype)setAttributesFromTransaction:(DSTransaction *)transaction {
+ [self.managedObjectContext performBlockAndWait:^{
+ [super setAttributesFromTransaction:transaction];
+ DSAssetUnlockTransaction *tx = (DSAssetUnlockTransaction *)transaction;
+ self.specialTransactionVersion = tx.specialTransactionVersion;
+ self.index = tx.index;
+ self.fee = tx.fee;
+ self.requestedHeight = tx.requestedHeight;
+ self.quorumHash = uint256_data(tx.quorumHash);
+ self.quorumSignature = uint768_data(tx.quorumSignature);
+ }];
+
+ return self;
+}
+
+- (DSTransaction *)transactionForChain:(DSChain *)chain {
+ DSAssetUnlockTransaction *tx = (DSAssetUnlockTransaction *)[super transactionForChain:chain];
+ tx.type = DSTransactionType_AssetUnlock;
+ [self.managedObjectContext performBlockAndWait:^{
+ tx.specialTransactionVersion = self.specialTransactionVersion;
+ tx.index = self.index;
+ tx.fee = self.fee;
+ tx.requestedHeight = self.requestedHeight;
+ tx.quorumHash = self.quorumHash.UInt256;
+ tx.quorumSignature = self.quorumSignature.UInt768;
+ }];
+
+ return tx;
+}
+
+- (Class)transactionClass {
+ return [DSAssetUnlockTransaction class];
+}
+
+@end
diff --git a/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataProperties.h b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataProperties.h
new file mode 100644
index 000000000..9c2a7baa8
--- /dev/null
+++ b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataProperties.h
@@ -0,0 +1,35 @@
+//
+// Created by Vladimir Pirogov
+// Copyright © 2024 Dash Core Group. All rights reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "DSAssetUnlockTransactionEntity+CoreDataClass.h"
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface DSAssetUnlockTransactionEntity (CoreDataProperties)
+
++ (NSFetchRequest *)fetchRequest;
+
+@property (nonatomic, assign) uint64_t index;
+@property (nonatomic, assign) uint32_t fee;
+@property (nonatomic, assign) uint32_t requestedHeight;
+@property (nullable, nonatomic, retain) NSData *quorumHash;
+@property (nullable, nonatomic, retain) NSData *quorumSignature;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataProperties.m b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataProperties.m
new file mode 100644
index 000000000..b5d9b60d6
--- /dev/null
+++ b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataProperties.m
@@ -0,0 +1,32 @@
+//
+// Created by Vladimir Pirogov
+// Copyright © 2024 Dash Core Group. All rights reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "DSAssetUnlockTransactionEntity+CoreDataProperties.h"
+
+@implementation DSAssetUnlockTransactionEntity (CoreDataProperties)
+
++ (NSFetchRequest *)fetchRequest {
+ return [NSFetchRequest fetchRequestWithEntityName:@"DSAssetUnlockTransactionEntity"];
+}
+
+@dynamic index;
+@dynamic fee;
+@dynamic requestedHeight;
+@dynamic quorumHash;
+@dynamic quorumSignature;
+
+@end
diff --git a/DashSync/shared/Models/Masternode/DSMasternodeListService.m b/DashSync/shared/Models/Masternode/DSMasternodeListService.m
index 3c8c15700..17c7dd746 100644
--- a/DashSync/shared/Models/Masternode/DSMasternodeListService.m
+++ b/DashSync/shared/Models/Masternode/DSMasternodeListService.m
@@ -261,7 +261,7 @@ - (void)removeFromRetrievalQueue:(NSData *)masternodeBlockHashData {
double count = self.retrievalQueue.count;
@synchronized (self.chain.chainManager.syncState) {
self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueCount = count;
- self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueMaxAmount = self.retrievalQueueMaxAmount;
+ self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueMaxAmount = (uint32_t) self.retrievalQueueMaxAmount;
DSLog(@"[%@] Masternode list queue updated: %f/%lu", self.chain.name, count, self.retrievalQueueMaxAmount);
[self.chain.chainManager notifySyncStateChanged];
}
@@ -275,7 +275,7 @@ - (void)cleanListsRetrievalQueue {
[self.retrievalQueue removeAllObjects];
@synchronized (self.chain.chainManager.syncState) {
self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueCount = 0;
- self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueMaxAmount = self.retrievalQueueMaxAmount;
+ self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueMaxAmount = (uint32_t) self.retrievalQueueMaxAmount;
DSLog(@"[%@] Masternode list queue cleaned up: 0/%lu", self.chain.name, self.retrievalQueueMaxAmount);
[self.chain.chainManager notifySyncStateChanged];
}
@@ -302,8 +302,8 @@ - (void)updateMasternodeRetrievalQueue {
return [self.store heightForBlockHash:obj1.UInt256] < [self.store heightForBlockHash:obj2.UInt256] ? NSOrderedAscending : NSOrderedDescending;
}];
@synchronized (self.chain.chainManager.syncState) {
- self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueCount = currentCount;
- self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueMaxAmount = self.retrievalQueueMaxAmount;
+ self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueCount = (uint32_t) currentCount;
+ self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueMaxAmount = (uint32_t) self.retrievalQueueMaxAmount;
DSLog(@"[%@] Masternode list queue updated: %lu/%lu", self.chain.name, currentCount, self.retrievalQueueMaxAmount);
[self.chain.chainManager notifySyncStateChanged];
}
diff --git a/DashSync/shared/Models/Notifications/DSSyncState.m b/DashSync/shared/Models/Notifications/DSSyncState.m
index 8b5481480..09f03a4f7 100644
--- a/DashSync/shared/Models/Notifications/DSSyncState.m
+++ b/DashSync/shared/Models/Notifications/DSSyncState.m
@@ -28,7 +28,7 @@ - (id)copyWithZone:(NSZone *)zone {
return copy;
}
- (NSString *)description {
- return [NSString stringWithFormat:@"%u/%u/%u/%u",
+ return [NSString stringWithFormat:@"%u/%u/%f/%u",
self.retrievalQueueCount,
self.retrievalQueueMaxAmount,
self.storedCount,
diff --git a/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.h b/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.h
index 066472548..ac5cb6549 100644
--- a/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.h
+++ b/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.h
@@ -41,6 +41,7 @@ typedef NS_ENUM(NSInteger, DSCoreDataMigrationVersionValue)
DSCoreDataMigrationVersionValue_18 = 18,
DSCoreDataMigrationVersionValue_19 = 19,
DSCoreDataMigrationVersionValue_20 = 20,
+ DSCoreDataMigrationVersionValue_21 = 21,
};
@interface DSCoreDataMigrationVersion : NSObject
diff --git a/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.m b/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.m
index 5703cf186..e6526f1f1 100644
--- a/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.m
+++ b/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.m
@@ -20,7 +20,7 @@
@implementation DSCoreDataMigrationVersion
+ (DSCoreDataMigrationVersionValue)current {
- return DSCoreDataMigrationVersionValue_20;
+ return DSCoreDataMigrationVersionValue_21;
}
+ (NSString *)modelResourceForVersion:(DSCoreDataMigrationVersionValue)version {
@@ -45,6 +45,7 @@ + (NSString *)modelResourceForVersion:(DSCoreDataMigrationVersionValue)version {
case DSCoreDataMigrationVersionValue_18: return @"DashSync 18";
case DSCoreDataMigrationVersionValue_19: return @"DashSync 19";
case DSCoreDataMigrationVersionValue_20: return @"DashSync 20";
+ case DSCoreDataMigrationVersionValue_21: return @"DashSync 21";
default:
return [NSString stringWithFormat:@"DashSync %ld", (long)version];
}
diff --git a/DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.h b/DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.h
new file mode 100644
index 000000000..01349ba38
--- /dev/null
+++ b/DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.h
@@ -0,0 +1,31 @@
+//
+// Created by Vladimir Pirogov
+// Copyright © 2024 Dash Core Group. All rights reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import
+#import "DSTransaction.h"
+#import "DSTransactionOutput.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface DSAssetLockTransaction : DSTransaction
+
+@property (nonatomic, assign) uint8_t specialTransactionVersion;
+@property (nonatomic, assign) NSMutableArray *creditOutputs;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.m b/DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.m
new file mode 100644
index 000000000..1ce845e2a
--- /dev/null
+++ b/DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.m
@@ -0,0 +1,61 @@
+//
+// Created by Vladimir Pirogov
+// Copyright © 2024 Dash Core Group. All rights reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "DSAssetLockTransaction.h"
+#import "DSChain.h"
+#import "DSTransactionFactory.h"
+#import "NSData+Dash.h"
+
+@implementation DSAssetLockTransaction
+
+- (instancetype)initWithMessage:(NSData *)message onChain:(DSChain *)chain {
+ if (!(self = [super initWithMessage:message onChain:chain]))
+ return nil;
+ self.type = DSTransactionType_AssetLock;
+ NSUInteger length = message.length;
+ uint32_t off = self.payloadOffset;
+
+ if (length - off < 1) return nil;
+ NSNumber *payloadLengthSize = nil;
+ __unused uint64_t payloadLength = [message varIntAtOffset:off length:&payloadLengthSize];
+ off += payloadLengthSize.unsignedLongValue;
+
+ if (length - off < 1) return nil;
+ self.specialTransactionVersion = [message UInt8AtOffset:off];
+ off += 1;
+
+ NSNumber *l = 0;
+ if (length - off < 1) return nil;
+ uint64_t count = (NSUInteger)[message varIntAtOffset:off length:&l]; // output count
+ off += l.unsignedIntegerValue;
+
+ NSMutableArray *creditOutputs = [NSMutableArray arrayWithCapacity:count];
+ for (NSUInteger i = 0; i < count; i++) { // outputs
+ uint64_t amount = [message UInt64AtOffset:off]; // output amount
+ off += sizeof(uint64_t);
+ NSData *outScript = [message dataAtOffset:off length:&l]; // output script
+ off += l.unsignedIntegerValue;
+ DSTransactionOutput *transactionOutput = [DSTransactionOutput transactionOutputWithAmount:amount outScript:outScript onChain:self.chain];
+ [creditOutputs addObject:transactionOutput];
+ }
+ self.creditOutputs = creditOutputs;
+ self.payloadOffset = off;
+ self.txHash = self.data.SHA256_2;
+
+ return self;
+}
+@end
diff --git a/DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.h b/DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.h
new file mode 100644
index 000000000..2a825a4de
--- /dev/null
+++ b/DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.h
@@ -0,0 +1,34 @@
+//
+// Created by Vladimir Pirogov
+// Copyright © 2024 Dash Core Group. All rights reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import
+#import "BigIntTypes.h"
+#import "DSTransaction.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface DSAssetUnlockTransaction : DSTransaction
+@property (nonatomic, assign) uint8_t specialTransactionVersion;
+@property (nonatomic, assign) uint64_t index;
+@property (nonatomic, assign) uint32_t fee;
+@property (nonatomic, assign) uint32_t requestedHeight;
+@property (nonatomic, assign) UInt256 quorumHash;
+@property (nonatomic, assign) UInt768 quorumSignature;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.m b/DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.m
new file mode 100644
index 000000000..01824db34
--- /dev/null
+++ b/DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.m
@@ -0,0 +1,95 @@
+//
+// Created by Vladimir Pirogov
+// Copyright © 2024 Dash Core Group. All rights reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "DSAssetUnlockTransaction.h"
+#import "DSChain.h"
+#import "DSTransactionFactory.h"
+#import "NSData+Dash.h"
+#import "NSMutableData+Dash.h"
+
+@implementation DSAssetUnlockTransaction
+
+- (instancetype)initWithMessage:(NSData *)message onChain:(DSChain *)chain {
+ if (!(self = [super initWithMessage:message onChain:chain]))
+ return nil;
+ self.type = DSTransactionType_AssetUnlock;
+ NSUInteger length = message.length;
+ uint32_t off = self.payloadOffset;
+
+ if (length - off < 1) return nil;
+ NSNumber *payloadLengthSize = nil;
+ uint64_t payloadLength = [message varIntAtOffset:off length:&payloadLengthSize];
+ off += payloadLengthSize.unsignedLongValue;
+
+ if (length - off < 1) return nil;
+ self.specialTransactionVersion = [message UInt8AtOffset:off];
+ off += 1;
+ if (length - off < 8) return nil;
+ self.index = [message UInt64AtOffset:off];
+ off += 8;
+ if (length - off < 4) return nil;
+ self.fee = [message UInt32AtOffset:off];
+ off += 4;
+ if (length - off < 4) return nil;
+ self.requestedHeight = [message UInt32AtOffset:off];
+ off += 4;
+
+ if (length - off < 32) return nil;
+ self.quorumHash = [message UInt256AtOffset:off];
+ off += 32;
+ if (length - off < 96) return nil;
+ self.quorumSignature = [message UInt768AtOffset:off];
+ off += 96;
+
+ self.payloadOffset = off;
+ if ([self payloadData].length != payloadLength) return nil;
+ self.txHash = self.data.SHA256_2;
+
+ return self;
+
+}
+- (BOOL)transactionTypeRequiresInputs {
+ return NO;
+}
+- (NSData *)payloadData {
+ return [self basePayloadData];
+}
+
+- (NSData *)basePayloadData {
+ NSMutableData *data = [NSMutableData data];
+ [data appendUInt8:self.specialTransactionVersion];
+ [data appendUInt64:self.index];
+ [data appendUInt32:self.fee];
+ [data appendUInt32:self.requestedHeight];
+ [data appendUInt256:self.quorumHash];
+ [data appendUInt768:self.quorumSignature];
+ return data;
+}
+
+- (NSData *)toDataWithSubscriptIndex:(NSUInteger)subscriptIndex {
+ @synchronized(self) {
+ NSMutableData *data = [[super toDataWithSubscriptIndex:subscriptIndex] mutableCopy];
+ [data appendCountedData:[self payloadData]];
+ if (subscriptIndex != NSNotFound) [data appendUInt32:SIGHASH_ALL];
+ return data;
+ }
+}
+- (size_t)size {
+ return [super size] + [self payloadData].length;
+}
+
+@end
diff --git a/DashSync/shared/Models/Transactions/Base/DSTransaction.m b/DashSync/shared/Models/Transactions/Base/DSTransaction.m
index f6f0e1f9f..428853fb9 100644
--- a/DashSync/shared/Models/Transactions/Base/DSTransaction.m
+++ b/DashSync/shared/Models/Transactions/Base/DSTransaction.m
@@ -28,6 +28,7 @@
#import "DSAccount.h"
#import "DSAddressEntity+CoreDataClass.h"
+#import "DSAssetUnlockTransaction.h"
#import "DSChain.h"
#import "DSChainEntity+CoreDataClass.h"
#import "DSChainManager.h"
@@ -408,7 +409,7 @@ - (NSData *)toDataWithSubscriptIndex:(NSUInteger)subscriptIndex {
NSArray *outputs = self.outputs;
NSUInteger inputsCount = inputs.count;
NSUInteger outputsCount = outputs.count;
- BOOL forSigHash = ([self isMemberOfClass:[DSTransaction class]] || [self isMemberOfClass:[DSCreditFundingTransaction class]]) && subscriptIndex != NSNotFound;
+ BOOL forSigHash = ([self isMemberOfClass:[DSTransaction class]] || [self isMemberOfClass:[DSCreditFundingTransaction class]] || [self isMemberOfClass:[DSAssetUnlockTransaction class]]) && subscriptIndex != NSNotFound;
NSUInteger dataSize = 8 + [NSMutableData sizeOfVarInt:inputsCount] + [NSMutableData sizeOfVarInt:outputsCount] + TX_INPUT_SIZE * inputsCount + TX_OUTPUT_SIZE * outputsCount + (forSigHash ? 4 : 0);
NSMutableData *d = [NSMutableData dataWithCapacity:dataSize];
diff --git a/DashSync/shared/Models/Transactions/DSTransactionFactory.h b/DashSync/shared/Models/Transactions/DSTransactionFactory.h
index a31f8c34d..6f2e876a8 100644
--- a/DashSync/shared/Models/Transactions/DSTransactionFactory.h
+++ b/DashSync/shared/Models/Transactions/DSTransactionFactory.h
@@ -20,8 +20,8 @@ typedef NS_ENUM(NSUInteger, DSTransactionType)
DSTransactionType_ProviderUpdateRevocation = 4,
DSTransactionType_Coinbase = 5,
DSTransactionType_QuorumCommitment = 6,
- DSTransactionType_SubscriptionRegistration = 8,
- DSTransactionType_SubscriptionTopUp = 9,
+ DSTransactionType_AssetLock = 8,
+ DSTransactionType_AssetUnlock = 9,
DSTransactionType_SubscriptionResetKey = 10,
DSTransactionType_SubscriptionCloseAccount = 11,
DSTransactionType_Transition = 12,
diff --git a/DashSync/shared/Models/Transactions/DSTransactionFactory.m b/DashSync/shared/Models/Transactions/DSTransactionFactory.m
index e47c7d11a..4bc66e4d9 100644
--- a/DashSync/shared/Models/Transactions/DSTransactionFactory.m
+++ b/DashSync/shared/Models/Transactions/DSTransactionFactory.m
@@ -5,6 +5,8 @@
// Created by Sam Westrich on 7/12/18.
//
+#import "DSAssetLockTransaction.h"
+#import "DSAssetUnlockTransaction.h"
#import "DSTransactionFactory.h"
#import "DSBlockchainIdentityCloseTransition.h"
#import "DSBlockchainIdentityRegistrationTransition.h"
@@ -56,6 +58,10 @@ + (DSTransaction *)transactionWithMessage:(NSData *)message onChain:(DSChain *)c
return [DSProviderUpdateRegistrarTransaction transactionWithMessage:message onChain:chain];
case DSTransactionType_ProviderUpdateRevocation:
return [DSProviderUpdateRevocationTransaction transactionWithMessage:message onChain:chain];
+ case DSTransactionType_AssetLock:
+ return [DSAssetLockTransaction transactionWithMessage:message onChain:chain];
+ case DSTransactionType_AssetUnlock:
+ return [DSAssetUnlockTransaction transactionWithMessage:message onChain:chain];
case DSTransactionType_QuorumCommitment:
return [DSQuorumCommitmentTransaction transactionWithMessage:message onChain:chain];
default:
@@ -69,9 +75,9 @@ + (BOOL)ignoreMessagesOfTransactionType:(DSTransactionType)transactionType {
return FALSE;
case DSTransactionType_Coinbase:
return FALSE;
- case DSTransactionType_SubscriptionRegistration:
+ case DSTransactionType_AssetLock:
return FALSE;
- case DSTransactionType_SubscriptionTopUp:
+ case DSTransactionType_AssetUnlock:
return FALSE;
case DSTransactionType_SubscriptionCloseAccount:
return FALSE;
diff --git a/DashSync/shared/Models/Wallet/DSSpecialTransactionsWalletHolder.m b/DashSync/shared/Models/Wallet/DSSpecialTransactionsWalletHolder.m
index 60509ae7d..ba087139c 100644
--- a/DashSync/shared/Models/Wallet/DSSpecialTransactionsWalletHolder.m
+++ b/DashSync/shared/Models/Wallet/DSSpecialTransactionsWalletHolder.m
@@ -5,6 +5,8 @@
// Created by Sam Westrich on 3/5/19.
//
+#import "DSAssetLockTransaction.h"
+#import "DSAssetUnlockTransaction.h"
#import "DSSpecialTransactionsWalletHolder.h"
#import "DSAddressEntity+CoreDataClass.h"
#import "DSChain.h"
@@ -37,6 +39,8 @@ @interface DSSpecialTransactionsWalletHolder ()
@property (nonatomic, strong) NSMutableDictionary *providerUpdateRegistrarTransactions;
@property (nonatomic, strong) NSMutableDictionary *providerUpdateRevocationTransactions;
@property (nonatomic, strong) NSMutableDictionary *creditFundingTransactions;
+@property (nonatomic, strong) NSMutableDictionary *assetLockTransactions;
+@property (nonatomic, strong) NSMutableDictionary *assetUnlockTransactions;
@property (nonatomic, strong) NSMutableArray *transactionsToSave;
@property (nonatomic, strong) NSMutableDictionary *> *transactionsToSaveInBlockSave;
@@ -154,6 +158,18 @@ - (BOOL)registerTransaction:(DSTransaction *)transaction saveImmediately:(BOOL)s
[self.creditFundingTransactions setObject:transaction forKey:uint256_data(creditFundingTransaction.creditBurnIdentityIdentifier)];
added = TRUE;
}
+ } else if ([transaction isMemberOfClass:[DSAssetLockTransaction class]]) {
+ DSAssetLockTransaction *assetLockTransaction = (DSAssetLockTransaction *)transaction;
+ if (![self.assetLockTransactions objectForKey:uint256_data(assetLockTransaction.txHash)]) {
+ [self.assetLockTransactions setObject:transaction forKey:uint256_data(assetLockTransaction.txHash)];
+ added = TRUE;
+ }
+ } else if ([transaction isMemberOfClass:[DSAssetUnlockTransaction class]]) {
+ DSAssetUnlockTransaction *assetUnlockTransaction = (DSAssetUnlockTransaction *)transaction;
+ if (![self.assetUnlockTransactions objectForKey:uint256_data(assetUnlockTransaction.txHash)]) {
+ [self.assetUnlockTransactions setObject:transaction forKey:uint256_data(assetUnlockTransaction.txHash)];
+ added = TRUE;
+ }
} else {
NSAssert(FALSE, @"unknown transaction type being registered");
return NO;
@@ -198,6 +214,12 @@ - (void)loadTransactions {
} else if ([transaction isMemberOfClass:[DSCreditFundingTransaction class]]) {
DSCreditFundingTransaction *creditFundingTransaction = (DSCreditFundingTransaction *)transaction;
[self.creditFundingTransactions setObject:transaction forKey:uint256_data(creditFundingTransaction.creditBurnIdentityIdentifier)];
+ } else if ([transaction isMemberOfClass:[DSAssetLockTransaction class]]) {
+ DSAssetLockTransaction *assetLockTransaction = (DSAssetLockTransaction *)transaction;
+ [self.assetLockTransactions setObject:transaction forKey:uint256_data(assetLockTransaction.txHash)];
+ } else if ([transaction isMemberOfClass:[DSAssetUnlockTransaction class]]) {
+ DSAssetUnlockTransaction *assetUnlockTransaction = (DSAssetUnlockTransaction *)transaction;
+ [self.assetUnlockTransactions setObject:transaction forKey:uint256_data(assetUnlockTransaction.txHash)];
} else { //the other ones don't have addresses in payload
NSAssert(FALSE, @"Unknown special transaction type");
}
diff --git a/Example/DashSync/DSTransactionDetailViewController.m b/Example/DashSync/DSTransactionDetailViewController.m
index 8ba0bbde3..ed4552701 100644
--- a/Example/DashSync/DSTransactionDetailViewController.m
+++ b/Example/DashSync/DSTransactionDetailViewController.m
@@ -6,6 +6,8 @@
// Copyright © 2018 Dash Core Group. All rights reserved.
//
+#import "DSAssetLockTransaction.h"
+#import "DSAssetUnlockTransaction.h"
#import "DSTransactionDetailViewController.h"
#import "BRCopyLabel.h"
#import "DSTransactionAmountTableViewCell.h"
@@ -286,6 +288,10 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
cell.statusLabel.text = @"Coinbase Transaction";
} else if ([self.transaction isMemberOfClass:[DSCreditFundingTransaction class]]) {
cell.statusLabel.text = @"Classical Credit Funding Transaction";
+ } else if ([self.transaction isMemberOfClass:[DSAssetLockTransaction class]]) {
+ cell.statusLabel.text = @"Asset Lock Transaction";
+ } else if ([self.transaction isMemberOfClass:[DSAssetUnlockTransaction class]]) {
+ cell.statusLabel.text = @"Asset Unlock Transaction";
} else {
cell.statusLabel.text = @"Classical Transaction";
}
diff --git a/Example/Podfile.lock b/Example/Podfile.lock
index 0dd922b4b..27ed1c626 100644
--- a/Example/Podfile.lock
+++ b/Example/Podfile.lock
@@ -657,7 +657,7 @@ PODS:
- gRPC/Interface-Legacy (1.49.0):
- gRPC-RxLibrary/Interface (= 1.49.0)
- KVO-MVVM (0.5.1)
- - Protobuf (3.28.2)
+ - Protobuf (3.28.3)
- SDWebImage (5.14.3):
- SDWebImage/Core (= 5.14.3)
- SDWebImage/Core (5.14.3)
@@ -727,7 +727,7 @@ SPEC CHECKSUMS:
gRPC-ProtoRPC: 1c223e0f1732bb8d0b9e9e0ea60cc0fe995b8e2d
gRPC-RxLibrary: 92327f150e11cf3b1c0f52e083944fd9f5cb5d1e
KVO-MVVM: 4df3afd1f7ebcb69735458b85db59c4271ada7c6
- Protobuf: 28c89b24435762f60244e691544ed80f50d82701
+ Protobuf: 5a8a7781d8e1004302f108977ac2d5b99323146f
SDWebImage: 9c36e66c8ce4620b41a7407698dda44211a96764
tinycbor: d4d71dddda1f8392fbb4249f63faf8552f327590
TinyCborObjc: 5204540fb90ff0c40fb22d408fa51bab79d78a80
diff --git a/Example/Tests/DSTransactionTests.m b/Example/Tests/DSTransactionTests.m
index 7ae28a403..200cf6dc3 100644
--- a/Example/Tests/DSTransactionTests.m
+++ b/Example/Tests/DSTransactionTests.m
@@ -8,6 +8,7 @@
#import
+#import "DSAssetUnlockTransaction.h"
#import "DSAuthenticationKeysDerivationPath.h"
#import "DSBlockchainIdentityCloseTransition.h"
#import "DSBlockchainIdentityRegistrationTransition.h"
@@ -91,6 +92,11 @@ - (void)testTransaction {
XCTAssertEqualObjects(d, tx.data, @"[DSTransaction transactionWithMessage:]");
processor_destroy_opaque_key(k);
}
+- (void)testAssetUnlockTx {
+ NSData *transactionData = @"030009000001a02ffa0d000000001976a9146641c13e0ee2ce2cdf70852bb7ae9853c01f29a988ac0000000091014e00000000000000be000000273e11004130304f40d1820b5e239baecd35249263b1206a1c76e66053ec39a04501000093d3851b6bda0518da51ff8932ef3570be20e7978369dd312947326e135004915c10b5fe0e31e572c40f41cdd941bed8115e314573faf472e1065ca370bdff486db8eaa6bbcba3943e6e5ada6a3c30dee70e39811814e59e1ffc54f3c9fca04f".hexToData;
+ DSAssetUnlockTransaction *tx = [[DSAssetUnlockTransaction alloc] initWithMessage:transactionData onChain:[DSChain testnet]];
+ XCTAssert(tx, @"Bad Asset Unlock Tx");
+}
- (void)testBlockchainIdentityFundingTransactionUniqueId {
NSData *transactionData = @"0300000002b74030bbda6edd804d4bfb2bdbbb7c207a122f3af2f6283de17074a42c6a5417020000006b483045022100815b175ab1a8fde7d651d78541ba73d2e9b297e6190f5244e1957004aa89d3c902207e1b164499569c1f282fe5533154495186484f7db22dc3dc1ccbdc9b47d997250121027f69794d6c4c942392b1416566aef9eaade43fbf07b63323c721b4518127baadffffffffb74030bbda6edd804d4bfb2bdbbb7c207a122f3af2f6283de17074a42c6a5417010000006b483045022100a7c94fe1bb6ffb66d2bb90fd8786f5bd7a0177b0f3af20342523e64291f51b3e02201f0308f1034c0f6024e368ca18949be42a896dda434520fa95b5651dc5ad3072012102009e3f2eb633ee12c0143f009bf773155a6c1d0f14271d30809b1dc06766aff0ffffffff031027000000000000166a1414ec6c36e6c39a9181f3a261a08a5171425ac5e210270000000000001976a91414ec6c36e6c39a9181f3a261a08a5171425ac5e288acc443953b000000001976a9140d1775b9ed85abeb19fd4a7d8cc88b08a29fe6de88ac00000000".hexToData;