package com.ripple.core.types.known.sle.entries;
import com.ripple.core.coretypes.AccountID;
import com.ripple.core.coretypes.Amount;
import com.ripple.core.coretypes.Currency;
import com.ripple.core.coretypes.Issue;
import com.ripple.core.coretypes.hash.Hash256;
import com.ripple.core.coretypes.hash.Index;
import com.ripple.core.coretypes.uint.UInt32;
import com.ripple.core.coretypes.uint.UInt64;
import com.ripple.core.enums.LedgerFlag;
import com.ripple.core.fields.AmountField;
import com.ripple.core.fields.Field;
import com.ripple.core.serialized.enums.LedgerEntryType;
import com.ripple.core.types.known.sle.ThreadedLedgerEntry;
import java.util.Arrays;
import java.util.List;
public class RippleState extends ThreadedLedgerEntry {
/**
The RippleState is a ledger entry which roughly speaking defines the balance and
trust limits between two accounts.
Like all current ledger entries, it has a canonical form for hashing that
doesn't necessarily communicate the information in a way that is clear or
obvious to a human. The current json format for some ledger entries is very
close to the hashing format, and isn't any better.
The two accounts on the link are categorized into a low account, and a high
account by comparing the 160bits of their account id as a big endian unsigned
integer.
There is one and only one `Balance` stored, using an amount struct with a
neutral `issuer`. ( A uint160 with the numerical value of `1` was chosen as a
placeholder, as the canonical way to represent a null account )
The Balance can be negative, zero, or positive and is in terms of the Low
account, such that when it's positive, it defines how much credit the High
account has issued.
Between any account, there can be two types of balance changes, issuance and
redemption. A redemption is the transferal of previously issued IOUs back to the
owner.
This implies that for any account, that can they can make a transferal using
funds from two distinct balances. After making this distinction it becomes
nonsensical to say that an account holds negative IOUs from the opposite line.
Thus, the one Balance in a ripple state actually implies 4 distinct balances.
```
{
...
"Balance" : {
"currency" : "USD",
"issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value" : "100"
},
"HighLimit" : {
"currency" : "USD",
"issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
"value" : "500"
},
"LowLimit" : {
"currency" : "USD",
"issuer" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"value" : "500"
},
}
```
lowAccount = LowLimit.issuer
hiAccount = HighLimit.issuer
Balances:
lowAccount has 100/USD/highAccount
lowAccount has 0/USD/lowAccount on the line
highAccount has 0/USD/lowAccount
highAccount has -100/USD/highAccount on the line
* */
public RippleState() {
super(LedgerEntryType.RippleState);
}
public UInt32 highQualityIn() {return get(UInt32.HighQualityIn);}
public UInt32 highQualityOut() {return get(UInt32.HighQualityOut);}
public UInt32 lowQualityIn() {return get(UInt32.LowQualityIn);}
public UInt32 lowQualityOut() {return get(UInt32.LowQualityOut);}
public UInt64 lowNode() {return get(UInt64.LowNode);}
public UInt64 highNode() {return get(UInt64.HighNode);}
public Amount balance() {return get(Amount.Balance);}
public Amount lowLimit() {return get(Amount.LowLimit);}
public Amount highLimit() {return get(Amount.HighLimit);}
public void highQualityIn(UInt32 val) {put(Field.HighQualityIn, val);}
public void highQualityOut(UInt32 val) {put(Field.HighQualityOut, val);}
public void lowQualityIn(UInt32 val) {put(Field.LowQualityIn, val);}
public void lowQualityOut(UInt32 val) {put(Field.LowQualityOut, val);}
public void lowNode(UInt64 val) {put(Field.LowNode, val);}
public void highNode(UInt64 val) {put(Field.HighNode, val);}
public void balance(Amount val) {put(Field.Balance, val);}
public void lowLimit(Amount val) {put(Field.LowLimit, val);}
public void highLimit(Amount val) {put(Field.HighLimit, val);}
public AccountID lowAccount() {
return lowLimit().issuer();
}
public AccountID highAccount() {
return highLimit().issuer();
}
public List<AccountID> sortedAccounts() {
return Arrays.asList(lowAccount(), highAccount());
}
public AmountField limitFieldFor(AccountID source) {
if (lowAccount().equals(source)) {
return Amount.LowLimit;
}
if (highAccount().equals(source)) {
return Amount.HighLimit;
} else {
return null;
}
}
public boolean isFor(AccountID source) {
return lowAccount().equals(source) || highAccount().equals(source);
}
public boolean isFor(Issue issue) {
return isFor(issue.issuer()) && balance().currency().equals(issue.currency());
}
// TODO, can optimize this
public boolean isFor(AccountID s1, AccountID s2, Currency currency) {
return currency.equals(balance().currency()) && isFor(s1) && isFor(s2);
}
public Currency currency() {
return balance().currency();
}
private Amount issuedBy(boolean hi) {
Amount balance;
if (hi) {
balance = balance().newIssuer(highAccount());
} else {
balance = balance().negate().newIssuer(lowAccount());
}
if (!balance.isPositive()) {
balance = balance.issue().amount(0);
}
return balance;
}
public Amount issuedByHigh() {
return issuedBy(true);
}
public Amount issuedByLow() {
return issuedBy(false);
}
public Amount issuedTo(AccountID accountID) {
return issuedBy(isLowAccount(accountID));
}
@Deprecated() // "not deprecated but needs fixing"
public boolean authorizedBy(AccountID account) {
UInt32 flags = flags();
return flags == null || flags.testBit(isHighAccount(account) ? LedgerFlag.HighAuth : LedgerFlag.LowAuth);
}
private boolean isBitSet(int flags, int flag) {
return (flags & flag) != 0;
}
private boolean isHighAccount(AccountID account) {
return highAccount().equals(account);
}
private boolean isLowAccount(AccountID account) {
return lowAccount().equals(account);
}
public Hash256 lowNodeOwnerDirectory() {
Hash256 ownerDir = Index.ownerDirectory(lowAccount());
return Index.directoryNode(ownerDir, lowNode());
}
public Hash256 highNodeOwnerDirectory() {
Hash256 ownerDir = Index.ownerDirectory(highAccount());
return Index.directoryNode(ownerDir, highNode());
}
public Hash256[] directoryIndexes() {
return new Hash256[]{lowNodeOwnerDirectory(), highNodeOwnerDirectory()};
}
@Override
public void setDefaults() {
super.setDefaults();
if (lowNode() == null) {
lowNode(UInt64.ZERO);
}
if (highNode() == null) {
highNode(UInt64.ZERO);
}
}
}