Skip to content
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
2 changes: 1 addition & 1 deletion csharp/src/Workflow.Solana/Helpers/EventDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
using System.Numerics;
using Train.Solver.Blockchain.Solana.Extensions;
using Train.Solver.Blockchain.Solana.Models;
using Train.Solver.Blockchain.Solana.Programs.HTLCProgram;
using Train.Solver.Infrastructure.Abstractions.Models;
using Train.Solver.Workflow.Abstractions.Models;
using Train.Solver.Workflow.Solana.Programs.HTLCProgram;

namespace Train.Solver.Blockchain.Solana.Helpers;

Expand Down
83 changes: 53 additions & 30 deletions csharp/src/Workflow.Solana/Helpers/SolanaTransactionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
using Solnet.Rpc.Builders;
using Solnet.Wallet;
using System.Numerics;
using Train.Solver.Blockchain.Solana.Programs.HTLCProgram;
using Train.Solver.Blockchain.Solana.Programs.HTLCProgram.Models;
using Train.Solver.Common.Extensions;
using Train.Solver.Data.Abstractions.Entities;
using Train.Solver.Infrastructure.Abstractions.Models;
using Train.Solver.Workflow.Abstractions.Models;
using Train.Solver.Workflow.Solana.Programs.HTLCProgram;
using Train.Solver.Workflow.Solana.Programs.HTLCProgram.Models;

namespace Train.Solver.Workflow.Solana.Helpers;

Expand Down Expand Up @@ -66,30 +66,53 @@ await GetOrCreateAssociatedTokenAccount(
new PublicKey(solverAccount),
new PublicKey(solverAccount));

builder.SetLockTransactionInstruction(
new PublicKey(htlcContractAddress),
new HTLCLockRequest
{
Hashlock = request.Hashlock.HexToByteArray(),
Id = request.CommitId.HexToByteArray(),
SignerPublicKey = new PublicKey(solverAccount),
ReceiverPublicKey = new PublicKey(request.Receiver),
Amount = request.Amount,
Timelock = new BigInteger(request.Timelock),
SourceAsset = currency.Symbol,
DestinationNetwork = request.DestinationNetwork,
SourceAddress = request.DestinationAddress,
DestinationAsset = request.DestinationAsset,
SourceTokenPublicKey = new PublicKey(currency.Contract),
Reward = request.Reward,
RewardTimelock = new BigInteger(request.RewardTimelock),
});
if (isNative)
{
builder.SetSolLockTransactionInstruction(
new PublicKey(htlcContractAddress),
new HTLCSplLockRequest
{
Id = request.CommitId.HexToByteArray(),
Hashlock = request.Hashlock.HexToByteArray(),
Timelock = new BigInteger(request.Timelock),
Amount = request.Amount,
DestinationNetwork = request.DestinationNetwork,
DestinationAsset = request.DestinationAsset,
SourceAsset = currency.Symbol,
SignerPublicKey = new PublicKey(solverAccount),
ReceiverPublicKey = new PublicKey(request.Receiver),
DestinationAddress = request.DestinationAddress,
Reward = request.Reward,
RewardTimelock = new BigInteger(request.RewardTimelock),
});
}
else
{
builder.SetSplLockTransactionInstruction(
new PublicKey(htlcContractAddress),
new HTLCSplLockRequest
{
Id = request.CommitId.HexToByteArray(),
Hashlock = request.Hashlock.HexToByteArray(),
Timelock = new BigInteger(request.Timelock),
Amount = request.Amount,
DestinationNetwork = request.DestinationNetwork,
DestinationAsset = request.DestinationAsset,
SourceAsset = currency.Symbol,
SignerPublicKey = new PublicKey(solverAccount),
ReceiverPublicKey = new PublicKey(request.Receiver),
DestinationAddress = request.DestinationAddress,
SourceTokenPublicKey = new PublicKey(currency.Contract),
Reward = request.Reward,
RewardTimelock = new BigInteger(request.RewardTimelock),
});
}

var latestBlockResult = await rpcClient.GetLatestBlockHashAsync();

if (!latestBlockResult.WasSuccessful)
{
throw new ($"Failed to get last valid block");
throw new($"Failed to get last valid block");
}

