Nep5Token extends SmartContract { TransactionBuilder buildMultiTransferInvocation(Wallet wallet, ScriptHash to, BigDecimal amount, List<Account> accounts) throws IOException { List<byte[]> scripts = new ArrayList<>(); List<Signer> signers = new ArrayList<>(); Iterator<Account> it = accounts.iterator(); BigInteger remainingAmount = getAmountAsBigInteger(amount); while (remainingAmount.signum() > 0 && it.hasNext()) { Account a = it.next(); if (a.isMultiSig() && !privateKeysArePresentForMultiSig(wallet, a.getScriptHash())) { continue; } BigInteger balance = getBalanceOf(a.getScriptHash()); if (balance.signum() <= 0) { continue; } signers.add(Signer.calledByEntry(a.getScriptHash())); if (balance.compareTo(remainingAmount) >= 0) { scripts.add(buildSingleTransferScript(a, to, remainingAmount)); } else { scripts.add(buildSingleTransferScript(a, to, balance)); } remainingAmount = remainingAmount.subtract(balance); } if (remainingAmount.signum() > 0) { BigInteger amountToCover = getAmountAsBigInteger(amount); BigInteger coveredAmount = amountToCover.subtract(remainingAmount); throw new InsufficientFundsException("The wallet does not hold enough tokens, resp. " + "token-holding accounts with available private keys. The transfer amount is " + amountToCover.toString() + " " + getSymbol() + " but the wallet only holds " + coveredAmount.toString() + " " + getSymbol() + " (in token fractions)."); } return assembleMultiTransferTransaction(wallet, scripts, signers); } Nep5Token(ScriptHash scriptHash, Neow3j neow); String getName(); String getSymbol(); BigInteger getTotalSupply(); int getDecimals(); BigInteger getBalanceOf(ScriptHash scriptHash); BigInteger getBalanceOf(Wallet wallet); TransactionBuilder transfer(Wallet wallet, ScriptHash to, BigDecimal amount); TransactionBuilder transferFromSpecificAccounts(Wallet wallet, ScriptHash to,
            BigDecimal amount, ScriptHash... from); TransactionBuilder transferFromDefaultAccount(Wallet wallet, ScriptHash to,
            BigDecimal amount);  }
