Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.tron.core.actuator;

import com.google.protobuf.GeneratedMessageV3;
import org.tron.common.math.StrictMathWrapper;
import org.tron.protos.Protocol.Transaction.Contract.ContractType;

public abstract class AbstractExchangeActuator extends AbstractActuator {

public AbstractExchangeActuator(ContractType type, Class<? extends GeneratedMessageV3> clazz) {
super(type, clazz);
}

protected boolean allowHarden() {
return chainBaseManager.getDynamicPropertiesStore().allowHardenExchangeCalculation();
}

public long subtractExact(long x, long y) {
return allowHarden() ? StrictMathWrapper.subtractExact(x, y) : x - y;
}

public long addExact(long x, long y) {
return allowHarden() ? StrictMathWrapper.addExact(x, y) : x + y;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import org.tron.protos.contract.ExchangeContract.ExchangeCreateContract;

@Slf4j(topic = "actuator")
public class ExchangeCreateActuator extends AbstractActuator {
public class ExchangeCreateActuator extends AbstractExchangeActuator {

public ExchangeCreateActuator() {
super(ContractType.ExchangeCreateContract, ExchangeCreateContract.class);
Expand Down Expand Up @@ -57,25 +57,25 @@ public boolean execute(Object object) throws ContractExeException {
long firstTokenBalance = exchangeCreateContract.getFirstTokenBalance();
long secondTokenBalance = exchangeCreateContract.getSecondTokenBalance();

long newBalance = accountCapsule.getBalance() - fee;
long newBalance = subtractExact(accountCapsule.getBalance(), fee);

accountCapsule.setBalance(newBalance);

if (Arrays.equals(firstTokenID, TRX_SYMBOL_BYTES)) {
accountCapsule.setBalance(newBalance - firstTokenBalance);
accountCapsule.setBalance(subtractExact(newBalance, firstTokenBalance));
} else {
accountCapsule
.reduceAssetAmountV2(firstTokenID, firstTokenBalance, dynamicStore, assetIssueStore);
}

if (Arrays.equals(secondTokenID, TRX_SYMBOL_BYTES)) {
accountCapsule.setBalance(newBalance - secondTokenBalance);
accountCapsule.setBalance(subtractExact(newBalance, secondTokenBalance));
} else {
accountCapsule
.reduceAssetAmountV2(secondTokenID, secondTokenBalance, dynamicStore, assetIssueStore);
}

long id = dynamicStore.getLatestExchangeNum() + 1;
long id = addExact(dynamicStore.getLatestExchangeNum(), 1);
long now = dynamicStore.getLatestBlockHeaderTimestamp();
if (dynamicStore.getAllowSameTokenName() == 0) {
//save to old asset store
Expand Down Expand Up @@ -124,7 +124,8 @@ public boolean execute(Object object) throws ContractExeException {
}
ret.setExchangeId(id);
ret.setStatus(fee, code.SUCESS);
} catch (BalanceInsufficientException | InvalidProtocolBufferException e) {
} catch (BalanceInsufficientException | InvalidProtocolBufferException
| ArithmeticException e) {
logger.debug(e.getMessage(), e);
ret.setStatus(fee, code.FAILED);
throw new ContractExeException(e.getMessage());
Expand All @@ -134,6 +135,14 @@ public boolean execute(Object object) throws ContractExeException {

@Override
public boolean validate() throws ContractValidateException {
try {
return doValidate();
} catch (ArithmeticException e) {
throw new ContractValidateException(e.getMessage());
}
}

private boolean doValidate() throws ContractValidateException {
if (this.any == null) {
throw new ContractValidateException(ActuatorConstant.CONTRACT_NOT_EXIST);
}
Expand Down Expand Up @@ -199,7 +208,7 @@ public boolean validate() throws ContractValidateException {
}

if (Arrays.equals(firstTokenID, TRX_SYMBOL_BYTES)) {
if (accountCapsule.getBalance() < (firstTokenBalance + calcFee())) {
if (accountCapsule.getBalance() < addExact(firstTokenBalance, calcFee())) {
throw new ContractValidateException("balance is not enough");
}
} else {
Expand All @@ -209,7 +218,7 @@ public boolean validate() throws ContractValidateException {
}

if (Arrays.equals(secondTokenID, TRX_SYMBOL_BYTES)) {
if (accountCapsule.getBalance() < (secondTokenBalance + calcFee())) {
if (accountCapsule.getBalance() < addExact(secondTokenBalance, calcFee())) {
throw new ContractValidateException("balance is not enough");
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@
import org.tron.core.store.DynamicPropertiesStore;
import org.tron.core.store.ExchangeStore;
import org.tron.core.store.ExchangeV2Store;
import org.tron.core.utils.TransactionUtil;
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
import org.tron.protos.Protocol.Transaction.Result.code;
import org.tron.protos.contract.ExchangeContract.ExchangeInjectContract;

@Slf4j(topic = "actuator")
public class ExchangeInjectActuator extends AbstractActuator {
public class ExchangeInjectActuator extends AbstractExchangeActuator {

public ExchangeInjectActuator() {
super(ContractType.ExchangeInjectContract, ExchangeInjectContract.class);
Expand All @@ -56,8 +55,8 @@ public boolean execute(Object object) throws ContractExeException {
.get(exchangeInjectContract.getOwnerAddress().toByteArray());

ExchangeCapsule exchangeCapsule;
exchangeCapsule = Commons.getExchangeStoreFinal(dynamicStore, exchangeStore, exchangeV2Store).
get(ByteArray.fromLong(exchangeInjectContract.getExchangeId()));
exchangeCapsule = Commons.getExchangeStoreFinal(dynamicStore, exchangeStore, exchangeV2Store)
.get(ByteArray.fromLong(exchangeInjectContract.getExchangeId()));
byte[] firstTokenID = exchangeCapsule.getFirstTokenId();
byte[] secondTokenID = exchangeCapsule.getSecondTokenId();
long firstTokenBalance = exchangeCapsule.getFirstTokenBalance();
Expand All @@ -73,27 +72,27 @@ public boolean execute(Object object) throws ContractExeException {
anotherTokenID = secondTokenID;
anotherTokenQuant = floorDiv(multiplyExact(
secondTokenBalance, tokenQuant), firstTokenBalance);
exchangeCapsule.setBalance(firstTokenBalance + tokenQuant,
secondTokenBalance + anotherTokenQuant);
exchangeCapsule.setBalance(addExact(firstTokenBalance, tokenQuant),
addExact(secondTokenBalance, anotherTokenQuant));
} else {
anotherTokenID = firstTokenID;
anotherTokenQuant = floorDiv(multiplyExact(
firstTokenBalance, tokenQuant), secondTokenBalance);
exchangeCapsule.setBalance(firstTokenBalance + anotherTokenQuant,
secondTokenBalance + tokenQuant);
exchangeCapsule.setBalance(addExact(firstTokenBalance, anotherTokenQuant),
addExact(secondTokenBalance, tokenQuant));
}

long newBalance = accountCapsule.getBalance() - calcFee();
long newBalance = subtractExact(accountCapsule.getBalance(), calcFee());
accountCapsule.setBalance(newBalance);

if (Arrays.equals(tokenID, TRX_SYMBOL_BYTES)) {
accountCapsule.setBalance(newBalance - tokenQuant);
accountCapsule.setBalance(subtractExact(newBalance, tokenQuant));
} else {
accountCapsule.reduceAssetAmountV2(tokenID, tokenQuant, dynamicStore, assetIssueStore);
}

if (Arrays.equals(anotherTokenID, TRX_SYMBOL_BYTES)) {
accountCapsule.setBalance(newBalance - anotherTokenQuant);
accountCapsule.setBalance(subtractExact(newBalance, anotherTokenQuant));
} else {
accountCapsule
.reduceAssetAmountV2(anotherTokenID, anotherTokenQuant, dynamicStore, assetIssueStore);
Expand All @@ -105,7 +104,8 @@ public boolean execute(Object object) throws ContractExeException {

ret.setExchangeInjectAnotherAmount(anotherTokenQuant);
ret.setStatus(fee, code.SUCESS);
} catch (ItemNotFoundException | InvalidProtocolBufferException e) {
} catch (ItemNotFoundException | InvalidProtocolBufferException
| ArithmeticException e) {
logger.debug(e.getMessage(), e);
ret.setStatus(fee, code.FAILED);
throw new ContractExeException(e.getMessage());
Expand All @@ -115,6 +115,14 @@ public boolean execute(Object object) throws ContractExeException {

@Override
public boolean validate() throws ContractValidateException {
try {
return doValidate();
} catch (ArithmeticException e) {
throw new ContractValidateException(e.getMessage());
}
}

private boolean doValidate() throws ContractValidateException {
if (this.any == null) {
throw new ContractValidateException(ActuatorConstant.CONTRACT_NOT_EXIST);
}
Expand Down Expand Up @@ -156,8 +164,8 @@ public boolean validate() throws ContractValidateException {

ExchangeCapsule exchangeCapsule;
try {
exchangeCapsule = Commons.getExchangeStoreFinal(dynamicStore, exchangeStore, exchangeV2Store).
get(ByteArray.fromLong(contract.getExchangeId()));
exchangeCapsule = Commons.getExchangeStoreFinal(dynamicStore, exchangeStore, exchangeV2Store)
.get(ByteArray.fromLong(contract.getExchangeId()));

} catch (ItemNotFoundException ex) {
throw new ContractValidateException("Exchange[" + contract.getExchangeId() + ActuatorConstant
Expand All @@ -179,9 +187,9 @@ public boolean validate() throws ContractValidateException {
byte[] anotherTokenID;
long anotherTokenQuant;

if (dynamicStore.getAllowSameTokenName() == 1 &&
!Arrays.equals(tokenID, TRX_SYMBOL_BYTES) &&
!isNumber(tokenID)) {
if (dynamicStore.getAllowSameTokenName() == 1
&& !Arrays.equals(tokenID, TRX_SYMBOL_BYTES)
&& !isNumber(tokenID)) {
throw new ContractValidateException("token id is not a valid number");
}

Expand All @@ -208,14 +216,14 @@ public boolean validate() throws ContractValidateException {
anotherTokenID = secondTokenID;
anotherTokenQuant = bigSecondTokenBalance.multiply(bigTokenQuant)
.divide(bigFirstTokenBalance).longValueExact();
newTokenBalance = firstTokenBalance + tokenQuant;
newAnotherTokenBalance = secondTokenBalance + anotherTokenQuant;
newTokenBalance = addExact(firstTokenBalance, tokenQuant);
newAnotherTokenBalance = addExact(secondTokenBalance, anotherTokenQuant);
} else {
anotherTokenID = firstTokenID;
anotherTokenQuant = bigFirstTokenBalance.multiply(bigTokenQuant)
.divide(bigSecondTokenBalance).longValueExact();
newTokenBalance = secondTokenBalance + tokenQuant;
newAnotherTokenBalance = firstTokenBalance + anotherTokenQuant;
newTokenBalance = addExact(secondTokenBalance, tokenQuant);
newAnotherTokenBalance = addExact(firstTokenBalance, anotherTokenQuant);
}

if (anotherTokenQuant <= 0) {
Expand All @@ -228,7 +236,7 @@ public boolean validate() throws ContractValidateException {
}

if (Arrays.equals(tokenID, TRX_SYMBOL_BYTES)) {
if (accountCapsule.getBalance() < (tokenQuant + calcFee())) {
if (accountCapsule.getBalance() < addExact(tokenQuant, calcFee())) {
throw new ContractValidateException("balance is not enough");
}
} else {
Expand All @@ -238,7 +246,7 @@ public boolean validate() throws ContractValidateException {
}

if (Arrays.equals(anotherTokenID, TRX_SYMBOL_BYTES)) {
if (accountCapsule.getBalance() < (anotherTokenQuant + calcFee())) {
if (accountCapsule.getBalance() < addExact(anotherTokenQuant, calcFee())) {
throw new ContractValidateException("balance is not enough");
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@
import org.tron.core.store.DynamicPropertiesStore;
import org.tron.core.store.ExchangeStore;
import org.tron.core.store.ExchangeV2Store;
import org.tron.core.utils.TransactionUtil;
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
import org.tron.protos.Protocol.Transaction.Result.code;
import org.tron.protos.contract.ExchangeContract.ExchangeTransactionContract;

@Slf4j(topic = "actuator")
public class ExchangeTransactionActuator extends AbstractActuator {
public class ExchangeTransactionActuator extends AbstractExchangeActuator {

public ExchangeTransactionActuator() {
super(ContractType.ExchangeTransactionContract, ExchangeTransactionContract.class);
Expand All @@ -56,8 +55,8 @@ public boolean execute(Object object) throws ContractExeException {
.get(exchangeTransactionContract.getOwnerAddress().toByteArray());

ExchangeCapsule exchangeCapsule = Commons
.getExchangeStoreFinal(dynamicStore, exchangeStore, exchangeV2Store).
get(ByteArray.fromLong(exchangeTransactionContract.getExchangeId()));
.getExchangeStoreFinal(dynamicStore, exchangeStore, exchangeV2Store)
.get(ByteArray.fromLong(exchangeTransactionContract.getExchangeId()));

byte[] firstTokenID = exchangeCapsule.getFirstTokenId();
byte[] secondTokenID = exchangeCapsule.getSecondTokenId();
Expand All @@ -67,25 +66,25 @@ public boolean execute(Object object) throws ContractExeException {

byte[] anotherTokenID;
long anotherTokenQuant = exchangeCapsule.transaction(tokenID, tokenQuant,
dynamicStore.allowStrictMath());
dynamicStore.allowStrictMath(), allowHarden());

if (Arrays.equals(tokenID, firstTokenID)) {
anotherTokenID = secondTokenID;
} else {
anotherTokenID = firstTokenID;
}

long newBalance = accountCapsule.getBalance() - calcFee();
long newBalance = subtractExact(accountCapsule.getBalance(), calcFee());
accountCapsule.setBalance(newBalance);

if (Arrays.equals(tokenID, TRX_SYMBOL_BYTES)) {
accountCapsule.setBalance(newBalance - tokenQuant);
accountCapsule.setBalance(subtractExact(newBalance, tokenQuant));
} else {
accountCapsule.reduceAssetAmountV2(tokenID, tokenQuant, dynamicStore, assetIssueStore);
}

if (Arrays.equals(anotherTokenID, TRX_SYMBOL_BYTES)) {
accountCapsule.setBalance(newBalance + anotherTokenQuant);
accountCapsule.setBalance(addExact(newBalance, anotherTokenQuant));
} else {
accountCapsule
.addAssetAmountV2(anotherTokenID, anotherTokenQuant, dynamicStore, assetIssueStore);
Expand All @@ -98,7 +97,8 @@ public boolean execute(Object object) throws ContractExeException {

ret.setExchangeReceivedAmount(anotherTokenQuant);
ret.setStatus(fee, code.SUCESS);
} catch (ItemNotFoundException | InvalidProtocolBufferException e) {
} catch (ItemNotFoundException | InvalidProtocolBufferException
| ContractValidateException | ArithmeticException e) {
logger.debug(e.getMessage(), e);
ret.setStatus(fee, code.FAILED);
throw new ContractExeException(e.getMessage());
Expand All @@ -109,6 +109,14 @@ public boolean execute(Object object) throws ContractExeException {

@Override
public boolean validate() throws ContractValidateException {
try {
return doValidate();
} catch (ArithmeticException e) {
throw new ContractValidateException(e.getMessage());
}
}

private boolean doValidate() throws ContractValidateException {
if (this.any == null) {
throw new ContractValidateException(ActuatorConstant.CONTRACT_NOT_EXIST);
}
Expand Down Expand Up @@ -150,8 +158,8 @@ public boolean validate() throws ContractValidateException {

ExchangeCapsule exchangeCapsule;
try {
exchangeCapsule = Commons.getExchangeStoreFinal(dynamicStore, exchangeStore, exchangeV2Store).
get(ByteArray.fromLong(contract.getExchangeId()));
exchangeCapsule = Commons.getExchangeStoreFinal(dynamicStore, exchangeStore, exchangeV2Store)
.get(ByteArray.fromLong(contract.getExchangeId()));
} catch (ItemNotFoundException ex) {
throw new ContractValidateException("Exchange[" + contract.getExchangeId()
+ ActuatorConstant.NOT_EXIST_STR);
Expand All @@ -166,9 +174,9 @@ public boolean validate() throws ContractValidateException {
long tokenQuant = contract.getQuant();
long tokenExpected = contract.getExpected();

if (dynamicStore.getAllowSameTokenName() == 1 &&
!Arrays.equals(tokenID, TRX_SYMBOL_BYTES) &&
!isNumber(tokenID)) {
if (dynamicStore.getAllowSameTokenName() == 1
&& !Arrays.equals(tokenID, TRX_SYMBOL_BYTES)
&& !isNumber(tokenID)) {
throw new ContractValidateException("token id is not a valid number");
}
if (!Arrays.equals(tokenID, firstTokenID) && !Arrays.equals(tokenID, secondTokenID)) {
Expand All @@ -191,13 +199,13 @@ public boolean validate() throws ContractValidateException {
long balanceLimit = dynamicStore.getExchangeBalanceLimit();
long tokenBalance = (Arrays.equals(tokenID, firstTokenID) ? firstTokenBalance
: secondTokenBalance);
tokenBalance += tokenQuant;
tokenBalance = addExact(tokenBalance, tokenQuant);
if (tokenBalance > balanceLimit) {
throw new ContractValidateException("token balance must less than " + balanceLimit);
}

if (Arrays.equals(tokenID, TRX_SYMBOL_BYTES)) {
if (accountCapsule.getBalance() < (tokenQuant + calcFee())) {
if (accountCapsule.getBalance() < addExact(tokenQuant, calcFee())) {
throw new ContractValidateException("balance is not enough");
}
} else {
Expand All @@ -207,7 +215,7 @@ public boolean validate() throws ContractValidateException {
}

long anotherTokenQuant = exchangeCapsule.transaction(tokenID, tokenQuant,
dynamicStore.allowStrictMath());
dynamicStore.allowStrictMath(), allowHarden());
if (anotherTokenQuant < tokenExpected) {
throw new ContractValidateException("token required must greater than expected");
}
Expand Down
Loading
Loading