builder.SetRecentBlockHash(latestBlockResult.Result.Value.Blockhash);
Expand Down Expand Up @@ -133,7 +156,7 @@ public static async Task<PrepareTransactionDto> BuildHTLCRedeemTransactionAsync(
{
throw new ArgumentNullException(nameof(request.SenderAddress), "Sender address is required");
}

var currency = network.Tokens.SingleOrDefault(x => x.Symbol.ToUpper() == request.Asset.ToUpper());

if (currency is null)
Expand All @@ -160,12 +183,12 @@ public static async Task<PrepareTransactionDto> BuildHTLCRedeemTransactionAsync(
var builder = new TransactionBuilder()
.SetFeePayer(new PublicKey(solverAccount));

await GetOrCreateAssociatedTokenAccount(
rpcClient,
builder,
currency,
new PublicKey(solverAccount),
new PublicKey(solverAccount));
await GetOrCreateAssociatedTokenAccount(
rpcClient,
builder,
currency,
new PublicKey(solverAccount),
new PublicKey(solverAccount));

builder.SetRedeemTransactionInstruction(
new PublicKey(htlcContractAddress),
Expand All @@ -177,7 +200,7 @@ await GetOrCreateAssociatedTokenAccount(
SignerPublicKey = new PublicKey(solverAccount),
ReceiverPublicKey = new PublicKey(request.DestinationAddress),
SenderPublicKey = new PublicKey(request.SenderAddress),
RewardPublicKey = request.DestinationAddress == solverAccount?
RewardPublicKey = request.DestinationAddress == solverAccount ?
new PublicKey(request.DestinationAddress) :
new PublicKey(request.SenderAddress),
});
Expand Down Expand Up @@ -535,5 +558,5 @@ private static async Task GetOrCreateAssociatedTokenAccount(
{
throw new Exception("Failed to load token wallet", ex);
}
}
}
}
68 changes: 58 additions & 10 deletions csharp/src/Workflow.Solana/Programs/HTLCProgram/HTLCProgram.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
using System.Text;
using Solnet.Rpc.Builders;
using Solnet.Wallet;
using Train.Solver.Blockchain.Solana.Programs;
using Train.Solver.Blockchain.Solana.Programs.HTLCProgram;
using Train.Solver.Blockchain.Solana.Programs.HTLCProgram.Models;
using Train.Solver.Workflow.Solana.Programs.HTLCProgram.Models;

namespace Train.Solver.Blockchain.Solana.Programs.HTLCProgram;
namespace Train.Solver.Workflow.Solana.Programs.HTLCProgram;