@Test public void testTransfer_MultiSig() throws IOException { setUpWireMockForCall("invokescript", "invokescript_transfer.json"); setUpWireMockForGetBlockCount(1000); setUpWireMockForInvokeFunction("decimals", "invokefunction_decimals.json"); setUpWireMockForBalanceOf(multiSigAccount.getScriptHash(), "invokefunction_balanceOf_3.json"); setUpWireMockForBalanceOf(account1.getScriptHash(), "invokefunction_balanceOf_4.json"); byte[] expectedScript = new ScriptBuilder() .contractCall(NEO_TOKEN_SCRIPT_HASH, NEP5_TRANSFER, Arrays.asList( ContractParameter.hash160(multiSigAccount.getScriptHash()), ContractParameter.hash160(RECIPIENT_SCRIPT_HASH), ContractParameter.integer(3))) .contractCall(NEO_TOKEN_SCRIPT_HASH, NEP5_TRANSFER, Arrays.asList( ContractParameter.hash160(account1.getScriptHash()), ContractParameter.hash160(RECIPIENT_SCRIPT_HASH), ContractParameter.integer(2))).toArray(); Wallet w = Wallet.withAccounts(multiSigAccount, account1, account2, account3); TransactionBuilder b = neoToken.buildMultiTransferInvocation(w, RECIPIENT_SCRIPT_HASH, new BigDecimal("5"), Arrays.asList(multiSigAccount, account1)); assertThat(b.getScript(), is(expectedScript)); }
@Test public void testTransferFromSpecificAccounts_firstAccountCoversAmount() throws IOException { setUpWireMockForCall("invokescript", "invokescript_transfer.json"); setUpWireMockForGetBlockCount(1000); setUpWireMockForInvokeFunction("decimals", "invokefunction_decimals.json"); setUpWireMockForBalanceOf(account2.getScriptHash(), "invokefunction_balanceOf_4.json"); byte[] expectedScript = new ScriptBuilder().contractCall(NEO_TOKEN_SCRIPT_HASH, NEP5_TRANSFER, Arrays.asList( ContractParameter.hash160(account2.getScriptHash()), ContractParameter.hash160(RECIPIENT_SCRIPT_HASH), ContractParameter.integer(4))).toArray(); Wallet w = Wallet.withAccounts(account1, account2, account3); TransactionBuilder b = neoToken.buildMultiTransferInvocation(w, RECIPIENT_SCRIPT_HASH, new BigDecimal("4"), Arrays.asList(account2, account3)); assertThat(b.getScript(), is(expectedScript)); }
@Test public void testTransferFromSpecificAccounts_firstConsideredAccountHasNoBalance() throws IOException { setUpWireMockForCall("invokescript", "invokescript_transfer.json"); setUpWireMockForGetBlockCount(1000); setUpWireMockForInvokeFunction("decimals", "invokefunction_decimals.json"); setUpWireMockForBalanceOf(account2.getScriptHash(), "invokefunction_balanceOf_0.json"); setUpWireMockForBalanceOf(account3.getScriptHash(), "invokefunction_balanceOf_3.json"); byte[] expectedScript = new ScriptBuilder() .contractCall(NEO_TOKEN_SCRIPT_HASH, NEP5_TRANSFER, Arrays.asList( ContractParameter.hash160(account3.getScriptHash()), ContractParameter.hash160(RECIPIENT_SCRIPT_HASH), ContractParameter.integer(1))).toArray(); Wallet w = Wallet.withAccounts(account1, account2, account3); TransactionBuilder b = neoToken.buildMultiTransferInvocation(w, RECIPIENT_SCRIPT_HASH, new BigDecimal("1"), Arrays.asList(account2, account3)); assertThat(b.getScript(), is(expectedScript)); }
@Test public void testTransferFromSpecificAccounts_firstAccountHasNoBalance() throws IOException { setUpWireMockForCall("invokescript", "invokescript_transfer.json"); setUpWireMockForGetBlockCount(1000); setUpWireMockForInvokeFunction("decimals", "invokefunction_decimals.json"); setUpWireMockForBalanceOf(account2.getScriptHash(), "invokefunction_balanceOf_0.json"); setUpWireMockForBalanceOf(account3.getScriptHash(), "invokefunction_balanceOf_3.json"); byte[] expectedScript = new ScriptBuilder().contractCall(NEO_TOKEN_SCRIPT_HASH, NEP5_TRANSFER, Arrays.asList( ContractParameter.hash160(account3.getScriptHash()), ContractParameter.hash160(RECIPIENT_SCRIPT_HASH), ContractParameter.integer(1))).toArray(); Wallet w = Wallet.withAccounts(account1, account2, account3); TransactionBuilder b = neoToken.buildMultiTransferInvocation(w, RECIPIENT_SCRIPT_HASH, new BigDecimal("1"), Arrays.asList(account2, account3)); assertThat(b.getScript(), is(expectedScript)); }
@Test(expected = InsufficientFundsException.class) public void testTransferFromSpecificAccounts_insufficientBalance() throws IOException { setUpWireMockForGetBlockCount(1000); setUpWireMockForInvokeFunction("decimals", "invokefunction_decimals.json"); setUpWireMockForInvokeFunction("symbol", "invokefunction_symbol.json"); setUpWireMockForBalanceOf(account1.getScriptHash(), "invokefunction_balanceOf_5.json"); setUpWireMockForBalanceOf(account3.getScriptHash(), "invokefunction_balanceOf_3.json"); Wallet w = Wallet.withAccounts(account1, account2, account3); neoToken.buildMultiTransferInvocation(w, RECIPIENT_SCRIPT_HASH, new BigDecimal("12"), Arrays.asList(account1, account3)); }