Skip to content

Commit f021ce5

Browse files
authored
Merge pull request #8 from KeetaNetwork/fix/update-naming
fix: update naming
2 parents 7ef1547 + 674d6c3 commit f021ce5

14 files changed

Lines changed: 170 additions & 18 deletions

File tree

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
# anchor-csharp
1+
# anchor-csharp - BETA
2+
3+
> Warning: This SDK is currently in beta and is subject to change without warning
24
35
C# SDK for the KeetaNet anchor. The client logic runs inside a sandboxed WebAssembly core (`keetanetwork_anchor_client_wasi.wasm`, built from [anchor-rs](https://github.com/KeetaNetwork/anchor-rs)) hosted in-process by [Wasmtime](https://github.com/bytecodealliance/wasmtime-dotnet).
46

scripts/pins.env

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
# The wasm core (scripts/build-wasm.sh).
55
ANCHOR_WASI_CRATE="keetanetwork-anchor-client-wasi"
6-
ANCHOR_WASI_VERSION="0.2.1"
7-
ANCHOR_WASI_SHA256="1eeffcc3bff2fa78caf8df7b3774a7bb183c18e52ccaabc969d7c1bcee6e3380"
6+
ANCHOR_WASI_VERSION="0.2.2"
7+
ANCHOR_WASI_SHA256="ec7e987bb55b98efca8ad071f983135161d6fd19aec7780ee563674454c1051e"
88

99
# The canonical node OpenAPI spec (scripts/generate-node-api.sh).
1010
NODE_CLIENT_CRATE="keetanetwork-client"

src/KeetaNet.Anchor/Crypto/Account.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ internal Account(WasmRuntime runtime, int handle)
1212
}
1313

1414
/// <summary>The account's textual <c>keeta_...</c> public-key string.</summary>
15-
public string PublicKeyString => Runtime.AccountAddress(Handle);
15+
public string PublicKeyString => Runtime.AccountPublicKeyString(Handle);
1616

1717
/// <summary>The account's algorithm name.</summary>
1818
public string Algorithm => Runtime.AccountAlgorithm(Handle);

src/KeetaNet.Anchor/Crypto/AccountFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public Account FromSeed(string seed, uint index, string algorithm)
2222
/// <summary>Build a read-only account from its textual <c>keeta_...</c> public-key string.</summary>
2323
public Account FromPublicKeyString(string publicKeyString)
2424
{
25-
int handle = _runtime.AccountFromAddress(publicKeyString);
25+
int handle = _runtime.AccountFromPublicKeyString(publicKeyString);
2626
return new(_runtime, handle);
2727
}
2828

src/KeetaNet.Anchor/Interop/WasmRuntime.Crypto.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ public sealed partial class WasmRuntime
1313
internal int AccountFromSeed(string seed, uint index, string algorithm) =>
1414
DerivedAccount("keeta_account_from_seed", seed, index, algorithm);
1515

16-
internal int AccountFromAddress(string address) => ParseText("keeta_account_from_address", address);
16+
internal int AccountFromPublicKeyString(string publicKeyString) =>
17+
ParseText("keeta_account_from_public_key_string", publicKeyString);
1718

1819
internal int AccountFromPrivateKey(string privateKey, string algorithm) =>
1920
AccountFromKeyMaterial("keeta_account_from_private_key", privateKey, algorithm);
@@ -66,7 +67,7 @@ internal byte[] AccountEncrypt(int handle, byte[] plaintext) =>
6667
internal byte[] AccountDecrypt(int handle, byte[] ciphertext) =>
6768
WithHandleAndBytes("keeta_account_decrypt", handle, ciphertext);
6869

69-
internal string AccountAddress(int handle) => TextOf("keeta_account_address", handle);
70+
internal string AccountPublicKeyString(int handle) => TextOf("keeta_account_public_key_string", handle);
7071

7172
internal string AccountAlgorithm(int handle) => TextOf("keeta_account_algorithm", handle);
7273

src/KeetaNet.Anchor/Interop/WasmRuntime.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,11 @@ private byte[] ReadAndFreeBytes(int handle)
552552
}
553553
}
554554

555-
/// <summary>Build an exception from the module's pending <c>code</c>/<c>message</c>.</summary>
555+
/// <summary>
556+
/// Build an exception from the module's pending <c>code</c>/<c>message</c>.
557+
/// An asset-movement blocker code carries the blocker as JSON in the
558+
/// message, surfaced typed as a <see cref="KeetaBlockerException"/>.
559+
/// </summary>
556560
private KeetaException LastError()
557561
{
558562
string code = ReadErrorPart(_lastErrorCode());
@@ -567,7 +571,7 @@ private KeetaException LastError()
567571
message = "operation failed";
568572
}
569573

570-
return new KeetaException(code, message);
574+
return KeetaBlockerException.TryDecode(code, message) ?? new KeetaException(code, message);
571575
}
572576

573577
/// <summary>Read one optional last-error part (an empty string when absent).</summary>

src/KeetaNet.Anchor/KeetaException.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ namespace KeetaNet.Anchor;
22

