/// <summary> /// Adds the master signature into the approved masters of the desired account. /// The minimum signatures required to consider an account approved /// is defined bythe RequiredAuthorizations method. /// </summary> /// <param name="args"> /// args[0] = account to approve, /// args[1] = the master account used to approve this request</param> /// <returns></returns> public static bool ApproveRegularAccount(object[] args) { Runtime.Log("Approve called"); if (args.Length != 2) { Runtime.Log("Invalid parameters for ApproveRegularAccount"); return(false); } byte[] newAccount = (byte[])args[0]; byte[] masterAccountKey = (byte[])args[1]; if (newAccount.Length != 20 || masterAccountKey.Length != 20) { Runtime.Log("Invalid parameters for ApproveRegularAccount"); return(false); } byte[] masterAccounts = BankDao.GetMasterAccounts(); if (masterAccounts.Length == 0) { Runtime.Log("Master account not found or not approved"); return(false); } byte[] account = BankDao.GetRegularAccount(newAccount); if (account.Length == 0) { Runtime.Log("Account not registered"); return(false); } Map <byte[], object> masterAccountsObjects = (Map <byte[], object>)masterAccounts.Deserialize(); if (masterAccountsObjects.HasKey(masterAccountKey)) { Map <string, object> masterAccountMap = (Map <string, object>)masterAccountsObjects[masterAccountKey]; Map <string, object> accountMap = (Map <string, object>)account.Deserialize(); //if (Runtime.CheckWitness(masterAccountKey)) if (true) { Map <byte[], BigInteger> accountApprovals = (Map <byte[], BigInteger>)accountMap[ModelMap.ACCOUNT_MASTER_APPROVALS]; if (accountApprovals.HasKey(masterAccountKey)) { BigInteger approvalStatus = accountApprovals[masterAccountKey]; if (approvalStatus != 1) { accountApprovals[masterAccountKey] = 1; accountMap[ModelMap.ACCOUNT_MASTER_APPROVALS] = accountApprovals; BankDao.PersistRegularAccount(newAccount, accountMap.Serialize()); Notifier.NotifyRegularAccountApproved(masterAccountKey, newAccount); return(true); } } else { accountApprovals[masterAccountKey] = 1; BankDao.PersistRegularAccount(newAccount, accountMap.Serialize()); Notifier.NotifyRegularAccountApproved(masterAccountKey, newAccount); return(true); } } } return(false); }
/// <summary> /// Creates tokens and tag it to the master that is creating it. /// </summary> /// <param name="args"></param> /// <returns></returns> public static bool MintTokens(object[] args) { if (args.Length != 3) { Runtime.Log("Invalid parameters for MintTokens"); return(false); } byte[] masterAccount = (byte[])args[0]; if (masterAccount.Length != 20) { Runtime.Log("Invalid master account"); return(false); } byte[] masterAccounts = BankDao.GetMasterAccounts(); if (masterAccounts.Length == 0) { Runtime.Log("Mint called before Deploy. Contract not deployed"); return(false); } Map <byte[], BigInteger> masterAccountsObjects = (Map <byte[], BigInteger>)masterAccounts.Deserialize(); if (!masterAccountsObjects.HasKey(masterAccount)) { Runtime.Log("Master Account not found"); return(false); } //if (!Runtime.CheckWitness(masterAccount)) //{ // Runtime.Log("Check Witness failed for master account"); // return false; //} byte[] recipient = (byte[])args[1]; if (recipient.Length != 20) { Runtime.Log("Invalid recipient to Mint"); return(false); } byte[] amountBytes = (byte[])args[2]; if (amountBytes.Length == 0) { Runtime.Log("Invalid amount to Mint"); return(false); } BigInteger amount = amountBytes.AsBigInteger(); if (amount > MaxMint) { Runtime.Log("Amount too large to Mint. "); return(false); } byte[] account = BankDao.GetRegularAccount(recipient); if (account.Length == 0) { Runtime.Log("Account not found"); return(false); } Map <string, object> accountMap = (Map <string, object>)account.Deserialize(); bool accountIsApproved = AccountHasApprovals(accountMap); if (!accountIsApproved) { Runtime.Log("Account not approved"); return(false); } Map <byte[], object> unspentTransactions = (Map <byte[], object>)accountMap[ModelMap.ACCOUNT_UNSPENT]; Transaction invocationTransaction = (Transaction)ExecutionEngine.ScriptContainer; uint currentBlockHeight = Blockchain.GetHeight(); object[] previousTransactions = new object[] { invocationTransaction.Hash }; Map <string, byte[]> transaction = CreateTransaction(currentBlockHeight, 1, masterAccount, amount, previousTransactions); byte[] serializedTransaction = transaction.Serialize(); byte[] transactionHash = Hash256(serializedTransaction); if (unspentTransactions.HasKey(transactionHash)) { Runtime.Log("Invalid transaction hash to mint"); return(false); } unspentTransactions[transactionHash] = serializedTransaction; accountMap[ModelMap.ACCOUNT_UNSPENT] = unspentTransactions; BankDao.PersistRegularAccount(recipient, accountMap.Serialize()); Notifier.NotifyMint(masterAccount, amount, recipient, transactionHash); return(true); }
/// <summary> /// Inserts a new account into the database. The account must be inserted prior to being approved. /// The account can only be registered by the owner (using the account signature) /// </summary> /// <param name="args"> /// Args[0] = Account ScriptHash, /// Args[1] = publicKey, /// Args[2] = signature, /// Args[3] = type (1 for personal 2 for enterprise), /// Args[4] = document, /// Args[5] = name, /// Args[6] = email, /// Args[7] = description </param> /// <returns></returns> public static bool RegisterRegularAccount(object[] args) { if (args.Length != 8) { Runtime.Log("Invalid parameters for RegisterRegularAccount"); return(false); } byte[] newAccount = (byte[])args[0]; if (newAccount.Length != 20) { Runtime.Log("Invalid parameters for ApproveRegularAccount"); return(false); } //if (!Runtime.CheckWitness(newAccount)) //{ // Runtime.Log("Invalid signature for account " + newAccount); // return false; //} byte[] currentAccount = BankDao.GetRegularAccount(newAccount); if (currentAccount.Length != 0) { Runtime.Log("Account already exists " + newAccount); return(false); } byte[] publicKey = (byte[])args[1]; byte[] signature = (byte[])args[2]; if (publicKey.Length == 0) { Runtime.Log("Invalid public key"); return(false); } if (signature.Length == 0) { Runtime.Log("Invalid Signature"); return(false); } BigInteger accountType = (BigInteger)args[3]; if (accountType != 1 && accountType != 2) { Runtime.Log("Invalid account type"); return(false); } string document = (string)args[4]; if (document.Length < 10 || document.Length > 24) { Runtime.Log("Invalid document"); return(false); } string accountName = (string)args[5]; if (accountName.Length <= 3) { Runtime.Log("Invalid account name"); return(false); } string email = (string)args[6]; if (email.Length < 5) { Runtime.Log("Invalid e-mail"); return(false); } string description = (string)args[7]; if (description.Length > 255) { Runtime.Log("Remarks too long"); return(false); } Map <string, object> accountMap = CreateRegularAccount(publicKey, document, email, accountName, accountType, description); BankDao.PersistRegularAccount(newAccount, accountMap.Serialize()); BankDao.PersistSignature(newAccount, signature); Notifier.NotifyNewRegularAccount(newAccount); return(true); }
/// <summary> /// Private method used to transfer values from one account to another. /// </summary> /// <param name="senderScriptHash"></param> /// <param name="recipientScriptHash"></param> /// <param name="sender"></param> /// <param name="recipient"></param> /// <param name="amount"></param> /// <param name="transactions"></param> /// <returns></returns> private static object DoTransfer(byte[] senderScriptHash, byte[] recipientScriptHash, Map <string, object> sender, Map <string, object> recipient, BigInteger amount, object[] transactions) { BigInteger transactionCount = transactions.Length; BigInteger totalInTransfers = 0; Map <byte[], object> senderUnspentTransactions = (Map <byte[], object>)sender[ModelMap.ACCOUNT_UNSPENT]; Map <byte[], object> spentTransactions = new Map <byte[], object>(); Map <byte[], object> recipientUnspentTransactions = (Map <byte[], object>)recipient[ModelMap.ACCOUNT_UNSPENT]; for (int i = 0; i < transactionCount; i++) { byte[] transactionHash = (byte[])transactions[i]; if (!senderUnspentTransactions.HasKey(transactionHash)) { Runtime.Log("Not the owner"); return(false); } byte[] transactionBytes = (byte[])senderUnspentTransactions[transactionHash]; Map <string, object> transaction = (Map <string, object>)transactionBytes.Deserialize(); byte[] amountInTransactionBytes = (byte[])transaction[ModelMap.TRANSACTION_AMOUNT]; if (amountInTransactionBytes.Length <= 0) { return(false); } senderUnspentTransactions.Remove(transactionHash); spentTransactions[transactionHash] = transaction; BigInteger amountInTransaction = amountInTransactionBytes.AsBigInteger(); totalInTransfers += amountInTransaction; if (totalInTransfers >= amount) { Runtime.Log("There is enough in the transactions sent."); if (i != transactionCount - 1) { Runtime.Log("Too many transactions"); return(false); } BigInteger change = totalInTransfers - amount; uint currentBlockHeight = Blockchain.GetHeight(); byte[] changeTransactionHash = new byte[0]; if (change > 0) { Runtime.Log("Has change!"); object[] previousTransactions = new object[] { transactionHash }; Map <string, byte[]> changeTransaction = CreateTransaction(currentBlockHeight, 0, new byte[0], change, previousTransactions); byte[] serializedChangeTransaction = changeTransaction.Serialize(); changeTransactionHash = Hash256(serializedChangeTransaction); senderUnspentTransactions[changeTransactionHash] = serializedChangeTransaction; } object[] previousTransactionsNewTransaction = new object[spentTransactions.Keys.Length]; for (int j = 0; j < spentTransactions.Keys.Length; j++) { byte[] spentTransactionHash = spentTransactions.Keys[j]; previousTransactionsNewTransaction[j] = spentTransactionHash; } Map <string, byte[]> sentTransaction = CreateTransaction(currentBlockHeight, 0, new byte[0], amount, previousTransactionsNewTransaction); byte[] serializedSentTransaction = sentTransaction.Serialize(); byte[] sentTransactionHash = Hash256(serializedSentTransaction); recipientUnspentTransactions[sentTransactionHash] = serializedSentTransaction; BankDao.PersistRegularAccount(senderScriptHash, sender.Serialize()); BankDao.PersistRegularAccount(recipientScriptHash, recipient.Serialize()); Notifier.NotifyTransfer(senderScriptHash, recipientScriptHash, amount, sentTransactionHash, change, changeTransactionHash); return(true); } } return(false); }