Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SVR-298] 던전점령권 판매 기능 추가 #160

Merged
merged 4 commits into from
Apr 16, 2024
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
50 changes: 50 additions & 0 deletions backend/app/Savor22b.Tests/Action/SellDungeonConquestTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@

namespace Savor22b.Tests.Action;

using Libplanet.State;
using Savor22b.Action;
using Savor22b.States;
using Xunit;

public class SellDungeonConquestTests : ActionTests
{
public static int TestDungeonId = 1;

public SellDungeonConquestTests() { }

[Fact]
public void Execute_Success_Normal()
{
var beforeState = CreatePresetStateDelta();

SellDungeonConquest action = new SellDungeonConquest(TestDungeonId);

IAccountStateDelta afterState = action.Execute(
new DummyActionContext
{
PreviousStates = beforeState,
Signer = SignerAddress(),
Random = random,
Rehearsal = false,
BlockIndex = 1,
}
);

var afterGlobalDungeonState = DeriveGlobalDungeonStateDelta(afterState);

Assert.False(afterGlobalDungeonState.IsDungeonConquestAddress(TestDungeonId, SignerAddress()));
}

private IAccountStateDelta CreatePresetStateDelta()
{
IAccountStateDelta state = new DummyState();

GlobalDungeonState globalDungeonState = state.GetState(GlobalDungeonState.StateAddress) is Bencodex.Types.Dictionary globalDungeonStateEncoded
? new GlobalDungeonState(globalDungeonStateEncoded)
: new GlobalDungeonState();

globalDungeonState = globalDungeonState.SetDungeonConquestAddress(TestDungeonId, SignerAddress());

return state.SetState(GlobalDungeonState.StateAddress, globalDungeonState.Serialize());
}
}
73 changes: 73 additions & 0 deletions backend/app/Savor22b/Action/SellDungeonConquest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
namespace Savor22b.Action;

using System.Collections.Immutable;
using Bencodex.Types;
using Libplanet.Action;
using Libplanet.Headless.Extensions;
using Libplanet.State;
using Savor22b.Action.Exceptions;
using Savor22b.States;
using Savor22b.Model;
using Libplanet.Assets;

[ActionType(nameof(SellDungeonConquest))]
public class SellDungeonConquest : SVRAction
{
public int DungeonId { get; private set; }

public SellDungeonConquest() { }

public SellDungeonConquest(int dungeonId)
{
DungeonId = dungeonId;
}

protected override IImmutableDictionary<string, IValue> PlainValueInternal =>
new Dictionary<string, IValue>()
{
[nameof(DungeonId)] = DungeonId.Serialize(),
}.ToImmutableDictionary();

protected override void LoadPlainValueInternal(IImmutableDictionary<string, IValue> plainValue)
{
DungeonId = plainValue[nameof(DungeonId)].ToInteger();
}

private Dungeon GetDungeonInCsv(int dungeonId)
{
Dungeon? dungeon = CsvDataHelper.GetDungeonById(dungeonId);

if (dungeon == null)
{
throw new InvalidDungeonException($"Invalid dungeon ID: {dungeonId}");
}

return dungeon;
}

public override IAccountStateDelta Execute(IActionContext ctx)
{
if (ctx.Rehearsal)
{
return ctx.PreviousStates;
}

IAccountStateDelta states = ctx.PreviousStates;

GlobalDungeonState globalDungeonState = states.GetState(GlobalDungeonState.StateAddress) is Dictionary globalDungeonStateEncoded
? new GlobalDungeonState(globalDungeonStateEncoded)
: new GlobalDungeonState();

if (!globalDungeonState.IsDungeonConquestAddress(DungeonId, ctx.Signer))
{
throw new InvalidValueException($"Invalid dungeon ID: {DungeonId}");
}

Dungeon dungeon = GetDungeonInCsv(DungeonId);

globalDungeonState = globalDungeonState.RemoveDungeonConquestAddress(DungeonId);

states = states.MintAsset(ctx.Signer, FungibleAssetValue.Parse(Currencies.KeyCurrency, dungeon.ReturnDungeonRewardBBG));
return states.SetState(GlobalDungeonState.StateAddress, globalDungeonState.Serialize());
}
}
32 changes: 32 additions & 0 deletions backend/app/Savor22b/GraphTypes/Query/Query.cs
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,38 @@ swarm is null
}
);

Field<NonNullGraphType<StringGraphType>>(
"createAction_SellDungeonConquest",
description: "던전점령권 시스템에 판매",
arguments: new QueryArguments(
new QueryArgument<NonNullGraphType<StringGraphType>>
{
Name = "publicKey",
Description = "The base64-encoded public key for Transaction.",
},
new QueryArgument<NonNullGraphType<GuidGraphType>>
{
Name = "dungeonId",
Description = "던전 Id",
}
),
resolve: context =>
{
var publicKey = new PublicKey(
ByteUtil.ParseHex(context.GetArgument<string>("publicKey"))
);

var action = new SellDungeonConquest(context.GetArgument<int>("dungeonId"));

return new GetUnsignedTransactionHex(
action,
publicKey,
_blockChain,
_swarm
).UnsignedTransactionHex;
}
);

Field<NonNullGraphType<StringGraphType>>(
"createAction_CancelRegisteredTradeGoodAction",
description: "무역상점 상품 등록 취소",
Expand Down
Loading