Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#374: fix npe on liquidity pool trustline in changetrustresponse #378

Merged
merged 1 commit into from
Nov 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions src/main/java/org/stellar/sdk/Asset.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ public abstract class Asset implements Comparable<Asset> {

/**
* Parses an asset string and returns the equivalent Asset instance.
* The asset string is expected to either be "native" or a string of the form "CODE:ISSUER"
* The asset string is expected to either be "native" or a string of Alpha4 or Alpha12
* asset code as "CODE:ISSUER"
*
* @param canonicalForm Canonical string representation of an asset
* @param canonicalForm Canonical string representation of an Alpha4 or Alpha12 asset
* @return Asset or throws IllegalArgumentException if not Alpha4 or Alpha12 asset code
*/
public static Asset create(String canonicalForm) {
if (canonicalForm.equals("native")) {
Expand All @@ -24,12 +26,36 @@ public static Asset create(String canonicalForm) {
return Asset.createNonNativeAsset(parts[0], parts[1]);
}

/**
* Creates Asset for Alpha4/Alpha5/Native
*
* @param type the type of asset can be 'native', 'alpha4', 'alpha12'
* @param code the asset code that conforms to type or null
* @param issuer the asset issuer the conforms to type or null
* @return
*/
public static Asset create(String type, String code, String issuer) {
return create(type, code, issuer, null);
}

/**
* Creates Asset for Alpha4/Alpha5/Native/LiquidityPool
*
* @param type the type of asset can be 'native', 'alpha4', 'alpha12' or 'liquidity_pool_shares'
* @param code the asset code that conforms to type or null
* @param issuer the asset issuer the conforms to type or null
* @param liquidityPoolID provided only if type is 'liquidity_pool_shares'
* @return Asset
*/
public static Asset create(String type, String code, String issuer, String liquidityPoolID) {
if (type.equals("native")) {
return new AssetTypeNative();
} else {
return Asset.createNonNativeAsset(code, issuer);
}
if (type.equals("liquidity_pool_shares")) {
return new AssetTypePoolShare(liquidityPoolID);
}

return Asset.createNonNativeAsset(code, issuer);
}

public static Asset create(ChangeTrustAsset.Wrapper wrapped) {
Expand Down Expand Up @@ -82,7 +108,7 @@ public static Asset fromXdr(org.stellar.sdk.xdr.Asset xdr) {
* <li><code>native</code></li>
* <li><code>credit_alphanum4</code></li>
* <li><code>credit_alphanum12</code></li>
* <li><code>pool_share</code></li>
* <li><code>liquidity_pool_shares</code></li>
* </ul>
*/
public abstract String getType();
Expand Down
70 changes: 70 additions & 0 deletions src/main/java/org/stellar/sdk/AssetTypePoolShare.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.stellar.sdk;

import com.google.common.base.Objects;

/**
* Represents Stellar liquidity pool share asset - <a href="https://developers.stellar.org/docs/glossary/liquidity-pool/#trustlines" target="_blank">lumens (XLM)</a>
* @see <a href="https://developers.stellar.org/docs/glossary/liquidity-pool/#trustlines" target="_blank">Assets</a>
*/
public final class AssetTypePoolShare extends Asset {

private final String poolId;

public AssetTypePoolShare(String poolId) {
this.poolId = poolId;
}

@Override
public String toString() {
return "liquidity_pool_shares";
}

@Override
public String getType() {
return "liquidity_pool_shares";
}

@Override
public boolean equals(Object object) {
if (object == null || !this.getClass().equals(object.getClass())) {
return false;
}

return (Objects.equal(((AssetTypePoolShare)object).getPoolId(), poolId));
}

@Override
public int hashCode() {
return Objects.hashCode(poolId);
}

@Override
public org.stellar.sdk.xdr.Asset toXdr() {
throw new UnsupportedOperationException("liquidity_pool_shares are not defined as Asset in XDR");
}

@Override
public int compareTo(Asset other) {
if (other == null || !this.getClass().equals(other.getClass())) {
return -1;
}

AssetTypePoolShare otherPoolShare = (AssetTypePoolShare)other;

if (poolId == null && otherPoolShare.getPoolId() == null) {
return 0;
}

if (poolId == null) {
return -1;
}

if (otherPoolShare.getPoolId() == null) {
return 1;
}

return poolId.compareTo(otherPoolShare.getPoolId());
}

public String getPoolId() { return poolId; }
}
24 changes: 15 additions & 9 deletions src/main/java/org/stellar/sdk/responses/AssetDeserializer.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
package org.stellar.sdk.responses;

import com.google.common.base.Function;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;

import org.stellar.sdk.Asset;
import org.stellar.sdk.AssetTypeNative;

import java.lang.reflect.Type;

import static com.google.common.base.Optional.fromNullable;

class AssetDeserializer implements JsonDeserializer<Asset> {
@Override
public Asset deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (!json.isJsonObject()) {
// Probably a canonical string
return Asset.create(json.getAsString());
}
String type = json.getAsJsonObject().get("asset_type").getAsString();
if (type.equals("native")) {
return new AssetTypeNative();
} else {
String code = json.getAsJsonObject().get("asset_code").getAsString();
String issuer = json.getAsJsonObject().get("asset_issuer").getAsString();
return Asset.createNonNativeAsset(code, issuer);

return Asset.create(json.getAsJsonObject().get("asset_type").getAsString(),
fromNullable(json.getAsJsonObject().get("asset_code")).transform(ToString.FUNCTION).orNull(),
fromNullable(json.getAsJsonObject().get("asset_issuer")).transform(ToString.FUNCTION).orNull(),
fromNullable(json.getAsJsonObject().get("liquidity_pool_id")).transform(ToString.FUNCTION).orNull());
}

enum ToString implements Function<JsonElement, String> {
FUNCTION;
@Override
public String apply(JsonElement input) {
return input.getAsString();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import com.google.common.base.Optional;
import com.google.gson.annotations.SerializedName;

import org.stellar.sdk.Asset;
import org.stellar.sdk.AssetTypeNative;
import org.stellar.sdk.responses.MuxedAccount;

/**
Expand All @@ -30,6 +28,8 @@ public class ChangeTrustOperationResponse extends OperationResponse {
private String assetIssuer;
@SerializedName("limit")
private String limit;
@SerializedName("liquidity_pool_id")
private String liquidityPoolId;

public Optional<MuxedAccount> getTrustorMuxed() {
if (this.trustorMuxed == null || this.trustorMuxed.isEmpty()) {
Expand All @@ -51,10 +51,7 @@ public String getLimit() {
}

public Asset getAsset() {
if (assetType.equals("native")) {
return new AssetTypeNative();
} else {
return Asset.createNonNativeAsset(assetCode, assetIssuer);
}
return Asset.create(assetType, assetCode, assetIssuer, liquidityPoolId);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -366,13 +366,54 @@ public void testDeserializeChangeTrustOperation() {

ChangeTrustOperationResponse operation = (ChangeTrustOperationResponse) GsonSingleton.getInstance().fromJson(json, OperationResponse.class);

operation.getAsset();
assertEquals(operation.getTrustee(), "GDIROJW2YHMSFZJJ4R5XWWNUVND5I45YEWS5DSFKXCHMADZ5V374U2LM");
assertEquals(operation.getTrustor(), "GDZ55LVXECRTW4G36EZPTHI4XIYS5JUC33TUS22UOETVFVOQ77JXWY4F");
assertEquals(operation.getLimit(), "922337203685.4775807");
assertEquals(operation.getAsset(), Asset.createNonNativeAsset("EUR", "GDIROJW2YHMSFZJJ4R5XWWNUVND5I45YEWS5DSFKXCHMADZ5V374U2LM"));
assertFalse(operation.getTrustorMuxed().isPresent());
}

@Test
public void testDeserializeChangeTrustOperationLiquidityPoolShares() {
String json = "{\n" +
" \"_links\": {\n" +
" \"self\": {\n" +
" \"href\": \"//horizon-testnet.stellar.org/operations/3602970755207169\"\n" +
" },\n" +
" \"transaction\": {\n" +
" \"href\": \"//horizon-testnet.stellar.org/transactions/8d409a788543895843d269c3f97a2d6a2ebca6e9f8f9a7ae593457b5c0ba6644\"\n" +
" },\n" +
" \"effects\": {\n" +
" \"href\": \"//horizon-testnet.stellar.org/operations/3602970755207169/effects\"\n" +
" },\n" +
" \"succeeds\": {\n" +
" \"href\": \"//horizon-testnet.stellar.org/effects?order=desc\\u0026cursor=3602970755207169\"\n" +
" },\n" +
" \"precedes\": {\n" +
" \"href\": \"//horizon-testnet.stellar.org/effects?order=asc\\u0026cursor=3602970755207169\"\n" +
" }\n" +
" },\n" +
" \"id\": \"3602970755207169\",\n" +
" \"paging_token\": \"3602970755207169\",\n" +
" \"source_account\": \"GDZ55LVXECRTW4G36EZPTHI4XIYS5JUC33TUS22UOETVFVOQ77JXWY4F\",\n" +
" \"type\": \"change_trust\",\n" +
" \"type_i\": 6,\n" +
" \"asset_type\": \"liquidity_pool_shares\",\n" +
" \"liquidity_pool_id\": \"02449937ed825805b7a945bb6c027b53dfaf140983c1a1a64c42a81edd89b5e0\",\n" +
" \"limit\": \"5.0000000\",\n" +
" \"trustee\": \"GDIROJW2YHMSFZJJ4R5XWWNUVND5I45YEWS5DSFKXCHMADZ5V374U2LM\",\n" +
" \"trustor\": \"GDZ55LVXECRTW4G36EZPTHI4XIYS5JUC33TUS22UOETVFVOQ77JXWY4F\"\n" +
" }";

ChangeTrustOperationResponse operation = (ChangeTrustOperationResponse) GsonSingleton.getInstance().fromJson(json, OperationResponse.class);

assertEquals(operation.getTrustee(), "GDIROJW2YHMSFZJJ4R5XWWNUVND5I45YEWS5DSFKXCHMADZ5V374U2LM");
assertEquals(operation.getTrustor(), "GDZ55LVXECRTW4G36EZPTHI4XIYS5JUC33TUS22UOETVFVOQ77JXWY4F");
assertEquals(operation.getLimit(), "5.0000000");
assertEquals(((AssetTypePoolShare)operation.getAsset()).getPoolId(), "02449937ed825805b7a945bb6c027b53dfaf140983c1a1a64c42a81edd89b5e0");
}

@Test
public void testDeserializeMuxedChangeTrustOperation() {
String json = "{\n" +
Expand Down