Skip to content

Commit

Permalink
Merge pull request #294 from duckmatt/master
Browse files Browse the repository at this point in the history
Support passing in a string for balance id
  • Loading branch information
fracek committed Dec 29, 2020
2 parents dfa625f + 60e8681 commit a3c1b35
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 14 deletions.
90 changes: 86 additions & 4 deletions stellar-dotnet-sdk-test/OperationTest.cs
Expand Up @@ -858,13 +858,16 @@ public void TestCreateClaimableBalanceOperation()
Assert.AreEqual("AAAAAQAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAA4AAAAAAAAAAEmU+aAAAAABAAAAAAAAAAAlyvHaD8duz+iEXkJUUbsHkklIlH46oMrMMYrt0odkfgAAAAMAAAABAAAABQAAAAAAAGJw", operation.ToXdrBase64());
}

/// <summary>
/// The API didn't previously did not support the balance id type within the balance id (expected 32 bytes rather than the full 36).
/// This tests that we can still pass in the 32 bytes for compatability and use the default type (0).
/// </summary>
[TestMethod]
public void TestClaimClaimableBalanceOperation()
public void TestClaimClaimableBalanceWithLegacyByteIdOperation()
{
// GDQNY3PBOJOKYZSRMK2S7LHHGWZIUISD4QORETLMXEWXBI7KFZZMKTL3
var source = KeyPair.FromSecretSeed("SBPQUZ6G4FZNWFHKUWC5BEYWF6R52E3SEP7R3GWYSM2XTKGF5LNTWW4R");



var balanceId = Enumerable.Repeat((byte)0x07, 32).ToArray();
var operation = new ClaimClaimableBalanceOperation.Builder(balanceId)
.SetSourceAccount(source)
Expand All @@ -877,7 +880,86 @@ public void TestClaimClaimableBalanceOperation()

Assert.AreEqual("AAAAAQAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAA8AAAAABwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwc=", operation.ToXdrBase64());
}


/// <summary>
/// Claim a claimable balance using the byte representation of the balance id.
/// </summary>
[TestMethod]
public void TestClaimClaimableBalanceWithByteIdOperation()
{
// GDQNY3PBOJOKYZSRMK2S7LHHGWZIUISD4QORETLMXEWXBI7KFZZMKTL3
var source = KeyPair.FromSecretSeed("SBPQUZ6G4FZNWFHKUWC5BEYWF6R52E3SEP7R3GWYSM2XTKGF5LNTWW4R");

// Prepend type bytes (first four bytes are the balance id type)
var balanceId = Enumerable.Repeat((byte)0x07, 32).Prepend((byte)0).Prepend((byte)0).Prepend((byte)0).Prepend((byte)0).ToArray();
var operation = new ClaimClaimableBalanceOperation.Builder(balanceId)
.SetSourceAccount(source)
.Build();

var xdr = operation.ToXdr();

var parsedOperation = (ClaimClaimableBalanceOperation)Operation.FromXdr(xdr);
Assert.AreEqual(operation.SourceAccount.AccountId, parsedOperation.SourceAccount.AccountId);

Assert.AreEqual("AAAAAQAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAA8AAAAABwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwc=", operation.ToXdrBase64());
}

/// <summary>
/// Claim a claimable balance using the string representation of the balance id.
/// </summary>
[TestMethod]
public void TestClaimClaimableBalanceWithStringIdOperationValid()
{
var balanceId = "000000006d6a0c142516a9cc7885a85c5aba3a1f4af5181cf9e7a809ac7ae5e4a58c825f";
var accountId = KeyPair.FromAccountId("GABTTS6N4CT7AUN4LD7IFIUMRD5PSMCW6QTLIQNEFZDEI6ZQVUCQMCLN");
var operation = new ClaimClaimableBalanceOperation.Builder(balanceId).SetSourceAccount(accountId).Build();

var xdr = operation.ToXdr();
var parsedOperation = (ClaimClaimableBalanceOperation)Operation.FromXdr(xdr);
Assert.AreEqual(operation.SourceAccount.AccountId, parsedOperation.SourceAccount.AccountId);
CollectionAssert.AreEqual(operation.BalanceId, parsedOperation.BalanceId);

Assert.AreEqual(
"AAAAAQAAAAADOcvN4KfwUbxY/oKijIj6+TBW9Ca0QaQuRkR7MK0FBgAAAA8AAAAAbWoMFCUWqcx4hahcWro6H0r1GBz556gJrHrl5KWMgl8=",
operation.ToXdrBase64());
}

[TestMethod]
public void TestClaimClaimableBalanceOperationInvalidEmptyBalanceId()
{
var balanceId = "";
var accountId = KeyPair.FromAccountId("GABTTS6N4CT7AUN4LD7IFIUMRD5PSMCW6QTLIQNEFZDEI6ZQVUCQMCLN");

Assert.ThrowsException<ArgumentException>(() =>
new ClaimClaimableBalanceOperation.Builder(balanceId).SetSourceAccount(accountId).Build());
}

