/// <summary> /// Transfer the amount desired using selected transactions. /// </summary> /// <param name="args"> [owner, recipient, amount, [txId, txId, ...]]</param> /// <returns></returns> public static object TransferTransactions(object[] args) { if (args.Length != 4) { return(false); } byte[] owner = (byte[])args[0]; if (owner.Length != 20) { return(false); } //if(!Runtime.CheckWitness(owner)) //{ // Runtime.Log("Not authorized"); // return false; //} byte[] accountBytes = BankDao.GetRegularAccount(owner); if (accountBytes.Length == 0) { Runtime.Log("Account not found"); return(false); } byte[] recipient = (byte[])args[1]; if (recipient.Length != 20) { Runtime.Log("Invalid recipient"); return(false); } byte[] recipientAccountBytes = BankDao.GetRegularAccount(owner); if (recipientAccountBytes.Length == 0) { Runtime.Log("Recipient can't be null"); return(false); } BigInteger amountToTransfer = (BigInteger)args[2]; if (amountToTransfer <= 0) { Runtime.Log("Amount can't be zero"); return(false); } Map <string, object> ownerAccount = (Map <string, object>)accountBytes.Deserialize(); Map <string, object> recipientAccount = (Map <string, object>)recipientAccountBytes.Deserialize(); //Logic starts here object[] transactions = (object[])args[3]; return(DoTransfer(owner, recipient, ownerAccount, recipientAccount, amountToTransfer, transactions)); }
/// <summary> /// Returns account information without balance and master approvals. /// </summary> /// <param name="args"></param> /// <returns></returns> public static object[] GetRegularAccount(object[] args) { if (args.Length != 1) { Runtime.Log("Invalid parameters for GetAccount"); return(new object[0]); } byte[] accountAddress = (byte[])args[0]; if (accountAddress.Length != 20) { Runtime.Log("Invalid address"); return(new object[0]); } byte[] account = BankDao.GetRegularAccount(accountAddress); if (account.Length == 0) { Runtime.Log("Account not found"); return(new object[0]); } Map <string, object> accountMap = (Map <string, object>)account.Deserialize(); object[] serializedAccount = new object[7]; serializedAccount[0] = accountMap[ModelMap.ACCOUNT_DOCUMENT]; serializedAccount[1] = accountMap[ModelMap.ACCOUNT_EMAIL]; serializedAccount[2] = accountMap[ModelMap.ACCOUNT_NAME]; serializedAccount[3] = accountMap[ModelMap.ACCOUNT_PUBLIC_KEY]; serializedAccount[4] = accountMap[ModelMap.ACCOUNT_REMARKS]; serializedAccount[6] = accountMap[ModelMap.ACCOUNT_TYPE]; return(serializedAccount); }
/// <summary> /// Get the account status. 1 for approved, 0 for waiting approval / not approved and -1 for account not found /// </summary> /// <param name="args"></param> /// <returns></returns> public static BigInteger GetAccountStatus(object[] args) { if (args.Length != 1) { Runtime.Log("Invalid parameters for GetAccountStatus"); return(-1); } byte[] account = (byte[])args[0]; if (account.Length != 20) { Runtime.Log("Invalid account for GetAccountStatus"); return(-1); } byte[] masterAccounts = BankDao.GetMasterAccounts(); if (masterAccounts.Length != 0) { Map <byte[], BigInteger> masterAccountsObjects = (Map <byte[], BigInteger>)masterAccounts.Deserialize(); byte[] accountBytes = BankDao.GetRegularAccount(account); if (accountBytes.Length == 0) { Runtime.Log("Account not registered"); return(-1); } Map <string, object> accountMap = (Map <string, object>)accountBytes.Deserialize(); if (AccountHasApprovals(accountMap)) { return(1); } } return(0); }
/// <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> /// Retrieves user unspent transactions. /// </summary> /// <param name="args">args[0] = Address script hash</param> /// <returns></returns> public static object GetBalance(object[] args) { if (args.Length != 1) { return(new object[0]); } byte[] account = (byte[])args[0]; if (account.Length != 20) { return(new object[0]); } byte[] serializedAccount = BankDao.GetRegularAccount(account); if (serializedAccount.Length == 0) { return(new object[0]); } Map <string, object> accountMap = (Map <string, object>)serializedAccount.Deserialize(); if (accountMap.HasKey(ModelMap.ACCOUNT_UNSPENT)) { Map <byte[], byte[]> unspentTransactions = (Map <byte[], byte[]>)accountMap[ModelMap.ACCOUNT_UNSPENT]; if (unspentTransactions.Keys.Length == 0) { Runtime.Log("No unspent found"); return(new object[0]); } int modelSize = 5; object[] readableUnspent = new object[unspentTransactions.Keys.Length * modelSize]; for (int i = 0; i < unspentTransactions.Keys.Length; i++) { byte[] txKey = unspentTransactions.Keys[i]; Runtime.Log(txKey.AsString()); byte[] txBytes = unspentTransactions[txKey]; Runtime.Log(txBytes.AsString()); if (txBytes.Length > 0) { Map <string, object> tx = (Map <string, object>)txBytes.Deserialize(); readableUnspent[i * modelSize] = txKey; readableUnspent[i * modelSize + 1] = tx[ModelMap.TRANSACTION_AMOUNT]; readableUnspent[i * modelSize + 2] = tx[ModelMap.TRANSACTION_BLOCK]; readableUnspent[i * modelSize + 3] = tx[ModelMap.TRANSACTION_MASTER_OWNERS]; //tx[ModelMap.TRANSACTION_AMOUNT]; byte[] previousTransactionsBytes = (byte[])tx[ModelMap.TRANSACTION_PREVIOUS_TRANSACTION_HASH]; object[] transactions = (object[])previousTransactionsBytes.Deserialize(); byte[] transactionsArray = new byte[0]; foreach (byte[] transaction in transactions) { transactionsArray = transactionsArray.Concat(transaction); } readableUnspent[i * modelSize + 4] = transactionsArray; } } return(readableUnspent); } return(new object[0]); }
/// <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> /// 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); }
public static object TransferAmount(object[] args) { if (args.Length != 3) { Runtime.Log("Invalid parameters"); return(false); } byte[] owner = (byte[])args[0]; if (owner.Length != 20) { return(false); } //if (!Runtime.CheckWitness(owner)) //{ // Runtime.Log("Not authorized"); // return false; //} byte[] accountBytes = BankDao.GetRegularAccount(owner); if (accountBytes.Length == 0) { Runtime.Log("Account not found"); return(false); } byte[] recipient = (byte[])args[1]; if (recipient.Length != 20) { Runtime.Log("Invalid recipient"); return(false); } byte[] recipientBytes = BankDao.GetRegularAccount(recipient); if (recipientBytes.Length == 0) { Runtime.Log("Account not found"); return(false); } BigInteger amount = (BigInteger)args[2]; if (amount <= 0) { Runtime.Log("Invalid amount"); return(false); } Map <string, object> ownerAccount = (Map <string, object>)accountBytes.Deserialize(); Map <string, object> recipientAccount = (Map <string, object>)recipientBytes.Deserialize(); Map <byte[], object> senderUnspentTransactions = (Map <byte[], object>)ownerAccount[ModelMap.ACCOUNT_UNSPENT]; Map <byte[], object> spentTransactions = new Map <byte[], object>(); BigInteger accumulatedTotal = 0; for (int i = 0; i < senderUnspentTransactions.Keys.Length; i++) { byte[] transactionHash = senderUnspentTransactions.Keys[i]; byte[] unspentTransaction = (byte[])senderUnspentTransactions[transactionHash]; if (unspentTransaction.Length > 0) { Runtime.Log("Has unspent"); Map <string, byte[]> tx = (Map <string, byte[]>)unspentTransaction.Deserialize(); spentTransactions[transactionHash] = unspentTransaction; BigInteger transactionAmount = tx[ModelMap.TRANSACTION_AMOUNT].AsBigInteger(); accumulatedTotal += transactionAmount; if (accumulatedTotal >= amount) { Runtime.Log("Has funds"); object[] transactionsToTransfer = new object[spentTransactions.Keys.Length]; for (int j = 0; j < spentTransactions.Keys.Length; j++) { byte[] spentTxHash = spentTransactions.Keys[i]; transactionsToTransfer[i] = transactionHash; } return(DoTransfer(owner, recipient, ownerAccount, recipientAccount, amount, transactionsToTransfer)); } else { Runtime.Log("Not enough funds"); } } else { Runtime.Log("No unspent"); } } return(false); }