Skip to content
Open
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
45 changes: 45 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Build, Test and Publish Package

on:
push:
tags:
- v*
branches:
- main
- feature/*

jobs:
build:
runs-on: ubuntu-latest
env:
DOTNET_VERSION: '6.0.x'
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Setup dotnet
uses: actions/setup-dotnet@v1
with:
dotnet-version: ${{ env.DOTNET_VERSION }}

- name: Restore dependencies
shell: bash
run: dotnet restore

- name: Build
shell: bash
run: dotnet build --no-restore -c Release

- name: Test
shell: bash
run: dotnet test --no-build --verbosity normal -c Release

- name: Publish package
shell: bash
run: dotnet publish --no-build Src/Mintsafe.SaleWorker/Mintsafe.SaleWorker.csproj -c Release -o release --nologo
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -452,3 +452,5 @@ $RECYCLE.BIN/
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

appsettings.Local.json
Binary file added CONTRIBUTING.md
Binary file not shown.
52 changes: 52 additions & 0 deletions Deploy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Deployment Guide

## Mintsafe.SaleWorker
The SaleWorker is a BackgroundService that should be published as a single executable with the appropriate config files.

### Publish Single Executable
```
dotnet publish -r linux-x64 Src/SaleWorker/Mintsafe.SaleWorker.csproj -c Release -o release -p:PublishSingleFile=true --self-contained true
```

### Update Config
Go to the `release` folder, update the `hostsettings.json` and `appsettings.{environment}.json` config files accordingly depending on your requirements.

### Transfer files to instance
```
scp -i ssh.pem release/* {USER}@{INSTANCE}:/home/{USER}/{FILES}
```

### Create Service File
```
touch mintsafe.saleworker.service
echo "[Unit]" >> mintsafe.saleworker.service
echo "Description=Mintsafe.SaleWorker Service TACF" >> mintsafe.saleworker.service
echo "" >> mintsafe.saleworker.service
echo "[Service]" >> mintsafe.saleworker.service
echo "WorkingDirectory=/home/user/mintsafe/saleworker" >> mintsafe.saleworker.service
echo "ExecStart=/home/user/mintsafe/saleworker/mintsafe.saleworker" >> mintsafe.saleworker.service
echo "" >> mintsafe.saleworker.service
echo "Restart=on-failure" >> mintsafe.saleworker.service
echo "RestartSec=10" >> mintsafe.saleworker.service
echo "KillSignal=SIGINT" >> mintsafe.saleworker.service
echo "RestartKillSignal=SIGINT" >> mintsafe.saleworker.service
echo "" >> mintsafe.saleworker.service
echo "StandardOutput=journal" >> mintsafe.saleworker.service
echo "StandardError=journal" >> mintsafe.saleworker.service
echo "SyslogIdentifier=mintsafe.saleworker.tacf" >> mintsafe.saleworker.service
echo "" >> mintsafe.saleworker.service
echo "User=ss" >> mintsafe.saleworker.service
echo "Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false" >> mintsafe.saleworker.service
echo "" >> mintsafe.saleworker.service
echo "[Install]" >> mintsafe.saleworker.service
echo "WantedBy=multi-user.target" >> mintsafe.saleworker.service
chmod 400 mintsafe.saleworker.service
sudo cp mintsafe.saleworker.service /etc/systemd/system/
```

### Start Service
```
sudo systemctl start mintsafe.saleworker.service
sudo systemctl enable mintsafe.saleworker.service
sudo systemctl status mintsafe.saleworker.service
```
13 changes: 13 additions & 0 deletions Mintsafe.sln
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C51E32B4-D9A9-480B-8C70-5AE9812A7BF0}"
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
.github\workflows\build.yaml = .github\workflows\build.yaml
CONTRIBUTING.md = CONTRIBUTING.md
README.md = README.md
EndProjectSection
EndProject
Expand All @@ -37,6 +39,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{610719E3
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mintsafe.DataImporter", "Src\DataImporter\Mintsafe.DataImporter.csproj", "{BF3C0082-4D79-4307-9988-FD4D513D028A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CardanoSharp.Wallet", "..\cardanosharp-wallet\CardanoSharp.Wallet\CardanoSharp.Wallet.csproj", "{C46A2637-A636-41F8-8CF4-F71562CDE785}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Deploy", "Deploy", "{F7454B84-B79D-4359-9202-1ADB836359FB}"
ProjectSection(SolutionItems) = preProject
Deploy\README.md = Deploy\README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -83,6 +92,10 @@ Global
{BF3C0082-4D79-4307-9988-FD4D513D028A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF3C0082-4D79-4307-9988-FD4D513D028A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF3C0082-4D79-4307-9988-FD4D513D028A}.Release|Any CPU.Build.0 = Release|Any CPU
{C46A2637-A636-41F8-8CF4-F71562CDE785}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C46A2637-A636-41F8-8CF4-F71562CDE785}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C46A2637-A636-41F8-8CF4-F71562CDE785}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C46A2637-A636-41F8-8CF4-F71562CDE785}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
104 changes: 91 additions & 13 deletions Src/Abstractions/CardanoTypes.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,112 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace Mintsafe.Abstractions;

public enum Network { Mainnet, Testnet }

public static class Assets
{
public const string LovelaceUnit = "lovelace";
}

public record struct Value(string Unit, long Quantity);
public record struct Value(string Unit, ulong Quantity);

public record Utxo(string TxHash, int OutputIndex, Value[] Values)
{
public override int GetHashCode() => ToString().GetHashCode();
public override string ToString() => $"{TxHash}__{OutputIndex}";
public override string ToString() => $"{TxHash}_{OutputIndex}";
bool IEquatable<Utxo>.Equals(Utxo? other) => other != null && TxHash == other.TxHash && OutputIndex == other.OutputIndex;
public long Lovelaces => Values.First(v => v.Unit == Assets.LovelaceUnit).Quantity;
public ulong Lovelaces => Values.First(v => v.Unit == Assets.LovelaceUnit).Quantity;
}

// TODO: Ideal types
public record struct NativeAssetValue(string PolicyId, string AssetName, ulong Quantity);

public record struct Balance(ulong Lovelaces, NativeAssetValue[] NativeAssets);

public record struct PendingTransactionOutput(string Address, Balance Value);

public record UnspentTransactionOutput(string TxHash, uint OutputIndex, Balance Value)
{
public override int GetHashCode() => ToString().GetHashCode();
public override string ToString() => $"{TxHash}_{OutputIndex}";
bool IEquatable<UnspentTransactionOutput>.Equals(UnspentTransactionOutput? other)
=> other != null && TxHash == other.TxHash && OutputIndex == other.OutputIndex;
public ulong Lovelaces => Value.Lovelaces;
}
public record TransactionSummary(string TxHash, TransactionIo[] Inputs, TransactionIo[] Outputs);
public record TransactionIo(string Address, int OutputIndex, Balance Values);

public record TxIo(string Address, int OutputIndex, Value[] Values);
public record BasicMintingPolicy(string[] PolicySigningKeysAll, uint ExpirySlot);
public record Mint(BasicMintingPolicy BasicMintingPolicy, NativeAssetValue[] NativeAssetsToMint);

public record ProtocolParams(uint MajorVersion, uint MinorVersion, uint MinFeeA, uint MinFeeB, uint CoinsPerUtxoWord);
public record NetworkContext(uint LatestSlot, ProtocolParams ProtocolParams);

public record BuildTransactionCommand(
UnspentTransactionOutput[] Inputs,
PendingTransactionOutput[] Outputs,
Mint[] Mint,
Dictionary<int, Dictionary<string, object>> Metadata,
string[] PaymentSigningKeys,
Network Network,
uint TtlTipOffsetSlots = 5400);

public record RewardsWithdrawal(string StakeAddress, uint RewardLovelaces);

public record BuildTxCommand(
UnspentTransactionOutput[] Inputs,
PendingTransactionOutput[] Outputs,
Network Network,
NativeAssetValue[]? Mint = null,
Dictionary<int, Dictionary<string, object>>? Metadata = null,
RewardsWithdrawal[]? RewardsWithdrawals = null,
SimpleScript[]? SimpleScripts = null,
string[]? SigningKeys = null,
uint TtlTipOffsetSlots = 7200);

public record BuiltTransaction(string TxHash, byte[] CborBytes);

public record TxIo(string Address, uint OutputIndex, Value[] Values);

public record TxInfo(string TxHash, TxIo[] Inputs, TxIo[] Outputs);

public record TxBuildOutput(string Address, Value[] Values, bool IsFeeDeducted = false);
public record TxBuildOutput(string Address, Balance Values, bool IsFeeDeducted = false);

public enum NativeScriptType { PubKeyHash = 0, All, Any, AtLeast, InvalidBefore, InvalidAfter }
public record SimpleScript(
NativeScriptType Type,
uint? AtLeast = null,
SimpleScript[]? Scripts = null,
string? PubKeyHash = null,
uint? InvalidBefore = null,
uint? InvalidAfter = null);

public record TxBuildCommand(
Utxo[] Inputs,
TxBuildOutput[] Outputs,
Value[] Mint,
string MintingScriptPath,
string MetadataJsonPath,
long TtlSlot,
string[] SigningKeyFiles);
//public interface INativeScript { }
//public class ScriptPubKey : INativeScript
//{
// public byte[] KeyHash { get; init; }
//}
//public class ScriptInvalidAfter : INativeScript
//{
// public ulong After { get; init; }
//}
//public class ScriptInvalidBefore : INativeScript
//{
// public ulong Before { get; init; }
//}
//public class ScriptAll : INativeScript
//{
// public INativeScript[] Scripts { get; init; }
//}
//public class ScriptAny : INativeScript
//{
// public INativeScript[] Scripts { get; init; }
//}
//public class ScriptNofK : INativeScript
//{
// public int N { get; init; }
// public INativeScript[] Scripts { get; init; }
//}
23 changes: 21 additions & 2 deletions Src/Abstractions/IBlockfrostClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ namespace Mintsafe.Abstractions;

public interface IBlockfrostClient
{
Task<BlockfrostLatestBlock> GetLatestBlockAsync(CancellationToken ct = default);
Task<BlockfrostProtocolParameters> GetLatestProtocolParameters(CancellationToken ct = default);
Task<BlockFrostTransactionUtxoResponse> GetTransactionAsync(string txHash, CancellationToken ct = default);
Task<BlockFrostAddressUtxo[]> GetUtxosAtAddressAsync(string address, CancellationToken ct = default);
Task<string> SubmitTransactionAsync(byte[] txSignedBinary, CancellationToken ct = default);
Expand All @@ -27,6 +29,23 @@ public BlockfrostResponseException(
}
}

public class BlockfrostLatestBlock
{
public uint? Epoch { get; init; }
public uint? Slot { get; init; }
public uint? Height { get; init; }
public string? Hash { get; init; }
}

public class BlockfrostProtocolParameters
{
public uint? Protocol_major_ver { get; init; }
public uint? Protocol_minor_ver { get; init; }
public uint? Min_fee_a { get; init; }
public uint? Min_fee_b { get; init; }
public string? Coins_per_utxo_word { get; init; }
}

public class BlockFrostValue
{
public string? Unit { get; init; }
Expand All @@ -36,7 +55,7 @@ public class BlockFrostValue
public class BlockFrostTransactionIo
{
public string? Address { get; init; }
public int Output_Index { get; init; }
public uint Output_Index { get; init; }
public BlockFrostValue[]? Amount { get; init; }
}

Expand All @@ -50,6 +69,6 @@ public class BlockFrostTransactionUtxoResponse
public class BlockFrostAddressUtxo
{
public string? Tx_hash { get; init; }
public int Output_index { get; init; }
public uint Output_index { get; init; }
public BlockFrostValue[]? Amount { get; init; }
}
12 changes: 12 additions & 0 deletions Src/Abstractions/IMintingKeychainRetriever.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Mintsafe.Abstractions;
using System.Threading;
using System.Threading.Tasks;

namespace Mintsafe.Abstractions;

public interface IMintingKeychainRetriever
{
Task<MintingKeyChain> GetMintingKeyChainAsync(
SaleContext saleContext,
CancellationToken ct = default);
}
9 changes: 9 additions & 0 deletions Src/Abstractions/INetworkContextRetriever.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Threading;
using System.Threading.Tasks;

namespace Mintsafe.Abstractions;

public interface INetworkContextRetriever
{
Task<NetworkContext> GetNetworkContext(CancellationToken ct = default);
}
5 changes: 3 additions & 2 deletions Src/Abstractions/INiftyDataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Mintsafe.Abstractions;

public interface INiftyDataService
{
public Task<CollectionAggregate?> GetCollectionAggregateAsync(Guid collectionId, CancellationToken ct = default);
Task InsertCollectionAggregateAsync(CollectionAggregate collectionAggregate, CancellationToken ct = default);
public Task<ProjectAggregate?> GetCollectionAggregateAsync(Guid collectionId, CancellationToken ct = default);
public Task<SaleAggregate?> GetSaleAggregateAsync(Guid saleId, CancellationToken ct = default);
Task InsertCollectionAggregateAsync(ProjectAggregate collectionAggregate, CancellationToken ct = default);
}
1 change: 1 addition & 0 deletions Src/Abstractions/INiftyDistributor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ Task<NiftyDistributionResult> DistributeNiftiesForSalePurchase(
Nifty[] allocatedNfts,
PurchaseAttempt purchaseRequest,
SaleContext saleContext,
NetworkContext networkContext,
CancellationToken ct = default);
}
5 changes: 4 additions & 1 deletion Src/Abstractions/ISaleAllocationStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ namespace Mintsafe.Abstractions
public interface ISaleAllocationStore
{
Task<SaleContext> GetOrRestoreSaleContextAsync(
CollectionAggregate collectionAggregate, Guid workerId, CancellationToken ct);
ProjectAggregate collectionAggregate, Guid workerId, CancellationToken ct);

Task<SaleContext> GetOrRestoreSaleContextAsync(
SaleAggregate saleAggregate, Guid workerId, CancellationToken ct);

Task<Nifty[]> AllocateNiftiesAsync(
PurchaseAttempt request, SaleContext context, CancellationToken ct);
Expand Down
12 changes: 8 additions & 4 deletions Src/Abstractions/ITxBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@

namespace Mintsafe.Abstractions;

public interface ITxBuilder
public interface IMintTransactionBuilder
{
public Task<byte[]> BuildTxAsync(
TxBuildCommand buildCommand,
CancellationToken ct = default);
BuiltTransaction BuildTx(
BuildTransactionCommand buildCommand,
NetworkContext networkContext);

BuiltTransaction BuildTx(
BuildTxCommand buildCommand,
NetworkContext networkContext);
}
Loading