public static class HTLCProgram
{
public static TransactionBuilder SetLockTransactionInstruction(
public static TransactionBuilder SetSplLockTransactionInstruction(
this TransactionBuilder builder,
PublicKey htlcProgramIdKey,
HTLCLockRequest htlcLockRequest)
HTLCSplLockRequest htlcLockRequest)
{
var htlcPdaParams = GetHtlcPdaParams(htlcLockRequest.Id, htlcProgramIdKey);
var htlcPdaParams = GetSPLHtlcPdaParams(htlcLockRequest.Id, htlcProgramIdKey);

var lockData = new HtlcInstructionDataBuilder().CreateLockData(htlcLockRequest);
var lockRewardData = new HtlcInstructionDataBuilder().CreateLockRewardData(htlcLockRequest);
Expand All @@ -21,7 +24,7 @@ public static TransactionBuilder SetLockTransactionInstruction(
builder.AddInstruction(new()
{
ProgramId = htlcProgramIdKey,
Keys = HtlcInstructionKeyProvider.CreateLockAccountKeys(htlcLockRequest, htlcPdaParams),
Keys = HtlcInstructionKeyProvider.CreateSplLockAccountKeys(htlcLockRequest, htlcPdaParams),
Data = lockData

});
Expand All @@ -36,12 +39,38 @@ public static TransactionBuilder SetLockTransactionInstruction(
return builder;
}

public static TransactionBuilder SetSolLockTransactionInstruction(
this TransactionBuilder builder,
PublicKey htlcProgramIdKey,
HTLCSolLockRequest htlcLockRequest)
{
var pdaParams = GetSolHtlcParams(htlcLockRequest.Id, htlcProgramIdKey);

var lockData = new HtlcInstructionDataBuilder().CreateLockData(htlcLockRequest);
var lockRewardData = new HtlcInstructionDataBuilder().CreateLockRewardData(htlcLockRequest);

builder.AddInstruction(new()
{
ProgramId = htlcProgramIdKey,
Keys = HtlcInstructionKeyProvider.CreateSolLockAccountKeys(htlcLockRequest, pdaParams),
Data = lockData
});

builder.AddInstruction(new()
{
ProgramId = htlcProgramIdKey,
Keys = HtlcInstructionKeyProvider.CreateSolLockRewardAccountKeys(htlcLockRequest, pdaParams),
Data = lockRewardData
});
return builder;
}

public static TransactionBuilder SetRedeemTransactionInstruction(
this TransactionBuilder builder,
PublicKey htlcProgramIdKey,
HTLCRedeemRequest redeemRequest)
{
var pdaParams = GetHtlcPdaParams(redeemRequest.Id, htlcProgramIdKey);
var pdaParams = GetSPLHtlcPdaParams(redeemRequest.Id, htlcProgramIdKey);

var redeemData = new HtlcInstructionDataBuilder().CreateRedeemData(redeemRequest, pdaParams);

Expand All @@ -60,7 +89,7 @@ public static TransactionBuilder SetRefundTransactionInstruction(
PublicKey htlcProgramIdKey,
HTLCRefundRequest htlcRefundRequest)
{
var pdaParams = GetHtlcPdaParams(htlcRefundRequest.Id, htlcProgramIdKey);
var pdaParams = GetSPLHtlcPdaParams(htlcRefundRequest.Id, htlcProgramIdKey);

var refundData = new HtlcInstructionDataBuilder().CreateRefundData(htlcRefundRequest, pdaParams);

Expand All @@ -79,7 +108,7 @@ public static TransactionBuilder SetAddLockSigInstruction(
PublicKey htlcProgramIdKey,
HTLCAddlocksigRequest htlcAddlocksigRequest)
{
var pdaParams = GetHtlcPdaParams(htlcAddlocksigRequest.AddLockSigMessageRequest.Id, htlcProgramIdKey);
var pdaParams = GetSPLHtlcPdaParams(htlcAddlocksigRequest.AddLockSigMessageRequest.Id, htlcProgramIdKey);
var message = Ed25519Program.CreateAddLockSigMessage(htlcAddlocksigRequest.AddLockSigMessageRequest);
var addLockSigData = new HtlcInstructionDataBuilder().CreateAddLockSigData(htlcAddlocksigRequest, pdaParams);

Expand All @@ -103,7 +132,7 @@ public static TransactionBuilder SetGetDetailsInstruction(
PublicKey htlcProgramIdKey,
byte[] id)
{
var pdaParams = GetHtlcPdaParams(id, htlcProgramIdKey);
var pdaParams = GetSPLHtlcPdaParams(id, htlcProgramIdKey);

var getDetailsData = new HtlcInstructionDataBuilder().CreateGetDetailsData(pdaParams, id);

Expand All @@ -117,7 +146,7 @@ public static TransactionBuilder SetGetDetailsInstruction(
return builder;
}

private static HTLCPdaResponse GetHtlcPdaParams(
private static HTLCSplPdaResponse GetSPLHtlcPdaParams(
byte[] Id,
PublicKey htlcProgramIdKey)
{
Expand Down Expand Up @@ -147,4 +176,23 @@ private static HTLCPdaResponse GetHtlcPdaParams(
HtlcBump = htlcBump
};
}

private static HTLCSolPdaResponse GetSolHtlcParams(
byte[] Id,
PublicKey htlcProgramIdKey)
{
var htlc = PublicKey.TryFindProgramAddress(
new List<byte[]>()
{
Id
},
htlcProgramIdKey,
out PublicKey htlcPubKey,
out _);

return new()
{
HtlcPublicKey = htlcPubKey
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Text;
using Train.Solver.Blockchain.Solana.Helpers;
using Train.Solver.Blockchain.Solana.Programs.HTLCProgram.Models;
using Train.Solver.Workflow.Solana.Programs.HTLCProgram.Models;

namespace Train.Solver.Blockchain.Solana.Programs.HTLCProgram;

Expand All @@ -19,21 +20,21 @@ private void SetFieldData(string property, int span, Action<object, byte[], int>
Span = span,
EncoderFunc = encoderFunc
});
}
}

public byte[] CreateLockData(
HTLCLockRequest lockRequest)
HTLCSolLockRequest lockRequest)
{
var destinationAssetData = Encoding.UTF8.GetBytes(lockRequest.DestinationAsset);
var sourceAddressData = Encoding.UTF8.GetBytes(lockRequest.SourceAddress);
var destionationAddressData = Encoding.UTF8.GetBytes(lockRequest.DestinationAddress);
var destinationNetworkData = Encoding.UTF8.GetBytes(lockRequest.DestinationNetwork);
var sourceAssetData = Encoding.UTF8.GetBytes(lockRequest.SourceAsset);

SetFieldData("id", lockRequest.Id.Length, (v, buf, off) => FieldEncoder.EncodeByteArray((byte[])v, buf, ref off));
SetFieldData("hashlock", lockRequest.Hashlock.Length, (v, buf, off) => FieldEncoder.EncodeByteArray((byte[])v, buf, ref off));
SetFieldData("timelock", 8, (v, buf, off) => buf.WriteBigInt((BigInteger)v, off, 8, isUnsigned: true, isBigEndian: false));
SetFieldData("destinationNetwork", destinationNetworkData.Length + 4, (v, buf, off) => FieldEncoder.EncodeByteArrayWithLength((byte[])v, buf, ref off));
SetFieldData("sourceAddress", sourceAddressData.Length + 4, (v, buf, off) => FieldEncoder.EncodeByteArrayWithLength((byte[])v, buf, ref off));
SetFieldData("destinationAddress", destionationAddressData.Length + 4, (v, buf, off) => FieldEncoder.EncodeByteArrayWithLength((byte[])v, buf, ref off));
SetFieldData("destinationAsset", destinationAssetData.Length + 4, (v, buf, off) => FieldEncoder.EncodeByteArrayWithLength((byte[])v, buf, ref off));
SetFieldData("sourceAsset", sourceAssetData.Length + 4, (v, buf, off) => FieldEncoder.EncodeByteArrayWithLength((byte[])v, buf, ref off));
SetFieldData("receiver", 32, (v, buf, off) => buf.WritePubKey((PublicKey)v, off));
Expand All @@ -45,7 +46,7 @@ public byte[] CreateLockData(
{ "hashlock", lockRequest.Hashlock},
{ "timelock", lockRequest.Timelock},
{ "destinationNetwork", destinationNetworkData },
{ "sourceAddress", sourceAddressData },
{ "destinationAddress", destionationAddressData },
{ "destinationAsset", destinationAssetData },
{ "sourceAsset", sourceAssetData },
{ "receiver", lockRequest.ReceiverPublicKey },
Expand All @@ -58,7 +59,7 @@ public byte[] CreateLockData(
}

public byte[] CreateLockRewardData(
HTLCLockRequest lockRequest)
HTLCSolLockRequest lockRequest)
{
SetFieldData("id", lockRequest.Id.Length, (v, buf, off) => FieldEncoder.EncodeByteArray((byte[])v, buf, ref off));
SetFieldData("rewardTimelock", 8, (v, buf, off) => buf.WriteBigInt((BigInteger)v, off, 8, isUnsigned: true, isBigEndian: false));
Expand All @@ -78,7 +79,7 @@ public byte[] CreateLockRewardData(

public byte[] CreateRedeemData(
HTLCRedeemRequest redeemRequest,
HTLCPdaResponse htlcPdaResponse)
HTLCSplPdaResponse htlcPdaResponse)
{
SetFieldData("id", redeemRequest.Id.Length, (v, buf, off) => FieldEncoder.EncodeByteArray((byte[])v, buf, ref off));
SetFieldData("secret", redeemRequest.Secret.Length, (v, buf, off) => FieldEncoder.EncodeByteArray((byte[])v, buf, ref off));
Expand All @@ -99,7 +100,7 @@ public byte[] CreateRedeemData(

public byte[] CreateRefundData(
HTLCRefundRequest refundRequest,
HTLCPdaResponse htlcPdaResponse)
HTLCSplPdaResponse htlcPdaResponse)
{
SetFieldData("id", refundRequest.Id.Length, (v, buf, off) => FieldEncoder.EncodeByteArray((byte[])v, buf, ref off));
SetFieldData("htlcBump", 1, (v, buf, off) => buf.WriteU8((byte)v, off));
Expand All @@ -116,7 +117,7 @@ public byte[] CreateRefundData(
}

public byte[] CreateGetDetailsData(
HTLCPdaResponse hTLCPdaResponse,
HTLCSplPdaResponse hTLCPdaResponse,
byte[] id)
{
SetFieldData("id", id.Length, (v, buf, off) => FieldEncoder.EncodeByteArray((byte[])v, buf, ref off));
Expand All @@ -135,7 +136,7 @@ public byte[] CreateGetDetailsData(

public byte[] CreateAddLockSigData(
HTLCAddlocksigRequest addLockSigRequest,
HTLCPdaResponse htlcPdaResponse)
HTLCSplPdaResponse htlcPdaResponse)
{
SetFieldData("id", addLockSigRequest.AddLockSigMessageRequest.Id.Length, (v, buf, off) => FieldEncoder.EncodeByteArray((byte[])v, buf, ref off));
SetFieldData("hashlock", addLockSigRequest.AddLockSigMessageRequest.Hashlock.Length, (v, buf, off) => FieldEncoder.EncodeByteArray((byte[])v, buf, ref off));
Expand All @@ -155,7 +156,6 @@ public byte[] CreateAddLockSigData(
FieldEncoder.Sighash(SolanaConstants.AddLockSigSighash));
}


private byte[] BuildInstructionData(Dictionary<string, object> instructionExecutionOrder, byte[] descriminator)
{
return FieldEncoder.Encode(Fields, instructionExecutionOrder, descriminator);
Expand Down
Loading