Skip to content
This repository has been archived by the owner on May 24, 2024. It is now read-only.

Commit

Permalink
Merge pull request #366 from elucidsoft/fix-muxed-account
Browse files Browse the repository at this point in the history
Fixes muxed account not working correctly.
  • Loading branch information
elucidsoft authored Jun 10, 2022
2 parents 327fc43 + 3f05829 commit 6a4a53c
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 52 deletions.
15 changes: 4 additions & 11 deletions stellar-dotnet-sdk-test/FeeBumpTransactionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,28 +145,21 @@ public void TestTransactionHash()
var network = Network.Test();
var innerTx = CreateInnerTransaction(100, network);

Assert.AreEqual(
"95dcf35a43a1a05bcd50f3eb148b31127829a9460dc32a17c4a7f7c4677409d4",
Util.BytesToHex(innerTx.Hash(network)).ToLowerInvariant());
Assert.AreEqual("2a8ead3351faa7797b284f59027355ddd69c21adb8e4da0b9bb95531f7f32681", Util.BytesToHex(innerTx.Hash(network)).ToLowerInvariant());

var feeSource = KeyPair.FromAccountId("GDQNY3PBOJOKYZSRMK2S7LHHGWZIUISD4QORETLMXEWXBI7KFZZMKTL3");
var feeBumpTx = TransactionBuilder.BuildFeeBumpTransaction(feeSource, innerTx, 200);

Assert.AreEqual(
"382b1588ee8b315177a34ae96ebcaeb81c0ad3e04fee7c6b5a583b826517e1e4",
Util.BytesToHex(feeBumpTx.Hash(network)).ToLowerInvariant());
Assert.AreEqual("58266712c0c1d1cd98faa0e0159605a361cf2a5ca44ad69650eeb1d27ee62334", Util.BytesToHex(feeBumpTx.Hash(network)).ToLowerInvariant());
}

private Transaction CreateInnerTransaction(uint fee, Network network)
{
var source = KeyPair.FromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS");
var destination =
MuxedAccountMed25519.FromMuxedAccountId(
"MCAAAAAAAAAAAAB7BQ2L7E5NBWMXDUCMZSIPOBKRDSBYVLMXGSSKF6YNPIB7Y77ITKNOG");
var destination = KeyPair.FromAccountId("GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ");
var account = new Account(source, 2908908335136768L);
var innerTx = new TransactionBuilder(account)
.AddOperation(
new PaymentOperation.Builder(destination, new AssetTypeNative(), "200.0").Build())
.AddOperation(new PaymentOperation.Builder(destination, new AssetTypeNative(), "200.0").Build())
.SetFee(fee)
.AddTimeBounds(new TimeBounds(10, 11))
.Build();
Expand Down
5 changes: 2 additions & 3 deletions stellar-dotnet-sdk-test/MuxedAccountTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ public class MuxedAccountTest
[TestMethod]
public void TestFromAccountId()
{
var muxed = MuxedAccountMed25519.FromMuxedAccountId(
"MAAAAAAAAAAAJURAAB2X52XFQP6FBXLGT6LWOOWMEXWHEWBDVRZ7V5WH34Y22MPFBHUHY");
var muxed = MuxedAccountMed25519.FromMuxedAccountId("MAQAA5L65LSYH7CQ3VTJ7F3HHLGCL3DSLAR2Y47263D56MNNGHSQSAAAAAAAAAAE2LP26");
Assert.AreEqual(1234UL, muxed.Id);
Assert.AreEqual("GAQAA5L65LSYH7CQ3VTJ7F3HHLGCL3DSLAR2Y47263D56MNNGHSQSTVY", muxed.Key.Address);
Assert.AreEqual("MAAAAAAAAAAAJURAAB2X52XFQP6FBXLGT6LWOOWMEXWHEWBDVRZ7V5WH34Y22MPFBHUHY", muxed.Address);
Assert.AreEqual("MAQAA5L65LSYH7CQ3VTJ7F3HHLGCL3DSLAR2Y47263D56MNNGHSQSAAAAAAAAAAE2LP26", muxed.Address);
}
}
}
22 changes: 12 additions & 10 deletions stellar-dotnet-sdk-test/StrKeyTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using stellar_dotnet_sdk;
using System.Collections.Generic;
using System.Linq;
using xdrSDK = stellar_dotnet_sdk.xdr;

