import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import com.credits.scapi.annotations.*;
import com.credits.scapi.v0.*;
import static java.math.BigDecimal.ROUND_FLOOR;
import static java.math.BigDecimal.ZERO;
public class Token12 extends SmartContract implements ExtensionStandard {
private final String owner;
private final BigDecimal tokenCost;
private final int decimal;
HashMap<String, BigDecimal> balances;
private String name;
private String symbol;
private BigDecimal totalCoins;
private HashMap<String, Map<String, BigDecimal>> allowed;
private boolean frozen;
public Token12() {
super();
name = "1";
symbol = "12";
decimal = 1;
tokenCost = new BigDecimal(0).setScale(decimal, ROUND_FLOOR);
totalCoins = new BigDecimal(100).setScale(decimal, ROUND_FLOOR);
owner = initiator;
allowed = new HashMap<>();
balances = new HashMap<>();
balances.put(owner, new BigDecimal(100L).setScale(decimal, ROUND_FLOOR));
}
@Override
public int getDecimal() {
return decimal;
}
@Override
public void register() {
balances.putIfAbsent(initiator, ZERO.setScale(decimal, ROUND_FLOOR));
}
@Override
public boolean setFrozen(boolean isFrozen) {
if (!initiator.equals(owner)) {
throw new RuntimeException("unable change frozen state! The wallet "+ initiator + " is not owner");
}
this.frozen = isFrozen;
return true;
}
@Override
public String getName() {
return name;
}
@Override
public String getSymbol() {
return symbol;
}
@Override
public String totalSupply() {
return totalCoins.toString();
}
@Override
public String balanceOf(String owner) {
return getTokensBalance(owner).toString();
}
@Override
public String allowance(String owner, String spender) {
if (allowed.get(owner) == null) {
return "0";
}
BigDecimal amount = allowed.get(owner).get(spender);
return amount != null ? amount.toString() : "0";
}
@Override
public boolean transfer(String to, String amount) {
contractIsNotFrozen();
if (!to.equals(initiator)) {
BigDecimal decimalAmount = toBigDecimal(amount);
BigDecimal sourceBalance = getTokensBalance(initiator);
BigDecimal targetTokensBalance = getTokensBalance(to);
if (decimalAmount.compareTo(ZERO.setScale(decimal, ROUND_FLOOR)) < 0) {
throw new RuntimeException("invalid amount");
}
if(targetTokensBalance == null)
{
targetTokensBalance = new BigDecimal(0).setScale(decimal, ROUND_FLOOR);
}
if (sourceBalance.compareTo(decimalAmount) < 0) {
throw new RuntimeException("the wallet" + initiator + "doesn't have enough tokens to transfer");
}
balances.put(initiator, sourceBalance.subtract(decimalAmount));
balances.put(to, targetTokensBalance.add(decimalAmount));
}
return true;
}
@Override
public boolean transferFrom(String from, String to, String amount) {
contractIsNotFrozen();
if (!from.equals(to)) {
BigDecimal sourceBalance = getTokensBalance(from);
BigDecimal targetTokensBalance = getTokensBalance(to);
if(targetTokensBalance == null)
{
targetTokensBalance = new BigDecimal(0).setScale(decimal, ROUND_FLOOR);
}
BigDecimal decimalAmount = toBigDecimal(amount);
if (decimalAmount.compareTo(ZERO.setScale(decimal, ROUND_FLOOR)) < 0) {
throw new RuntimeException("invalid amount");
}
if (sourceBalance.compareTo(decimalAmount) < 0)
throw new RuntimeException("unable transfer tokens! The balance of " + from + " less then " + amount);
Map<String, BigDecimal> spender = allowed.get(from);
if (spender == null || !spender.containsKey(initiator))
throw new RuntimeException("unable transfer tokens! The wallet " + from + " not allow transfer tokens for " + to);
BigDecimal allowTokens = spender.get(initiator);
if (allowTokens.compareTo(decimalAmount) < 0) {
throw new RuntimeException("unable transfer tokens! Not enough allowed tokens. For the wallet " + initiator + " allow only " + allowTokens + " tokens");
}
spender.put(initiator, allowTokens.subtract(decimalAmount));
balances.put(from, sourceBalance.subtract(decimalAmount));
balances.put(to, targetTokensBalance.add(decimalAmount));
}
return true;
}
@Override
public void approve(String spender, String amount) {
initiatorIsRegistered();
BigDecimal decimalAmount = toBigDecimal(amount);
if (decimalAmount.compareTo(ZERO.setScale(decimal, ROUND_FLOOR)) < 0) {
throw new RuntimeException("invalid amount");
}
Map<String, BigDecimal> initiatorSpenders = allowed.get(initiator);
if (initiatorSpenders == null) {
Map<String, BigDecimal> newSpender = new HashMap<>();
newSpender.put(spender, decimalAmount);
allowed.put(initiator, newSpender);
} else {
BigDecimal spenderAmount = initiatorSpenders.get(spender);
initiatorSpenders.put(spender, spenderAmount == null ? decimalAmount : spenderAmount.add(decimalAmount));
}
}
@Override
public boolean burn(String amount) {
contractIsNotFrozen();
BigDecimal decimalAmount = toBigDecimal(amount);
if (decimalAmount.compareTo(ZERO.setScale(decimal, ROUND_FLOOR)) < 0) {
throw new RuntimeException("invalid amount");
}
if (!initiator.equals(owner))
throw new RuntimeException("can not burn tokens! The wallet " + initiator + " is not owner");
if (totalCoins.compareTo(decimalAmount) < 0) totalCoins = ZERO;
else totalCoins = totalCoins.subtract(decimalAmount);
return true;
}
public void payable(String amount, String currency) {
contractIsNotFrozen();
BigDecimal decimalAmount = toBigDecimal(amount);
if (totalCoins.compareTo(decimalAmount) < 0) throw new RuntimeException("not enough tokes to buy");
balances.put(initiator, Optional.ofNullable(balances.get(initiator)).orElse(ZERO).add(decimalAmount));
totalCoins = totalCoins.subtract(decimalAmount);
}
@Override
public boolean buyTokens(String amount) {
return false;
}
private void contractIsNotFrozen() {
if (frozen) throw new RuntimeException("unavailable action! The smart-contract is frozen");
}
private void initiatorIsRegistered() {
if (!balances.containsKey(initiator))
throw new RuntimeException("unavailable action! The wallet " + initiator + " is not registered");
}
private BigDecimal toBigDecimal(String stringValue) {
return new BigDecimal(stringValue).setScale(decimal, ROUND_FLOOR);
}
private BigDecimal getTokensBalance(String address) {
return balances.get(address);
}
}