33
/// <summary>
44
/// A failure surfaced from the SDK (the wasm core or the node transport): a
5-
/// programmatic <see cref="Code"/> plus a human-readable message.
5+
/// programmatic <see cref="Code"/> plus a human-readable message. Failures
6+
/// that carry a typed payload derive from it, such as
7+
/// <see cref="KeetaBlockerException"/>.
68
/// </summary>
7-
public sealed class KeetaException : Exception
9+
public class KeetaException : Exception
810
{
911
/// <summary>The stable, machine-readable error code.</summary>
1012
public string Code { get; }

src/KeetaNet.Anchor/Services/AssetMovement/AssetMovementClient.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ public async Task<IReadOnlyList<AssetProvider>> GetProvidersForTransfer(
8080

8181
/// <summary>
8282
/// The provider's advertised legal disclaimers, or null when its metadata
83-
/// carries none. Malformed entries are skipped, mirroring the reference
84-
/// <c>getLegalDisclaimers</c>.
83+
/// carries none. Malformed entries are skipped.
8584
/// </summary>
8685
public IReadOnlyList<AssetDisclaimer>? GetLegalDisclaimers(AssetProvider provider)
8786
{
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System.Text.Json;
2+
3+
namespace KeetaNet.Anchor;
4+
5+
/// <summary>
6+
/// An anchor refusal carrying a typed asset-movement blocker: the operation
7+
/// cannot proceed until the user resolves <see cref="Blocker"/>.
8+
/// </summary>
9+
public sealed class KeetaBlockerException : KeetaException
10+
{
11+
/// <summary>Every recognized blocker transport code starts with this.</summary>
12+
internal const string CodePrefix = "KEETA_ANCHOR_ASSET_MOVEMENT_";
13+
14+
/// <summary>The typed blocker the user must resolve.</summary>
15+
public AssetMovementBlocker Blocker { get; }
16+
17+
private KeetaBlockerException(string code, string message, AssetMovementBlocker blocker)
18+
: base(code, message)
19+
{
20+
Blocker = blocker;
21+
}
22+
23+
/// <summary>
24+
/// Rehydrate a blocker failure from the core's last-error parts, or null
25+
/// when <paramref name="code"/> is not a blocker transport code or
26+
/// <paramref name="payload"/> does not decode as a recognized blocker.
27+
/// </summary>
28+
internal static KeetaBlockerException? TryDecode(string code, string payload)
29+
{
30+
if (!code.StartsWith(CodePrefix, StringComparison.Ordinal))
31+
{
32+
return null;
33+
}
34+
35+
AssetMovementBlocker? blocker;
36+
try
37+
{
38+
blocker = JsonSerializer.Deserialize<AssetMovementBlocker>(payload, KeetaJson.Options);
39+
}
40+
catch (JsonException)
41+
{
42+
return null;
43+
}
44+
45+
if (blocker is null || Describe(blocker) is not { } summary)
46+
{
47+
return null;
48+
}
49+
50+
return new KeetaBlockerException(code, summary, blocker);
51+
}
52+
53+
/// <summary>
54+
/// A human-readable summary of what the user must resolve, or null for a
55+
/// shape that does not surface typed.
56+
/// </summary>
57+
private static string? Describe(AssetMovementBlocker blocker) =>
58+
blocker switch
59+
{
60+
AssetKycShareNeededBlocker => "the provider requires KYC attributes to be shared first",
61+
AssetAdditionalKycNeededBlocker => "the provider requires additional KYC steps",
62+
AssetOperationNotSupportedBlocker => "the provider does not support this operation",
63+
AssetUserActionNeededBlocker => "the provider requires on-ledger user actions",
64+
_ => null,
65+
};
66+
}

tests/KeetaNet.Anchor.E2eTests/AssetFlowTests.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,25 @@ await Assert.ThrowsAsync<KeetaException>(
287287
session.Shutdown();
288288
}
289289

290+
[Fact]
291+
public async Task ARefusedShareSurfacesTheTypedKycBlocker()
292+
{
293+
using var session = AssetSession.Open();
294+
(AssetMovementClient client, AssetAnchor anchor, CancellationToken cancellationToken) = session;
295+
AssetProvider provider = await session.DiscoveredProviderAsync();
296+
297+
// The anchor refuses the magic attributes with a 403 blocker envelope
298+
KeetaBlockerException refusal = await Assert.ThrowsAsync<KeetaBlockerException>(
299+
() => client.ShareKycAttributes(provider, new AssetShareKycRequest("blocked"), cancellationToken));
300+
301+
Assert.Equal("KEETA_ANCHOR_ASSET_MOVEMENT_KYC_SHARE_NEEDED", refusal.Code);
302+
var share = Assert.IsType<AssetKycShareNeededBlocker>(refusal.Blocker);
303+
Assert.Equal(BlockedAttributes, share.NeededAttributes);
304+
Assert.Equal(new[] { anchor.SendToAddress }, share.ShareWithPrincipals);
305+
306+
session.Shutdown();
307+
}
308+
290309
/// <summary>A push transfer moving the base token from the EVM location to Keeta.</summary>
291310
private static AssetTransferRequest PushTransfer(AssetAnchor anchor, object? recipient) =>
292311
new(

0 commit comments

Comments
 (0)