namespace stellar_dotnet_sdk_test
{
Expand Down Expand Up @@ -37,25 +38,26 @@ public void TestDecodeInvalidSeed()
[TestMethod]
public void TestDecodeEncodeMuxedAccount()
{
var address = "MAAAAAAAAAAAAAB7BQ2L7E5NBWMXDUCMZSIPOBKRDSBYVLMXGSSKF6YNPIB7Y77ITLVL6";
var (id, key) = StrKey.DecodeStellarMuxedAccount(address);
var address = "MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUQ";
var muxed = StrKey.DecodeStellarMuxedAccount(address);
Assert.IsTrue(StrKey.IsValidMuxedAccount(address));
Assert.AreEqual(0UL, id);
var encodedKey = StrKey.EncodeStellarAccountId(key);
Assert.AreEqual(0UL, muxed.Med25519.Id.InnerValue);

var encodedKey = StrKey.EncodeStellarAccountId(muxed.Med25519.Ed25519.InnerValue);
Assert.AreEqual("GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ", encodedKey);
Assert.AreEqual(address, StrKey.EncodeStellarMuxedAccount(key, id));
Assert.AreEqual(address, StrKey.EncodeStellarMuxedAccount(new MuxedAccountMed25519(KeyPair.FromPublicKey(muxed.Med25519.Ed25519.InnerValue), muxed.Med25519.Id.InnerValue).MuxedAccount));
}

[TestMethod]
public void TestDecodeEncodeMuxedAccountWithLargeId()
{
var address = "MCAAAAAAAAAAAAB7BQ2L7E5NBWMXDUCMZSIPOBKRDSBYVLMXGSSKF6YNPIB7Y77ITKNOG";
var (id, key) = StrKey.DecodeStellarMuxedAccount(address);
var address = "MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVAAAAAAAAAAAAAJLK";
var muxed = StrKey.DecodeStellarMuxedAccount(address);
Assert.IsTrue(StrKey.IsValidMuxedAccount(address));
Assert.AreEqual(9223372036854775808UL, id);
var encodedKey = StrKey.EncodeStellarAccountId(key);
Assert.AreEqual(9223372036854775808UL, muxed.Med25519.Id.InnerValue);
var encodedKey = StrKey.EncodeStellarAccountId(muxed.Med25519.Ed25519.InnerValue);
Assert.AreEqual("GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ", encodedKey);
Assert.AreEqual(address, StrKey.EncodeStellarMuxedAccount(key, id));
Assert.AreEqual(address, StrKey.EncodeStellarMuxedAccount(new MuxedAccountMed25519(KeyPair.FromPublicKey(muxed.Med25519.Ed25519.InnerValue), muxed.Med25519.Id.InnerValue).MuxedAccount));
}

[TestMethod]
Expand Down
8 changes: 4 additions & 4 deletions stellar-dotnet-sdk/MuxedAccountMed25519.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ public static MuxedAccountMed25519 FromMuxedAccountXdr(xdr.MuxedAccount.MuxedAcc
/// <returns></returns>
public static MuxedAccountMed25519 FromMuxedAccountId(string muxedAccountId)
{
var (id, data) = StrKey.DecodeStellarMuxedAccount(muxedAccountId);
var key = KeyPair.FromPublicKey(data);
return new MuxedAccountMed25519(key, id);
var muxedAccount = StrKey.DecodeStellarMuxedAccount(muxedAccountId);
var key = KeyPair.FromPublicKey(muxedAccount.Med25519.Ed25519.InnerValue);
return new MuxedAccountMed25519(key, muxedAccount.Med25519.Id.InnerValue);
}

/// <summary>
Expand All @@ -67,7 +67,7 @@ public xdr.MuxedAccount MuxedAccount
/// <summary>
/// Get the MuxedAccount address, starting with M.
/// </summary>
public string Address => StrKey.EncodeStellarMuxedAccount(Key.PublicKey, Id);
public string Address => StrKey.EncodeStellarMuxedAccount(MuxedAccount);

/// <summary>
/// Get the MuxedAccount account id, starting with M.
Expand Down
75 changes: 51 additions & 24 deletions stellar-dotnet-sdk/StrKey.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using xdr = stellar_dotnet_sdk.xdr;
using xdrSDK = stellar_dotnet_sdk.xdr;

namespace stellar_dotnet_sdk
{
Expand Down Expand Up @@ -41,19 +41,20 @@ public static string EncodeSignedPayload(SignedPayloadSigner signedPayloadSigner
}
}

public static string EncodeStellarMuxedAccount(byte[] data, ulong id)
public static string EncodeStellarMuxedAccount(xdrSDK.MuxedAccount muxedAccount)
{
// 8 bytes for 64 bit id + data
var dataToEncode = new byte[8 + data.Length];
// Prepend the id in network byte order to the data
var idBytes = BitConverter.GetBytes(id);
if (BitConverter.IsLittleEndian)
switch (muxedAccount.Discriminant.InnerValue)
{
Array.Reverse(idBytes);
case xdrSDK.CryptoKeyType.CryptoKeyTypeEnum.KEY_TYPE_MUXED_ED25519:
var bytes = muxedAccount.Med25519.Ed25519.InnerValue.Concat(Util.ToByteArray(muxedAccount.Med25519.Id.InnerValue)).ToArray();
return EncodeCheck(VersionByte.MUXED_ACCOUNT, bytes);

case xdrSDK.CryptoKeyType.CryptoKeyTypeEnum.KEY_TYPE_ED25519:
return EncodeCheck(VersionByte.ACCOUNT_ID, muxedAccount.Ed25519.InnerValue);

default:
throw new ArgumentException("invalid discriminant");
}
Buffer.BlockCopy(idBytes, 0, dataToEncode, 0, 8);
Buffer.BlockCopy(data, 0, dataToEncode, 8, data.Length);
return EncodeCheck(VersionByte.MUXED_ACCOUNT, dataToEncode);
}

public static string EncodeStellarSecretSeed(byte[] data)
Expand Down Expand Up @@ -82,24 +83,50 @@ public static SignedPayloadSigner DecodeSignedPayload(string data)
}
}