/// <summary>
/// The first 4 bytes of the balance id are the balance id type, these are required. The default is 0x00000000.
/// </summary>
[TestMethod]
public void TestClaimClaimableBalanceOperationInvalidClaimableBalanceIDTypeMissing()
{
var balanceId = "6d6a0c142516a9cc7885a85c5aba3a1f4af5181cf9e7a809ac7ae5e4a58c825f";
var accountId = KeyPair.FromAccountId("GABTTS6N4CT7AUN4LD7IFIUMRD5PSMCW6QTLIQNEFZDEI6ZQVUCQMCLN");

Assert.ThrowsException<ArgumentException>(() =>
new ClaimClaimableBalanceOperation.Builder(balanceId).SetSourceAccount(accountId).Build());
}

/// <summary>
/// The last 32 bytes of the balance id are the balance id body, this is required.
/// </summary>
[TestMethod]
public void TestClaimClaimableBalanceOperationInvalidClaimableBalanceIDBodyMissing()
{
var balanceId = "00000000";
var accountId = KeyPair.FromAccountId("GABTTS6N4CT7AUN4LD7IFIUMRD5PSMCW6QTLIQNEFZDEI6ZQVUCQMCLN");

Assert.ThrowsException<ArgumentException>(() =>
new ClaimClaimableBalanceOperation.Builder(balanceId).SetSourceAccount(accountId).Build());
}

[TestMethod]
public void TestBeginSponsoringFutureReservesOperation()
{
Expand Down
47 changes: 37 additions & 10 deletions stellar-dotnet-sdk/ClaimClaimableBalanceOperation.cs
Expand Up @@ -10,10 +10,26 @@ namespace stellar_dotnet_sdk
/// </summary>
public class ClaimClaimableBalanceOperation : Operation
{
/// <summary>
/// The ID of the ClaimableBalanceEntry being claimed.
/// </summary>
public byte[] BalanceId { get; }

public ClaimClaimableBalanceOperation(byte[] balanceId)
{
// Backwards compat - was previously expecting no type to be set, set CLAIMABLE_BALANCE_ID_TYPE_V0 to match previous behaviour.
if (balanceId.Length == 32)
{
var expanded = new byte[36];
Array.Copy(balanceId, 0, expanded, 4, 32);
balanceId = expanded;
}

if (balanceId.Length != 36)
{
throw new ArgumentException("Must be 36 bytes long", nameof(balanceId));
}

BalanceId = balanceId;
}

Expand All @@ -24,14 +40,7 @@ public override xdr.Operation.OperationBody ToOperationBody()
Discriminant = xdr.OperationType.Create(xdr.OperationType.OperationTypeEnum.CLAIM_CLAIMABLE_BALANCE),
ClaimClaimableBalanceOp = new xdr.ClaimClaimableBalanceOp
{
BalanceID = new xdr.ClaimableBalanceID
{
Discriminant = new xdr.ClaimableBalanceIDType
{
InnerValue = xdr.ClaimableBalanceIDType.ClaimableBalanceIDTypeEnum.CLAIMABLE_BALANCE_ID_TYPE_V0,
},
V0 = new xdr.Hash(BalanceId)
}
BalanceID = xdr.ClaimableBalanceID.Decode(new xdr.XdrDataInputStream(BalanceId))
}
};
}
Expand All @@ -50,13 +59,31 @@ public Builder(xdr.ClaimClaimableBalanceOp op)
_balanceId = op.BalanceID.V0.InnerValue;
}

/// <summary>
/// Creates a new ClaimClaimableBalanceOperation builder.
/// </summary>
/// <param name="balanceId">The ID of the ClaimableBalanceEntry being claimed.</param>
/// <exception cref="ArgumentException">when balance id is not 36 bytes.</exception>
public Builder(byte[] balanceId)
{
if (balanceId.Length != 32)
throw new ArgumentException("Must be 32 bytes long", nameof(balanceId));
if (balanceId.Length != 36 && balanceId.Length != 32)
// Don't mention the 32 bytes, it's for backwards compat and shouldn't direct towards using it.
throw new ArgumentException("Must be 36 bytes long", nameof(balanceId));
_balanceId = balanceId;
}

/// <summary>
/// Creates a new ClaimClaimableBalanceOperation builder.
/// </summary>
/// <param name="balanceId">The ID of the ClaimableBalanceEntry being claimed.</param>
/// <exception cref="ArgumentException">when balance id is not a hex string representing 36 bytes.</exception>
public Builder(String balanceId)
{
if (balanceId.Length != 72)
throw new ArgumentException("Must be a hex string of 72 characters", nameof(balanceId));
_balanceId = Util.HexToBytes(balanceId);
}

/// <summary>
/// Sets the source account for this operation.
/// </summary>
Expand Down

0 comments on commit a3c1b35

Please sign in to comment.