1 module tagion.wallet.AccountDetails; 2 import std.format; 3 import tagion.basic.Types; 4 import tagion.crypto.Types; 5 6 //import tagion.script.prior.StandardRecords; 7 import tagion.dart.DARTBasic; 8 import tagion.hibon.Document; 9 import tagion.hibon.HiBONRecord; 10 import tagion.script.TagionCurrency; 11 import tagion.script.common; 12 import tagion.script.standardnames; 13 14 @safe 15 struct AccountDetails { 16 @optional string name; 17 @label(StdNames.owner) @optional Pubkey owner; 18 @label("$derivers") Buffer[Pubkey] derivers; 19 @label("$bills") TagionBill[] bills; 20 @label("$used") TagionBill[] used_bills; 21 @label("$state") Buffer derive_state; 22 @label("$locked") bool[Pubkey] activated; /// locked bills 23 @label("$requested") TagionBill[Pubkey] requested; /// Requested bills 24 @label("$requested_invoices") Invoice[] requested_invoices; 25 @label("$hirpc") Document[] hirpcs; /// HiRPC request 26 import std.algorithm : any, each, filter, map, sum; 27 28 bool remove_bill(Pubkey pk) { 29 import std.algorithm : countUntil, remove; 30 31 const index = countUntil!"a.owner == b"(bills, pk); 32 if (index > 0) { 33 bills = bills.remove(index); 34 return true; 35 } 36 return false; 37 } 38 39 void remove_bill_by_hash(const(DARTIndex) billHash) { 40 import std.algorithm : countUntil, remove; 41 import tagion.crypto.SecureNet : StdHashNet; 42 43 const net = new StdHashNet; 44 45 auto billsHashes = bills.map!(b => cast(Buffer) net.calcHash(b.toDoc.serialize)).array; 46 const index = billsHashes.countUntil(billHash); 47 bills = bills.remove(index); 48 } 49 50 void unlock_bill_by_hash(const(DARTIndex) billHash) { 51 import std.algorithm : countUntil, remove; 52 import tagion.crypto.SecureNet : StdHashNet; 53 54 const net = new StdHashNet; 55 56 auto billsHashes = bills.map!(b => cast(Buffer) net.calcHash(b.toDoc.serialize)).array; 57 const index = billsHashes.countUntil(billHash); 58 59 activated.remove(bills[index].owner); 60 } 61 62 pragma(msg, "Don't think this function fits in AccountDetails"); 63 int check_contract_payment(const(DARTIndex)[] inputs, const(Document[]) outputs) { 64 import std.algorithm : countUntil; 65 import tagion.crypto.SecureNet : StdHashNet; 66 67 const net = new StdHashNet; 68 69 auto billsHashes = bills.map!(b => cast(Buffer) net.calcHash(b.toDoc.serialize)).array; 70 71 // Look for input matches. Return 0 from func if found. 72 foreach (inputHash; inputs) { 73 const index = countUntil!"a == b"(billsHashes, inputHash); 74 if (index >= 0) { 75 return 0; 76 } 77 } 78 // Proceed if inputs are not matched. 79 // Look for outputs matches. Return 1 from func if found or 2 if not. 80 foreach (outputPubkey; outputs.map!(output => output[StdNames.owner].get!Pubkey)) { 81 const index = countUntil!"a.owner == b"(bills, outputPubkey); 82 if (index >= 0) { 83 return 1; 84 } 85 } 86 87 if (bills.length == 0) { 88 return 1; 89 } 90 91 return 2; 92 } 93 94 bool check_invoice_payment(Pubkey invoicePubkey, ref TagionCurrency amount) { 95 import std.algorithm : countUntil; 96 97 const index = countUntil!"a.owner == b"(bills, invoicePubkey); 98 if (index >= 0) { 99 amount = bills[index].value; 100 return true; 101 } 102 return false; 103 } 104 105 bool add_bill(TagionBill bill) { 106 if (bill.owner in requested) { 107 bills ~= requested[bill.owner]; 108 requested.remove(bill.owner); 109 return true; 110 } 111 return false; 112 } 113 114 TagionBill add_bill(const Document doc) { 115 auto bill = TagionBill(doc); 116 const added=add_bill(bill); 117 if (added) { 118 return bill; 119 } 120 return TagionBill.init; 121 } 122 123 void requestBill(TagionBill bill, Buffer derive) { 124 check((bill.owner in derivers) is null, format("Bill %(%x%) already exists", bill.owner)); 125 derivers[bill.owner] = derive; 126 requested[bill.owner] = bill; 127 } 128 /++ 129 Clear up the Account 130 Remove used bills 131 +/ 132 void clearup() pure { 133 bills 134 .filter!(b => b.owner in derivers) 135 .each!(b => derivers.remove(b.owner)); 136 bills 137 .filter!(b => b.owner in activated) 138 .each!(b => activated.remove(b.owner)); 139 } 140 141 const pure { 142 /++ 143 Returns: 144 true if the all transaction has been registered as processed 145 +/ 146 bool processed() nothrow { 147 return bills 148 .any!(b => (b.owner in activated)); 149 } 150 /++ 151 Returns: 152 The available balance 153 +/ 154 TagionCurrency available() { 155 return bills 156 .filter!(b => !(b.owner in activated)) 157 .map!(b => b.value) 158 .sum; 159 } 160 /++ 161 Returns: 162 The total locked amount 163 +/ 164 TagionCurrency locked() { 165 return bills 166 .filter!(b => b.owner in activated) 167 .map!(b => b.value) 168 .sum; 169 } 170 /++ 171 Returns: 172 The total balance including the locked bills 173 +/ 174 TagionCurrency total() { 175 return bills 176 .map!(b => b.value) 177 .sum; 178 } 179 } 180 mixin HiBONRecord; 181 } 182 183 @safe 184 @recordType("Invoice") 185 struct Invoice { 186 string name; /// Name of the invoice 187 TagionCurrency amount; /// Amount to be payed 188 @label(StdNames.owner) Pubkey pkey; /// Key to the payee 189 @optional Document info; /// Information about the invoice 190 mixin HiBONRecord; 191 } 192 193 @safe 194 struct Invoices { 195 Invoice[] list; /// List of invoice (store in the wallet) 196 mixin HiBONRecord; 197 }