public static (ulong, byte[]) DecodeStellarMuxedAccount(string data)
public static xdrSDK.MuxedAccount DecodeStellarMuxedAccount(string data)
{
var bytes = DecodeCheck(VersionByte.MUXED_ACCOUNT, data);
var keyData = new byte[bytes.Length - 8];
ulong id;
Buffer.BlockCopy(bytes, 8, keyData, 0, keyData.Length);
xdrSDK.MuxedAccount muxed = new xdrSDK.MuxedAccount();

if (BitConverter.IsLittleEndian)
if (data.Length == 0)
{
var idBuffer = new byte[8];
Buffer.BlockCopy(bytes, 0, idBuffer, 0, 8);
Array.Reverse(idBuffer);
id = BitConverter.ToUInt64(idBuffer, 0);
return (id, keyData);
throw new ArgumentException("Address is empty");
}

id = BitConverter.ToUInt64(bytes, 0);
return (id, keyData);
switch (DecodeVersionByte(data))
{
case VersionByte.ACCOUNT_ID:
muxed.Discriminant.InnerValue = xdrSDK.CryptoKeyType.CryptoKeyTypeEnum.KEY_TYPE_ED25519;

try
{
muxed.Ed25519 = xdrSDK.Uint256.Decode(new xdrSDK.XdrDataInputStream(DecodeStellarAccountId(data)));
}
catch (InvalidOperationException e)
{
throw new ArgumentException("invalid address: " + data, e);
}
break;

case VersionByte.MUXED_ACCOUNT:
xdrSDK.XdrDataInputStream input = new xdrSDK.XdrDataInputStream(DecodeCheck(VersionByte.MUXED_ACCOUNT, data));
muxed.Discriminant.InnerValue = xdrSDK.CryptoKeyType.CryptoKeyTypeEnum.KEY_TYPE_MUXED_ED25519;
xdrSDK.MuxedAccount.MuxedAccountMed25519 med = new xdrSDK.MuxedAccount.MuxedAccountMed25519();

try
{
med.Ed25519 = xdrSDK.Uint256.Decode(input);
med.Id = xdrSDK.Uint64.Decode(input);
}
catch (InvalidOperationException e)
{
throw new ArgumentException("invalid address: " + data, e);
}
muxed.Med25519 = med;
break;
default:
throw new FormatException("Version byte is invalid");
}
return muxed;
}

public static byte[] DecodeStellarSecretSeed(string data)
Expand Down
12 changes: 12 additions & 0 deletions stellar-dotnet-sdk/Util.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@ public static void Fill<T>(this T[] arr, T value)
arr[i] = value;
}

public static byte[] ToByteArray(ulong value)
{

byte[] result = new byte[8];
for (int i = 7; i >= 0; i--)
{
result[i] = (byte)(value & 0xffL);
value >>= 8;
}
return result;
}

public static int ComputeByteArrayHash(params byte[] data)
{
unchecked
Expand Down

0 comments on commit 6a4a53c

Please sign in to comment.