From ebfa72e6482546160a1c03795edc433b584201a3 Mon Sep 17 00:00:00 2001 From: Stanimir Stoyanov Date: Thu, 16 Jan 2025 17:48:19 +0200 Subject: [PATCH 1/3] fix: Enable the nft airdrops to distribute multiple serials Signed-off-by: Stanimir Stoyanov --- .../hts/airdrops/TokenAirdropDecoder.java | 30 ++--- .../airdrops/AirdropSystemContractTest.java | 106 +++++++++++++++++- .../contract/contracts/Airdrop/Airdrop.bin | 2 +- .../contract/contracts/Airdrop/Airdrop.sol | 2 +- 4 files changed, 124 insertions(+), 16 deletions(-) diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/airdrops/TokenAirdropDecoder.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/airdrops/TokenAirdropDecoder.java index 0ec657739482..b5e7a7f9cc7c 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/airdrops/TokenAirdropDecoder.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/airdrops/TokenAirdropDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-2025 Hedera Hashgraph, LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -99,18 +99,22 @@ private TokenAirdropTransactionBody bodyForAirdrop( tokenTransferList.transfers(aaList); } if (nftAmountsTuple.length > 0) { - final var nftAmount = nftAmountsTuple[0]; - final var serial = (long) nftAmount.get(NFT_SERIAL); - final var sender = addressIdConverter.convert(nftAmount.get(NFT_SENDER)); - final var receiver = addressIdConverter.convert(nftAmount.get(NFT_RECEIVER)); - checkForSystemAccount(receiver); - final var isApproval = (boolean) nftAmount.get(NFT_IS_APPROVAL); - tokenTransferList.nftTransfers(NftTransfer.newBuilder() - .senderAccountID(sender) - .receiverAccountID(receiver) - .serialNumber(serial) - .isApproval(isApproval) - .build()); + final var nftTransfersList = new ArrayList(); + Arrays.stream(nftAmountsTuple).forEach(nftAmount -> { + final var serial = (long) nftAmount.get(NFT_SERIAL); + final var sender = addressIdConverter.convert(nftAmount.get(NFT_SENDER)); + final var receiver = addressIdConverter.convert(nftAmount.get(NFT_RECEIVER)); + checkForSystemAccount(receiver); + final var isApproval = (boolean) nftAmount.get(NFT_IS_APPROVAL); + final var nftTransfer = NftTransfer.newBuilder() + .senderAccountID(sender) + .receiverAccountID(receiver) + .serialNumber(serial) + .isApproval(isApproval) + .build(); + nftTransfersList.add(nftTransfer); + }); + tokenTransferList.nftTransfers(nftTransfersList); } transferBuilderList.add(tokenTransferList.build()); }); diff --git a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/airdrops/AirdropSystemContractTest.java b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/airdrops/AirdropSystemContractTest.java index ac8e18cd4c5f..4aea7c61393f 100644 --- a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/airdrops/AirdropSystemContractTest.java +++ b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/airdrops/AirdropSystemContractTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-2025 Hedera Hashgraph, LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -492,4 +492,108 @@ public Stream failToUpdateNFTsMetadata( .andAssert(txn -> txn.hasKnownStatuses(CONTRACT_REVERT_EXECUTED, INVALID_TOKEN_NFT_SERIAL_NUMBER))); } + + @HapiTest + @Order(12) + @DisplayName("Distribute NFTs to multiple accounts") + public Stream distributeNfts( + @NonNull @NonFungibleToken(numPreMints = 3) final SpecNonFungibleToken nft, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver1, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver2, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver3) { + return hapiTest(withOpContext((spec, opLog) -> { + allRunFor( + spec, + sender.associateTokens(nft), + receiver1.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver2.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver3.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver1.getInfo(), + receiver1.getInfo(), + receiver3.getInfo(), + nft.treasury().transferNFTsTo(sender, nft, 1L, 2L, 3L)); + allRunFor( + spec, + airdropContract + .call( + "nftAirdropDistribute", + nft, + sender, + prepareAccountAddresses(spec, receiver1, receiver2, receiver3)) + .gas(1500000), + receiver1.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 1L)), + receiver2.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 1L)), + receiver3.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 1L)), + nft.serialNo(1L).assertOwnerIs(receiver1), + nft.serialNo(2L).assertOwnerIs(receiver2), + nft.serialNo(3L).assertOwnerIs(receiver3)); + })); + } + + @HapiTest + @Order(13) + @DisplayName("Cannon Distribute 11 NFTs to multiple accounts") + public Stream distributeNftsOutOfBound( + @NonNull @NonFungibleToken(numPreMints = 11) final SpecNonFungibleToken nft, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver1, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver2, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver3, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver4, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver5, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver6, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver7, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver8, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver9, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver10, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver11) { + return hapiTest(withOpContext((spec, opLog) -> { + allRunFor( + spec, + sender.associateTokens(nft), + receiver1.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver2.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver3.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver4.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver5.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver6.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver7.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver8.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver9.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver10.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver11.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + nft.treasury().transferNFTsTo(sender, nft, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L), + nft.treasury().transferNFTsTo(sender, nft, 11L)); + allRunFor( + spec, + airdropContract + .call( + "nftAirdropDistribute", + nft, + sender, + prepareAccountAddresses( + spec, + receiver1, + receiver2, + receiver3, + receiver4, + receiver5, + receiver6, + receiver7, + receiver8, + receiver9, + receiver10, + receiver11)) + .andAssert(txn -> txn.hasKnownStatuses(CONTRACT_REVERT_EXECUTED)) + .gas(1500000), + receiver1.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver2.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver3.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver4.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver5.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver6.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver7.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver8.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver9.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L))); + })); + } } diff --git a/hedera-node/test-clients/src/main/resources/contract/contracts/Airdrop/Airdrop.bin b/hedera-node/test-clients/src/main/resources/contract/contracts/Airdrop/Airdrop.bin index 629e7fbea0d0..9adbb7256197 100644 --- a/hedera-node/test-clients/src/main/resources/contract/contracts/Airdrop/Airdrop.bin +++ b/hedera-node/test-clients/src/main/resources/contract/contracts/Airdrop/Airdrop.bin @@ -1 +1 @@ -608060405234801561001057600080fd5b50612bbd806100206000396000f3fe60806040526004361061009c5760003560e01c80638a96eca8116100645780638a96eca8146101ac578063913073f9146101dc5780639b23d3d91461020c5780639ef773bf14610249578063ba7ee6e514610279578063e6c6ac4c146102a95761009c565b806315dacbea146100a15780631b79e5f9146100de57806352c0d7d41461010e578063618dc65e1461013e5780637da131bf1461017c575b600080fd5b3480156100ad57600080fd5b506100c860048036038101906100c39190611b1e565b6102e6565b6040516100d59190611ba1565b60405180910390f35b6100f860048036038101906100f39190611be8565b610404565b6040516101059190611ba1565b60405180910390f35b61012860048036038101906101239190611be8565b6104f9565b6040516101359190611ba1565b60405180910390f35b34801561014a57600080fd5b5061016560048036038101906101609190611d95565b61066e565b604051610173929190611e89565b60405180910390f35b61019660048036038101906101919190611f81565b6107ca565b6040516101a39190611ba1565b60405180910390f35b6101c660048036038101906101c1919061203c565b610931565b6040516101d39190611ba1565b60405180910390f35b6101f660048036038101906101f191906120db565b610c28565b6040516102039190611ba1565b60405180910390f35b34801561021857600080fd5b50610233600480360381019061022e9190611b1e565b610eda565b6040516102409190611ba1565b60405180910390f35b610263600480360381019061025e9190612221565b610ff8565b6040516102709190611ba1565b60405180910390f35b610293600480360381019061028e919061239b565b6112f9565b6040516102a09190611ba1565b60405180910390f35b3480156102b557600080fd5b506102d060048036038101906102cb919061240a565b6114ba565b6040516102dd9190611ba1565b60405180910390f35b600080600061016773ffffffffffffffffffffffffffffffffffffffff166315dacbea60e01b8888888860405160240161032394939291906124ff565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161038d9190612580565b6000604051808303816000865af19150503d80600081146103ca576040519150601f19603f3d011682016040523d82523d6000602084013e6103cf565b606091505b5091509150816103e05760156103f5565b808060200190518101906103f491906125d0565b5b60030b92505050949350505050565b600080600167ffffffffffffffff81111561042257610421611c6a565b5b60405190808252806020026020018201604052801561045b57816020015b6104486119aa565b8152602001906001900390816104405790505b5090506104666119aa565b86816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506104a98686866116b5565b816020018190525080826000815181106104c6576104c56125fd565b5b60200260200101819052506104da82611804565b9250601660030b8360070b146104ef57600080fd5b5050949350505050565b600080600167ffffffffffffffff81111561051757610516611c6a565b5b60405190808252806020026020018201604052801561055057816020015b61053d6119aa565b8152602001906001900390816105355790505b50905061055b6119aa565b86816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060006105a0878787611919565b90506000600167ffffffffffffffff8111156105bf576105be611c6a565b5b6040519080825280602002602001820160405280156105f857816020015b6105e56119e1565b8152602001906001900390816105dd5790505b50905081816000815181106106105761060f6125fd565b5b60200260200101819052508083604001819052508284600081518110610639576106386125fd565b5b602002602001018190525061064d84611804565b9450601660030b8560070b1461066257600080fd5b50505050949350505050565b6000606060008061016773ffffffffffffffffffffffffffffffffffffffff1663618dc65e60e01b87876040516024016106a992919061262c565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516107139190612580565b6000604051808303816000865af19150503d8060008114610750576040519150601f19603f3d011682016040523d82523d6000602084013e610755565b606091505b50915091507f4af4780e06fe8cb9df64b0794fa6f01399af979175bb988e35e0e57e594567bc828260405161078b929190612677565b60405180910390a1816107af576015604051806020016040528060008152506107b3565b6016815b8160030b9150809450819550505050509250929050565b6000808451905060008167ffffffffffffffff8111156107ed576107ec611c6a565b5b60405190808252806020026020018201604052801561082657816020015b6108136119aa565b81526020019060019003908161080b5790505b50905060005b828110156109085761083c6119aa565b88828151811061084f5761084e6125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506108cd8883815181106108a4576108a36125fd565b5b60200260200101518884815181106108bf576108be6125fd565b5b6020026020010151886116b5565b8160200181905250808383815181106108e9576108e86125fd565b5b6020026020010181905250508080610900906126d6565b91505061082c565b5061091281611804565b9250601660030b8360070b1461092757600080fd5b5050949350505050565b6000808551905060008167ffffffffffffffff81111561095457610953611c6a565b5b60405190808252806020026020018201604052801561098d57816020015b61097a6119aa565b8152602001906001900390816109725790505b50905060005b82811015610bff576109a36119aa565b8882815181106109b6576109b56125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506109fd611a3a565b88816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000885190506000805b82811015610a68578982610a53919061271e565b91508080610a60906126d6565b915050610a3f565b5080610a739061277e565b836020019060070b908160070b815250506000600183610a9391906127c6565b67ffffffffffffffff811115610aac57610aab611c6a565b5b604051908082528060200260200182016040528015610ae557816020015b610ad2611a3a565b815260200190600190039081610aca5790505b5090508381600081518110610afd57610afc6125fd565b5b602002602001018190525060005b83811015610bbe57610b1b611a3a565b8c8281518110610b2e57610b2d6125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508b816020019060070b908160070b815250508083600184610b8e91906127c6565b81518110610b9f57610b9e6125fd565b5b6020026020010181905250508080610bb6906126d6565b915050610b0b565b5080856020018190525084878781518110610bdc57610bdb6125fd565b5b602002602001018190525050505050508080610bf7906126d6565b915050610993565b50610c0981611804565b9250601660030b8360070b14610c1e57600080fd5b5050949350505050565b60008060018451610c3991906127c6565b90506000600167ffffffffffffffff811115610c5857610c57611c6a565b5b604051908082528060200260200182016040528015610c9157816020015b610c7e6119aa565b815260200190600190039081610c765790505b509050610c9c6119aa565b87816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050610cdc611a3a565b87816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000805b8851811015610d42578782610d2d919061271e565b91508080610d3a906126d6565b915050610d18565b5080610d4d9061277e565b826020019060070b908160070b8152505060008567ffffffffffffffff811115610d7a57610d79611c6a565b5b604051908082528060200260200182016040528015610db357816020015b610da0611a3a565b815260200190600190039081610d985790505b5090508281600081518110610dcb57610dca6125fd565b5b60200260200101819052506000600190505b86811015610e8457610ded611a3a565b8a8281518110610e0057610dff6125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505089816020019060070b908160070b8152505080838381518110610e6557610e646125fd565b5b6020026020010181905250508080610e7c906126d6565b915050610ddd565b508084602001819052508385600081518110610ea357610ea26125fd565b5b6020026020010181905250610eb785611804565b9650601660030b8760070b14610ecc57600080fd5b505050505050949350505050565b600080600061016773ffffffffffffffffffffffffffffffffffffffff16639b23d3d960e01b88888888604051602401610f1794939291906124ff565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610f819190612580565b6000604051808303816000865af19150503d8060008114610fbe576040519150601f19603f3d011682016040523d82523d6000602084013e610fc3565b606091505b509150915081610fd4576015610fe9565b80806020019051810190610fe891906125d0565b5b60030b92505050949350505050565b6000808551885161100991906127c6565b905060008167ffffffffffffffff81111561102757611026611c6a565b5b60405190808252806020026020018201604052801561106057816020015b61104d6119aa565b8152602001906001900390816110455790505b50905060005b8951811015611143576110776119aa565b8c828151811061108a576110896125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506111088b83815181106110df576110de6125fd565b5b60200260200101518b84815181106110fa576110f96125fd565b5b6020026020010151896116b5565b816020018190525080838381518110611124576111236125fd565b5b602002602001018190525050808061113b906126d6565b915050611066565b5060008951905060005b838210156112cb5761115d6119aa565b8c82815181106111705761116f6125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000600167ffffffffffffffff8111156111cc576111cb611c6a565b5b60405190808252806020026020018201604052801561120557816020015b6111f26119e1565b8152602001906001900390816111ea5790505b5090506112618b848151811061121e5761121d6125fd565b5b60200260200101518b8581518110611239576112386125fd565b5b60200260200101518a8681518110611254576112536125fd565b5b6020026020010151611919565b81600081518110611275576112746125fd565b5b60200260200101819052508082604001819052508185858151811061129d5761129c6125fd565b5b602002602001018190525083806112b3906126d6565b945050505080806112c3906126d6565b91505061114d565b506112d582611804565b9350601660030b8460070b146112ea57600080fd5b50505098975050505050505050565b600080825190506000600167ffffffffffffffff81111561131d5761131c611c6a565b5b60405190808252806020026020018201604052801561135657816020015b6113436119aa565b81526020019060019003908161133b5790505b5090506113616119aa565b86816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060008367ffffffffffffffff8111156113b5576113b4611c6a565b5b6040519080825280602002602001820160405280156113ee57816020015b6113db6119e1565b8152602001906001900390816113d35790505b50905060005b848110156114675760006001905061142789898481518110611419576114186125fd565b5b602002602001015183611919565b83838151811061143a576114396125fd565b5b60200260200101819052508080611450906127fa565b91505050808061145f906126d6565b9150506113f4565b508082604001819052508183600081518110611486576114856125fd565b5b602002602001018190525061149a83611804565b9450601660030b8560070b146114af57600080fd5b505050509392505050565b6000808551905060008167ffffffffffffffff8111156114dd576114dc611c6a565b5b60405190808252806020026020018201604052801561151657816020015b6115036119aa565b8152602001906001900390816114fb5790505b50905060005b8281101561168c5761152c6119aa565b88828151811061153f5761153e6125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000600167ffffffffffffffff81111561159b5761159a611c6a565b5b6040519080825280602002602001820160405280156115d457816020015b6115c16119e1565b8152602001906001900390816115b95790505b5090506116308984815181106115ed576115ec6125fd565b5b6020026020010151898581518110611608576116076125fd565b5b6020026020010151898681518110611623576116226125fd565b5b6020026020010151611919565b81600081518110611644576116436125fd565b5b60200260200101819052508082604001819052508184848151811061166c5761166b6125fd565b5b602002602001018190525050508080611684906126d6565b91505061151c565b5061169681611804565b9250601660030b8360070b146116ab57600080fd5b5050949350505050565b60606116bf611a3a565b84816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050826117019061277e565b816020019060070b908160070b8152505061171a611a3a565b84816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083816020019060070b908160070b81525050600267ffffffffffffffff81111561177f5761177e611c6a565b5b6040519080825280602002602001820160405280156117b857816020015b6117a5611a3a565b81526020019060019003908161179d5790505b50925081836000815181106117d0576117cf6125fd565b5b602002602001018190525080836001815181106117f0576117ef6125fd565b5b602002602001018190525050509392505050565b600080600061016773ffffffffffffffffffffffffffffffffffffffff16632f34811960e01b8560405160240161183b9190612b65565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516118a59190612580565b6000604051808303816000865af19150503d80600081146118e2576040519150601f19603f3d011682016040523d82523d6000602084013e6118e7565b606091505b5091509150816118f857601561190d565b8080602001905181019061190c91906125d0565b5b60030b92505050919050565b6119216119e1565b83816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505082816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505081816040019060070b908160070b815250509392505050565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001606081525090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600060070b81526020016000151581525090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600060070b81526020016000151581525090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611ab582611a8a565b9050919050565b611ac581611aaa565b8114611ad057600080fd5b50565b600081359050611ae281611abc565b92915050565b6000819050919050565b611afb81611ae8565b8114611b0657600080fd5b50565b600081359050611b1881611af2565b92915050565b60008060008060808587031215611b3857611b37611a80565b5b6000611b4687828801611ad3565b9450506020611b5787828801611ad3565b9350506040611b6887828801611ad3565b9250506060611b7987828801611b09565b91505092959194509250565b60008160070b9050919050565b611b9b81611b85565b82525050565b6000602082019050611bb66000830184611b92565b92915050565b611bc581611b85565b8114611bd057600080fd5b50565b600081359050611be281611bbc565b92915050565b60008060008060808587031215611c0257611c01611a80565b5b6000611c1087828801611ad3565b9450506020611c2187828801611ad3565b9350506040611c3287828801611ad3565b9250506060611c4387828801611bd3565b91505092959194509250565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b611ca282611c59565b810181811067ffffffffffffffff82111715611cc157611cc0611c6a565b5b80604052505050565b6000611cd4611a76565b9050611ce08282611c99565b919050565b600067ffffffffffffffff821115611d0057611cff611c6a565b5b611d0982611c59565b9050602081019050919050565b82818337600083830152505050565b6000611d38611d3384611ce5565b611cca565b905082815260208101848484011115611d5457611d53611c54565b5b611d5f848285611d16565b509392505050565b600082601f830112611d7c57611d7b611c4f565b5b8135611d8c848260208601611d25565b91505092915050565b60008060408385031215611dac57611dab611a80565b5b6000611dba85828601611ad3565b925050602083013567ffffffffffffffff811115611ddb57611dda611a85565b5b611de785828601611d67565b9150509250929050565b6000819050919050565b611e0481611df1565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015611e44578082015181840152602081019050611e29565b60008484015250505050565b6000611e5b82611e0a565b611e658185611e15565b9350611e75818560208601611e26565b611e7e81611c59565b840191505092915050565b6000604082019050611e9e6000830185611dfb565b8181036020830152611eb08184611e50565b90509392505050565b600067ffffffffffffffff821115611ed457611ed3611c6a565b5b602082029050602081019050919050565b600080fd5b6000611efd611ef884611eb9565b611cca565b90508083825260208201905060208402830185811115611f2057611f1f611ee5565b5b835b81811015611f495780611f358882611ad3565b845260208401935050602081019050611f22565b5050509392505050565b600082601f830112611f6857611f67611c4f565b5b8135611f78848260208601611eea565b91505092915050565b60008060008060808587031215611f9b57611f9a611a80565b5b600085013567ffffffffffffffff811115611fb957611fb8611a85565b5b611fc587828801611f53565b945050602085013567ffffffffffffffff811115611fe657611fe5611a85565b5b611ff287828801611f53565b935050604085013567ffffffffffffffff81111561201357612012611a85565b5b61201f87828801611f53565b925050606061203087828801611bd3565b91505092959194509250565b6000806000806080858703121561205657612055611a80565b5b600085013567ffffffffffffffff81111561207457612073611a85565b5b61208087828801611f53565b945050602061209187828801611ad3565b935050604085013567ffffffffffffffff8111156120b2576120b1611a85565b5b6120be87828801611f53565b92505060606120cf87828801611bd3565b91505092959194509250565b600080600080608085870312156120f5576120f4611a80565b5b600061210387828801611ad3565b945050602061211487828801611ad3565b935050604085013567ffffffffffffffff81111561213557612134611a85565b5b61214187828801611f53565b925050606061215287828801611bd3565b91505092959194509250565b600067ffffffffffffffff82111561217957612178611c6a565b5b602082029050602081019050919050565b600061219d6121988461215e565b611cca565b905080838252602082019050602084028301858111156121c0576121bf611ee5565b5b835b818110156121e957806121d58882611bd3565b8452602084019350506020810190506121c2565b5050509392505050565b600082601f83011261220857612207611c4f565b5b813561221884826020860161218a565b91505092915050565b600080600080600080600080610100898b03121561224257612241611a80565b5b600089013567ffffffffffffffff8111156122605761225f611a85565b5b61226c8b828c01611f53565b985050602089013567ffffffffffffffff81111561228d5761228c611a85565b5b6122998b828c01611f53565b975050604089013567ffffffffffffffff8111156122ba576122b9611a85565b5b6122c68b828c01611f53565b965050606089013567ffffffffffffffff8111156122e7576122e6611a85565b5b6122f38b828c01611f53565b955050608089013567ffffffffffffffff81111561231457612313611a85565b5b6123208b828c01611f53565b94505060a089013567ffffffffffffffff81111561234157612340611a85565b5b61234d8b828c01611f53565b93505060c061235e8b828c01611bd3565b92505060e089013567ffffffffffffffff81111561237f5761237e611a85565b5b61238b8b828c016121f3565b9150509295985092959890939650565b6000806000606084860312156123b4576123b3611a80565b5b60006123c286828701611ad3565b93505060206123d386828701611ad3565b925050604084013567ffffffffffffffff8111156123f4576123f3611a85565b5b61240086828701611f53565b9150509250925092565b6000806000806080858703121561242457612423611a80565b5b600085013567ffffffffffffffff81111561244257612441611a85565b5b61244e87828801611f53565b945050602085013567ffffffffffffffff81111561246f5761246e611a85565b5b61247b87828801611f53565b935050604085013567ffffffffffffffff81111561249c5761249b611a85565b5b6124a887828801611f53565b925050606085013567ffffffffffffffff8111156124c9576124c8611a85565b5b6124d5878288016121f3565b91505092959194509250565b6124ea81611aaa565b82525050565b6124f981611ae8565b82525050565b600060808201905061251460008301876124e1565b61252160208301866124e1565b61252e60408301856124e1565b61253b60608301846124f0565b95945050505050565b600081905092915050565b600061255a82611e0a565b6125648185612544565b9350612574818560208601611e26565b80840191505092915050565b600061258c828461254f565b915081905092915050565b60008160030b9050919050565b6125ad81612597565b81146125b857600080fd5b50565b6000815190506125ca816125a4565b92915050565b6000602082840312156125e6576125e5611a80565b5b60006125f4848285016125bb565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060408201905061264160008301856124e1565b81810360208301526126538184611e50565b90509392505050565b60008115159050919050565b6126718161265c565b82525050565b600060408201905061268c6000830185612668565b818103602083015261269e8184611e50565b90509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006126e182611ae8565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612713576127126126a7565b5b600182019050919050565b600061272982611b85565b915061273483611b85565b925082820190507fffffffffffffffffffffffffffffffffffffffffffffffff80000000000000008112677fffffffffffffff82131715612778576127776126a7565b5b92915050565b600061278982611b85565b91507fffffffffffffffffffffffffffffffffffffffffffffffff800000000000000082036127bb576127ba6126a7565b5b816000039050919050565b60006127d182611ae8565b91506127dc83611ae8565b92508282019050808211156127f4576127f36126a7565b5b92915050565b600061280582611b85565b9150677fffffffffffffff820361281f5761281e6126a7565b5b600182019050919050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61285f81611aaa565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61289a81611b85565b82525050565b6128a98161265c565b82525050565b6060820160008201516128c56000850182612856565b5060208201516128d86020850182612891565b5060408201516128eb60408501826128a0565b50505050565b60006128fd83836128af565b60608301905092915050565b6000602082019050919050565b600061292182612865565b61292b8185612870565b935061293683612881565b8060005b8381101561296757815161294e88826128f1565b975061295983612909565b92505060018101905061293a565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6080820160008201516129b66000850182612856565b5060208201516129c96020850182612856565b5060408201516129dc6040850182612891565b5060608201516129ef60608501826128a0565b50505050565b6000612a0183836129a0565b60808301905092915050565b6000602082019050919050565b6000612a2582612974565b612a2f818561297f565b9350612a3a83612990565b8060005b83811015612a6b578151612a5288826129f5565b9750612a5d83612a0d565b925050600181019050612a3e565b5085935050505092915050565b6000606083016000830151612a906000860182612856565b5060208301518482036020860152612aa88282612916565b91505060408301518482036040860152612ac28282612a1a565b9150508091505092915050565b6000612adb8383612a78565b905092915050565b6000602082019050919050565b6000612afb8261282a565b612b058185612835565b935083602082028501612b1785612846565b8060005b85811015612b535784840389528151612b348582612acf565b9450612b3f83612ae3565b925060208a01995050600181019050612b1b565b50829750879550505050505092915050565b60006020820190508181036000830152612b7f8184612af0565b90509291505056fea264697066735822122086192d7645d5df16eaa64587e1f5eeb32a603b6a78dbbf0e02cac6e8763dffa264736f6c63430008120033 \ No newline at end of file +608060405234801561001057600080fd5b50612bbd806100206000396000f3fe60806040526004361061009c5760003560e01c80638a96eca8116100645780638a96eca8146101ac578063913073f9146101dc5780639b23d3d91461020c5780639ef773bf14610249578063ba7ee6e514610279578063e6c6ac4c146102a95761009c565b806315dacbea146100a15780631b79e5f9146100de57806352c0d7d41461010e578063618dc65e1461013e5780637da131bf1461017c575b600080fd5b3480156100ad57600080fd5b506100c860048036038101906100c39190611b1e565b6102e6565b6040516100d59190611ba1565b60405180910390f35b6100f860048036038101906100f39190611be8565b610404565b6040516101059190611ba1565b60405180910390f35b61012860048036038101906101239190611be8565b6104f9565b6040516101359190611ba1565b60405180910390f35b34801561014a57600080fd5b5061016560048036038101906101609190611d95565b61066e565b604051610173929190611e89565b60405180910390f35b61019660048036038101906101919190611f81565b6107ca565b6040516101a39190611ba1565b60405180910390f35b6101c660048036038101906101c1919061203c565b610931565b6040516101d39190611ba1565b60405180910390f35b6101f660048036038101906101f191906120db565b610c28565b6040516102039190611ba1565b60405180910390f35b34801561021857600080fd5b50610233600480360381019061022e9190611b1e565b610eda565b6040516102409190611ba1565b60405180910390f35b610263600480360381019061025e9190612221565b610ff8565b6040516102709190611ba1565b60405180910390f35b610293600480360381019061028e919061239b565b6112f9565b6040516102a09190611ba1565b60405180910390f35b3480156102b557600080fd5b506102d060048036038101906102cb919061240a565b6114ba565b6040516102dd9190611ba1565b60405180910390f35b600080600061016773ffffffffffffffffffffffffffffffffffffffff166315dacbea60e01b8888888860405160240161032394939291906124ff565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161038d9190612580565b6000604051808303816000865af19150503d80600081146103ca576040519150601f19603f3d011682016040523d82523d6000602084013e6103cf565b606091505b5091509150816103e05760156103f5565b808060200190518101906103f491906125d0565b5b60030b92505050949350505050565b600080600167ffffffffffffffff81111561042257610421611c6a565b5b60405190808252806020026020018201604052801561045b57816020015b6104486119aa565b8152602001906001900390816104405790505b5090506104666119aa565b86816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506104a98686866116b5565b816020018190525080826000815181106104c6576104c56125fd565b5b60200260200101819052506104da82611804565b9250601660030b8360070b146104ef57600080fd5b5050949350505050565b600080600167ffffffffffffffff81111561051757610516611c6a565b5b60405190808252806020026020018201604052801561055057816020015b61053d6119aa565b8152602001906001900390816105355790505b50905061055b6119aa565b86816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060006105a0878787611919565b90506000600167ffffffffffffffff8111156105bf576105be611c6a565b5b6040519080825280602002602001820160405280156105f857816020015b6105e56119e1565b8152602001906001900390816105dd5790505b50905081816000815181106106105761060f6125fd565b5b60200260200101819052508083604001819052508284600081518110610639576106386125fd565b5b602002602001018190525061064d84611804565b9450601660030b8560070b1461066257600080fd5b50505050949350505050565b6000606060008061016773ffffffffffffffffffffffffffffffffffffffff1663618dc65e60e01b87876040516024016106a992919061262c565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516107139190612580565b6000604051808303816000865af19150503d8060008114610750576040519150601f19603f3d011682016040523d82523d6000602084013e610755565b606091505b50915091507f4af4780e06fe8cb9df64b0794fa6f01399af979175bb988e35e0e57e594567bc828260405161078b929190612677565b60405180910390a1816107af576015604051806020016040528060008152506107b3565b6016815b8160030b9150809450819550505050509250929050565b6000808451905060008167ffffffffffffffff8111156107ed576107ec611c6a565b5b60405190808252806020026020018201604052801561082657816020015b6108136119aa565b81526020019060019003908161080b5790505b50905060005b828110156109085761083c6119aa565b88828151811061084f5761084e6125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506108cd8883815181106108a4576108a36125fd565b5b60200260200101518884815181106108bf576108be6125fd565b5b6020026020010151886116b5565b8160200181905250808383815181106108e9576108e86125fd565b5b6020026020010181905250508080610900906126d6565b91505061082c565b5061091281611804565b9250601660030b8360070b1461092757600080fd5b5050949350505050565b6000808551905060008167ffffffffffffffff81111561095457610953611c6a565b5b60405190808252806020026020018201604052801561098d57816020015b61097a6119aa565b8152602001906001900390816109725790505b50905060005b82811015610bff576109a36119aa565b8882815181106109b6576109b56125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506109fd611a3a565b88816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000885190506000805b82811015610a68578982610a53919061271e565b91508080610a60906126d6565b915050610a3f565b5080610a739061277e565b836020019060070b908160070b815250506000600183610a9391906127c6565b67ffffffffffffffff811115610aac57610aab611c6a565b5b604051908082528060200260200182016040528015610ae557816020015b610ad2611a3a565b815260200190600190039081610aca5790505b5090508381600081518110610afd57610afc6125fd565b5b602002602001018190525060005b83811015610bbe57610b1b611a3a565b8c8281518110610b2e57610b2d6125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508b816020019060070b908160070b815250508083600184610b8e91906127c6565b81518110610b9f57610b9e6125fd565b5b6020026020010181905250508080610bb6906126d6565b915050610b0b565b5080856020018190525084878781518110610bdc57610bdb6125fd565b5b602002602001018190525050505050508080610bf7906126d6565b915050610993565b50610c0981611804565b9250601660030b8360070b14610c1e57600080fd5b5050949350505050565b60008060018451610c3991906127c6565b90506000600167ffffffffffffffff811115610c5857610c57611c6a565b5b604051908082528060200260200182016040528015610c9157816020015b610c7e6119aa565b815260200190600190039081610c765790505b509050610c9c6119aa565b87816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050610cdc611a3a565b87816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000805b8851811015610d42578782610d2d919061271e565b91508080610d3a906126d6565b915050610d18565b5080610d4d9061277e565b826020019060070b908160070b8152505060008567ffffffffffffffff811115610d7a57610d79611c6a565b5b604051908082528060200260200182016040528015610db357816020015b610da0611a3a565b815260200190600190039081610d985790505b5090508281600081518110610dcb57610dca6125fd565b5b60200260200101819052506000600190505b86811015610e8457610ded611a3a565b8a8281518110610e0057610dff6125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505089816020019060070b908160070b8152505080838381518110610e6557610e646125fd565b5b6020026020010181905250508080610e7c906126d6565b915050610ddd565b508084602001819052508385600081518110610ea357610ea26125fd565b5b6020026020010181905250610eb785611804565b9650601660030b8760070b14610ecc57600080fd5b505050505050949350505050565b600080600061016773ffffffffffffffffffffffffffffffffffffffff16639b23d3d960e01b88888888604051602401610f1794939291906124ff565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610f819190612580565b6000604051808303816000865af19150503d8060008114610fbe576040519150601f19603f3d011682016040523d82523d6000602084013e610fc3565b606091505b509150915081610fd4576015610fe9565b80806020019051810190610fe891906125d0565b5b60030b92505050949350505050565b6000808551885161100991906127c6565b905060008167ffffffffffffffff81111561102757611026611c6a565b5b60405190808252806020026020018201604052801561106057816020015b61104d6119aa565b8152602001906001900390816110455790505b50905060005b8951811015611143576110776119aa565b8c828151811061108a576110896125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506111088b83815181106110df576110de6125fd565b5b60200260200101518b84815181106110fa576110f96125fd565b5b6020026020010151896116b5565b816020018190525080838381518110611124576111236125fd565b5b602002602001018190525050808061113b906126d6565b915050611066565b5060008951905060005b838210156112cb5761115d6119aa565b8c82815181106111705761116f6125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000600167ffffffffffffffff8111156111cc576111cb611c6a565b5b60405190808252806020026020018201604052801561120557816020015b6111f26119e1565b8152602001906001900390816111ea5790505b5090506112618b848151811061121e5761121d6125fd565b5b60200260200101518b8581518110611239576112386125fd565b5b60200260200101518a8681518110611254576112536125fd565b5b6020026020010151611919565b81600081518110611275576112746125fd565b5b60200260200101819052508082604001819052508185858151811061129d5761129c6125fd565b5b602002602001018190525083806112b3906126d6565b945050505080806112c3906126d6565b91505061114d565b506112d582611804565b9350601660030b8460070b146112ea57600080fd5b50505098975050505050505050565b600080825190506000600167ffffffffffffffff81111561131d5761131c611c6a565b5b60405190808252806020026020018201604052801561135657816020015b6113436119aa565b81526020019060019003908161133b5790505b5090506113616119aa565b86816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060008367ffffffffffffffff8111156113b5576113b4611c6a565b5b6040519080825280602002602001820160405280156113ee57816020015b6113db6119e1565b8152602001906001900390816113d35790505b50905060006001905060005b858110156114665761142789898381518110611419576114186125fd565b5b602002602001015184611919565b83828151811061143a576114396125fd565b5b60200260200101819052508180611450906127fa565b925050808061145e906126d6565b9150506113fa565b508183604001819052508284600081518110611485576114846125fd565b5b602002602001018190525061149984611804565b9550601660030b8660070b146114ae57600080fd5b50505050509392505050565b6000808551905060008167ffffffffffffffff8111156114dd576114dc611c6a565b5b60405190808252806020026020018201604052801561151657816020015b6115036119aa565b8152602001906001900390816114fb5790505b50905060005b8281101561168c5761152c6119aa565b88828151811061153f5761153e6125fd565b5b6020026020010151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000600167ffffffffffffffff81111561159b5761159a611c6a565b5b6040519080825280602002602001820160405280156115d457816020015b6115c16119e1565b8152602001906001900390816115b95790505b5090506116308984815181106115ed576115ec6125fd565b5b6020026020010151898581518110611608576116076125fd565b5b6020026020010151898681518110611623576116226125fd565b5b6020026020010151611919565b81600081518110611644576116436125fd565b5b60200260200101819052508082604001819052508184848151811061166c5761166b6125fd565b5b602002602001018190525050508080611684906126d6565b91505061151c565b5061169681611804565b9250601660030b8360070b146116ab57600080fd5b5050949350505050565b60606116bf611a3a565b84816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050826117019061277e565b816020019060070b908160070b8152505061171a611a3a565b84816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083816020019060070b908160070b81525050600267ffffffffffffffff81111561177f5761177e611c6a565b5b6040519080825280602002602001820160405280156117b857816020015b6117a5611a3a565b81526020019060019003908161179d5790505b50925081836000815181106117d0576117cf6125fd565b5b602002602001018190525080836001815181106117f0576117ef6125fd565b5b602002602001018190525050509392505050565b600080600061016773ffffffffffffffffffffffffffffffffffffffff16632f34811960e01b8560405160240161183b9190612b65565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516118a59190612580565b6000604051808303816000865af19150503d80600081146118e2576040519150601f19603f3d011682016040523d82523d6000602084013e6118e7565b606091505b5091509150816118f857601561190d565b8080602001905181019061190c91906125d0565b5b60030b92505050919050565b6119216119e1565b83816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505082816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505081816040019060070b908160070b815250509392505050565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001606081525090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600060070b81526020016000151581525090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600060070b81526020016000151581525090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611ab582611a8a565b9050919050565b611ac581611aaa565b8114611ad057600080fd5b50565b600081359050611ae281611abc565b92915050565b6000819050919050565b611afb81611ae8565b8114611b0657600080fd5b50565b600081359050611b1881611af2565b92915050565b60008060008060808587031215611b3857611b37611a80565b5b6000611b4687828801611ad3565b9450506020611b5787828801611ad3565b9350506040611b6887828801611ad3565b9250506060611b7987828801611b09565b91505092959194509250565b60008160070b9050919050565b611b9b81611b85565b82525050565b6000602082019050611bb66000830184611b92565b92915050565b611bc581611b85565b8114611bd057600080fd5b50565b600081359050611be281611bbc565b92915050565b60008060008060808587031215611c0257611c01611a80565b5b6000611c1087828801611ad3565b9450506020611c2187828801611ad3565b9350506040611c3287828801611ad3565b9250506060611c4387828801611bd3565b91505092959194509250565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b611ca282611c59565b810181811067ffffffffffffffff82111715611cc157611cc0611c6a565b5b80604052505050565b6000611cd4611a76565b9050611ce08282611c99565b919050565b600067ffffffffffffffff821115611d0057611cff611c6a565b5b611d0982611c59565b9050602081019050919050565b82818337600083830152505050565b6000611d38611d3384611ce5565b611cca565b905082815260208101848484011115611d5457611d53611c54565b5b611d5f848285611d16565b509392505050565b600082601f830112611d7c57611d7b611c4f565b5b8135611d8c848260208601611d25565b91505092915050565b60008060408385031215611dac57611dab611a80565b5b6000611dba85828601611ad3565b925050602083013567ffffffffffffffff811115611ddb57611dda611a85565b5b611de785828601611d67565b9150509250929050565b6000819050919050565b611e0481611df1565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015611e44578082015181840152602081019050611e29565b60008484015250505050565b6000611e5b82611e0a565b611e658185611e15565b9350611e75818560208601611e26565b611e7e81611c59565b840191505092915050565b6000604082019050611e9e6000830185611dfb565b8181036020830152611eb08184611e50565b90509392505050565b600067ffffffffffffffff821115611ed457611ed3611c6a565b5b602082029050602081019050919050565b600080fd5b6000611efd611ef884611eb9565b611cca565b90508083825260208201905060208402830185811115611f2057611f1f611ee5565b5b835b81811015611f495780611f358882611ad3565b845260208401935050602081019050611f22565b5050509392505050565b600082601f830112611f6857611f67611c4f565b5b8135611f78848260208601611eea565b91505092915050565b60008060008060808587031215611f9b57611f9a611a80565b5b600085013567ffffffffffffffff811115611fb957611fb8611a85565b5b611fc587828801611f53565b945050602085013567ffffffffffffffff811115611fe657611fe5611a85565b5b611ff287828801611f53565b935050604085013567ffffffffffffffff81111561201357612012611a85565b5b61201f87828801611f53565b925050606061203087828801611bd3565b91505092959194509250565b6000806000806080858703121561205657612055611a80565b5b600085013567ffffffffffffffff81111561207457612073611a85565b5b61208087828801611f53565b945050602061209187828801611ad3565b935050604085013567ffffffffffffffff8111156120b2576120b1611a85565b5b6120be87828801611f53565b92505060606120cf87828801611bd3565b91505092959194509250565b600080600080608085870312156120f5576120f4611a80565b5b600061210387828801611ad3565b945050602061211487828801611ad3565b935050604085013567ffffffffffffffff81111561213557612134611a85565b5b61214187828801611f53565b925050606061215287828801611bd3565b91505092959194509250565b600067ffffffffffffffff82111561217957612178611c6a565b5b602082029050602081019050919050565b600061219d6121988461215e565b611cca565b905080838252602082019050602084028301858111156121c0576121bf611ee5565b5b835b818110156121e957806121d58882611bd3565b8452602084019350506020810190506121c2565b5050509392505050565b600082601f83011261220857612207611c4f565b5b813561221884826020860161218a565b91505092915050565b600080600080600080600080610100898b03121561224257612241611a80565b5b600089013567ffffffffffffffff8111156122605761225f611a85565b5b61226c8b828c01611f53565b985050602089013567ffffffffffffffff81111561228d5761228c611a85565b5b6122998b828c01611f53565b975050604089013567ffffffffffffffff8111156122ba576122b9611a85565b5b6122c68b828c01611f53565b965050606089013567ffffffffffffffff8111156122e7576122e6611a85565b5b6122f38b828c01611f53565b955050608089013567ffffffffffffffff81111561231457612313611a85565b5b6123208b828c01611f53565b94505060a089013567ffffffffffffffff81111561234157612340611a85565b5b61234d8b828c01611f53565b93505060c061235e8b828c01611bd3565b92505060e089013567ffffffffffffffff81111561237f5761237e611a85565b5b61238b8b828c016121f3565b9150509295985092959890939650565b6000806000606084860312156123b4576123b3611a80565b5b60006123c286828701611ad3565b93505060206123d386828701611ad3565b925050604084013567ffffffffffffffff8111156123f4576123f3611a85565b5b61240086828701611f53565b9150509250925092565b6000806000806080858703121561242457612423611a80565b5b600085013567ffffffffffffffff81111561244257612441611a85565b5b61244e87828801611f53565b945050602085013567ffffffffffffffff81111561246f5761246e611a85565b5b61247b87828801611f53565b935050604085013567ffffffffffffffff81111561249c5761249b611a85565b5b6124a887828801611f53565b925050606085013567ffffffffffffffff8111156124c9576124c8611a85565b5b6124d5878288016121f3565b91505092959194509250565b6124ea81611aaa565b82525050565b6124f981611ae8565b82525050565b600060808201905061251460008301876124e1565b61252160208301866124e1565b61252e60408301856124e1565b61253b60608301846124f0565b95945050505050565b600081905092915050565b600061255a82611e0a565b6125648185612544565b9350612574818560208601611e26565b80840191505092915050565b600061258c828461254f565b915081905092915050565b60008160030b9050919050565b6125ad81612597565b81146125b857600080fd5b50565b6000815190506125ca816125a4565b92915050565b6000602082840312156125e6576125e5611a80565b5b60006125f4848285016125bb565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060408201905061264160008301856124e1565b81810360208301526126538184611e50565b90509392505050565b60008115159050919050565b6126718161265c565b82525050565b600060408201905061268c6000830185612668565b818103602083015261269e8184611e50565b90509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006126e182611ae8565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612713576127126126a7565b5b600182019050919050565b600061272982611b85565b915061273483611b85565b925082820190507fffffffffffffffffffffffffffffffffffffffffffffffff80000000000000008112677fffffffffffffff82131715612778576127776126a7565b5b92915050565b600061278982611b85565b91507fffffffffffffffffffffffffffffffffffffffffffffffff800000000000000082036127bb576127ba6126a7565b5b816000039050919050565b60006127d182611ae8565b91506127dc83611ae8565b92508282019050808211156127f4576127f36126a7565b5b92915050565b600061280582611b85565b9150677fffffffffffffff820361281f5761281e6126a7565b5b600182019050919050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61285f81611aaa565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61289a81611b85565b82525050565b6128a98161265c565b82525050565b6060820160008201516128c56000850182612856565b5060208201516128d86020850182612891565b5060408201516128eb60408501826128a0565b50505050565b60006128fd83836128af565b60608301905092915050565b6000602082019050919050565b600061292182612865565b61292b8185612870565b935061293683612881565b8060005b8381101561296757815161294e88826128f1565b975061295983612909565b92505060018101905061293a565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6080820160008201516129b66000850182612856565b5060208201516129c96020850182612856565b5060408201516129dc6040850182612891565b5060608201516129ef60608501826128a0565b50505050565b6000612a0183836129a0565b60808301905092915050565b6000602082019050919050565b6000612a2582612974565b612a2f818561297f565b9350612a3a83612990565b8060005b83811015612a6b578151612a5288826129f5565b9750612a5d83612a0d565b925050600181019050612a3e565b5085935050505092915050565b6000606083016000830151612a906000860182612856565b5060208301518482036020860152612aa88282612916565b91505060408301518482036040860152612ac28282612a1a565b9150508091505092915050565b6000612adb8383612a78565b905092915050565b6000602082019050919050565b6000612afb8261282a565b612b058185612835565b935083602082028501612b1785612846565b8060005b85811015612b535784840389528151612b348582612acf565b9450612b3f83612ae3565b925060208a01995050600181019050612b1b565b50829750879550505050505092915050565b60006020820190508181036000830152612b7f8184612af0565b90509291505056fea2646970667358221220f5c5743bc121bb9c07222745c48732c36fbf4509eeec4e857ec0af026da1eb3564736f6c63430008120033 \ No newline at end of file diff --git a/hedera-node/test-clients/src/main/resources/contract/contracts/Airdrop/Airdrop.sol b/hedera-node/test-clients/src/main/resources/contract/contracts/Airdrop/Airdrop.sol index cf8dc6bd294a..9592c38f40c2 100644 --- a/hedera-node/test-clients/src/main/resources/contract/contracts/Airdrop/Airdrop.sol +++ b/hedera-node/test-clients/src/main/resources/contract/contracts/Airdrop/Airdrop.sol @@ -108,8 +108,8 @@ contract Airdrop is HederaTokenService { IHederaTokenService.TokenTransferList memory airdrop; airdrop.token = token; IHederaTokenService.NftTransfer[] memory nftTransfers = new IHederaTokenService.NftTransfer[](length); + int64 serial = 1; for (uint i = 0; i < length; i++) { - int64 serial = 1; nftTransfers[i] = prepareNftTransfer(sender, receivers[i], serial); serial++; } From e5fa1c6d00af746964160ebc4c8bde52bda442e4 Mon Sep 17 00:00:00 2001 From: Stanimir Stoyanov Date: Fri, 17 Jan 2025 10:25:07 +0200 Subject: [PATCH 2/3] nit: typo Signed-off-by: Stanimir Stoyanov --- .../contract/precompile/airdrops/AirdropSystemContractTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/airdrops/AirdropSystemContractTest.java b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/airdrops/AirdropSystemContractTest.java index 4aea7c61393f..24762058feeb 100644 --- a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/airdrops/AirdropSystemContractTest.java +++ b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/airdrops/AirdropSystemContractTest.java @@ -532,7 +532,7 @@ public Stream distributeNfts( @HapiTest @Order(13) - @DisplayName("Cannon Distribute 11 NFTs to multiple accounts") + @DisplayName("Cannot Distribute 11 NFTs to multiple accounts") public Stream distributeNftsOutOfBound( @NonNull @NonFungibleToken(numPreMints = 11) final SpecNonFungibleToken nft, @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver1, From f3c676ce4703397fa2a0b8f0459093a088d5b412 Mon Sep 17 00:00:00 2001 From: Stanimir Stoyanov Date: Wed, 22 Jan 2025 12:46:40 +0200 Subject: [PATCH 3/3] fix: add tests to address PR comments Signed-off-by: Stanimir Stoyanov --- .../hts/airdrops/TokenAirdropDecoderTest.java | 46 +++++++++++++++--- .../airdrops/AirdropSystemContractTest.java | 47 +++++++++++++++++++ 2 files changed, 87 insertions(+), 6 deletions(-) diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/airdrops/TokenAirdropDecoderTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/airdrops/TokenAirdropDecoderTest.java index 1d648a9d2c40..ab6c9deea508 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/airdrops/TokenAirdropDecoderTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/airdrops/TokenAirdropDecoderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-2025 Hedera Hashgraph, LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -92,11 +92,14 @@ public class TokenAirdropDecoderTest { private final TokenAirdropTransactionBody nftAirdrop = TokenAirdropTransactionBody.newBuilder() .tokenTransfers(TokenTransferList.newBuilder() .token(NON_FUNGIBLE_TOKEN_ID) - .nftTransfers(NftTransfer.newBuilder() - .senderAccountID(SENDER_ID) - .receiverAccountID(OWNER_ID) - .serialNumber(1) - .build()) + .nftTransfers(nftTransfer(1)) + .build()) + .build(); + + private final TokenAirdropTransactionBody nftAirdrops = TokenAirdropTransactionBody.newBuilder() + .tokenTransfers(TokenTransferList.newBuilder() + .token(NON_FUNGIBLE_TOKEN_ID) + .nftTransfers(nftTransfer(1), nftTransfer(2), nftTransfer(3)) .build()) .build(); @@ -273,6 +276,29 @@ void tokenAirdropDecoderWorksForNFT() { assertEquals(nftAirdrop, body.tokenAirdrop()); } + @Test + void tokenAirdropDecoderWorksForMultipleNFTs() { + final var tuple = new Tuple[] { + Tuple.of(NON_FUNGIBLE_TOKEN_HEADLONG_ADDRESS, new Tuple[] {}, new Tuple[] { + Tuple.of(asHeadlongAddress(SENDER_ID.accountNum()), OWNER_ACCOUNT_AS_ADDRESS, 1L, false), + Tuple.of(asHeadlongAddress(SENDER_ID.accountNum()), OWNER_ACCOUNT_AS_ADDRESS, 2L, false), + Tuple.of(asHeadlongAddress(SENDER_ID.accountNum()), OWNER_ACCOUNT_AS_ADDRESS, 3L, false) + }) + }; + final var encoded = Bytes.wrapByteBuffer(TOKEN_AIRDROP.encodeCall(Tuple.singleton(tuple))); + given(attempt.inputBytes()).willReturn(encoded.toArrayUnsafe()); + given(attempt.configuration()).willReturn(configuration); + given(attempt.addressIdConverter()).willReturn(addressIdConverter); + given(configuration.getConfigData(LedgerConfig.class)).willReturn(ledgerConfig); + given(ledgerConfig.tokenTransfersMaxLen()).willReturn(10); + given(ledgerConfig.nftTransfersMaxLen()).willReturn(10); + final var body = subject.decodeAirdrop(attempt); + assertNotNull(body); + assertNotNull(body.tokenAirdrop()); + assertNotNull(body.tokenAirdrop().tokenTransfers()); + assertEquals(nftAirdrops, body.tokenAirdrop()); + } + @Test void tokenAirdropDecoderForNFTFailsIfNftExceedLimits() { final var tuple = new Tuple[] { @@ -301,4 +327,12 @@ void tokenAirdropDecoderForNFTFailsIfNftExceedLimits() { .isThrownBy(() -> subject.decodeAirdrop(attempt)) .withMessage(TOKEN_REFERENCE_LIST_SIZE_LIMIT_EXCEEDED.protoName()); } + + private NftTransfer nftTransfer(final long serial) { + return NftTransfer.newBuilder() + .senderAccountID(SENDER_ID) + .receiverAccountID(OWNER_ID) + .serialNumber(serial) + .build(); + } } diff --git a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/airdrops/AirdropSystemContractTest.java b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/airdrops/AirdropSystemContractTest.java index 24762058feeb..4d379d8ac13a 100644 --- a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/airdrops/AirdropSystemContractTest.java +++ b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/airdrops/AirdropSystemContractTest.java @@ -18,6 +18,7 @@ import static com.hedera.services.bdd.junit.TestTags.SMART_CONTRACT; import static com.hedera.services.bdd.spec.HapiSpec.hapiTest; +import static com.hedera.services.bdd.spec.transactions.TxnVerbs.burnToken; import static com.hedera.services.bdd.spec.utilops.CustomSpecAssert.allRunFor; import static com.hedera.services.bdd.spec.utilops.UtilVerbs.withOpContext; import static com.hedera.services.bdd.suites.contract.precompile.airdrops.SystemContractAirdropHelper.prepareAccountAddresses; @@ -42,6 +43,7 @@ import com.hedera.services.bdd.spec.dsl.entities.SpecFungibleToken; import com.hedera.services.bdd.spec.dsl.entities.SpecNonFungibleToken; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.List; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; @@ -596,4 +598,49 @@ public Stream distributeNftsOutOfBound( receiver9.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L))); })); } + + @HapiTest + @Order(14) + @DisplayName("Cannot distribute NFTs to multiple accounts when some of the NFTs do not exist") + public Stream failToDistributeNfts( + @NonNull @NonFungibleToken(numPreMints = 6) final SpecNonFungibleToken nft, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver1, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver2, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver3, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver4, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver5, + @NonNull @Account(maxAutoAssociations = -1) final SpecAccount receiver6) { + return hapiTest(withOpContext((spec, opLog) -> { + allRunFor( + spec, + sender.associateTokens(nft), + // We have six pre minted serials + // Burning some of them to make them invalid + burnToken(nft.name(), List.of(3L, 4L)), + receiver1.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver2.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver3.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver4.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver5.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver6.getBalance().andAssert(balance -> balance.hasTokenBalance(nft.name(), 0L)), + receiver1.getInfo(), + receiver1.getInfo(), + receiver3.getInfo(), + receiver4.getInfo(), + receiver5.getInfo(), + receiver6.getInfo(), + nft.treasury().transferNFTsTo(sender, nft, 1L, 2L, 5L, 6L)); + allRunFor( + spec, + airdropContract + .call( + "nftAirdropDistribute", + nft, + sender, + prepareAccountAddresses( + spec, receiver1, receiver2, receiver3, receiver4, receiver5, receiver6)) + .gas(1500000) + .andAssert(txn -> txn.hasKnownStatuses(CONTRACT_REVERT_EXECUTED, INVALID_NFT_ID))); + })); + } }