GS2-Exchange Deploy/CDK Reference

The template format used when creating stacks with GS2-Deploy, and implementation examples of template output in various languages using CDK

Entities

Resources targeted by the Deploy operation

Namespace

Namespace

A Namespace allows multiple independent instances of the same service within a single project by separating data spaces and usage contexts. Each GS2 service is managed on a per-namespace basis. Even when using the same service, if the namespace differs, the data is treated as a completely independent data space.

Therefore, you must create a namespace before you can start using each service.

Request

Resource creation and update requests

TypeConditionRequiredDefaultValue LimitsDescription
namestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
descriptionstring~ 1024 charsDescription
enableAwaitExchangeboolfalseWhether to enable exchanges that require a waiting time before receiving results
When enabled, exchange rate models with await timing type can be used. These exchanges require real-time to elapse before rewards can be claimed, enabling crafting or production mechanics where players must wait for the result.
enableDirectExchangebooltrueAllow direct exchange API calls
When enabled, clients can call the exchange API directly to perform resource exchanges. When disabled, exchanges can only be triggered via transaction actions (transactions), providing tighter server-side control over when exchanges occur.
transactionSettingTransactionSetting
Transaction Setting
Configuration for controlling how distributed transactions are executed when processing exchange operations. Supports auto-run, atomic commit, and async processing options.
exchangeScriptScriptSettingScript to run when an attempt is made to perform an exchange
Script Trigger Reference - exchange
incrementalExchangeScriptScriptSettingScript to run when an attempt is made to perform an incremental exchange
Script Trigger Reference - incrementalExchange
acquireAwaitScriptScriptSettingScript setting executed when the waiting period completes and the reward is about to be acquired in an await-type exchange
Script Trigger Reference - acquireAwait
logSettingLogSettingLog Output Setting
Configuration for outputting log data of exchange operations to GS2-Log. By specifying a GS2-Log namespace, API request and response logs for exchange, incremental exchange, and await operations can be collected.

GetAttr

Resource creation results that can be retrieved using the !GetAttr tag

TypeDescription
ItemNamespaceNamespace created

Implementation Example

Type: GS2::Exchange::Namespace
Properties:
  Name: namespace-0001
  Description: null
  EnableAwaitExchange: null
  EnableDirectExchange: null
  TransactionSetting: 
    EnableAutoRun: true
    QueueNamespaceId: grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001
  ExchangeScript: null
  IncrementalExchangeScript: null
  AcquireAwaitScript: null
  LogSetting: 
    LoggingNamespaceId: grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001
import (
    "github.com/gs2io/gs2-golang-cdk/core"
    "github.com/gs2io/gs2-golang-cdk/exchange"
    "github.com/openlyinc/pointy"
)


SampleStack := core.NewStack()
exchange.NewNamespace(
    &SampleStack,
    "namespace-0001",
    exchange.NamespaceOptions{
        TransactionSetting: core.NewTransactionSetting(
            core.TransactionSettingOptions{
                QueueNamespaceId: pointy.String("grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001"),
            },
        ),
        LogSetting: &core.LogSetting{
            LoggingNamespaceId: "grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001",
        },
    },
)

println(SampleStack.Yaml())  // Generate Template
class SampleStack extends \Gs2Cdk\Core\Model\Stack
{
    function __construct() {
        parent::__construct();
        new \Gs2Cdk\Exchange\Model\Namespace_(
            stack: $this,
            name: "namespace-0001",
            options: new \Gs2Cdk\Exchange\Model\Options\NamespaceOptions(
                transactionSetting: new \Gs2Cdk\Core\Model\TransactionSetting(
                    new \Gs2Cdk\Core\Model\TransactionSettingOptions(
                        queueNamespaceId: "grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001"
                    )
                ),
                logSetting: new \Gs2Cdk\Core\Model\LogSetting(
                    loggingNamespaceId: "grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001"
                )
            )
        );
    }
}

print((new SampleStack())->yaml());  // Generate Template
class SampleStack extends io.gs2.cdk.core.model.Stack
{
    public SampleStack() {
        super();
        new io.gs2.cdk.exchange.model.Namespace(
                this,
                "namespace-0001",
                new io.gs2.cdk.exchange.model.options.NamespaceOptions()
                        .withTransactionSetting(new io.gs2.cdk.core.model.TransactionSetting(
                            new io.gs2.cdk.core.model.options.TransactionSettingOptions()
                                .withQueueNamespaceId("grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001")
                        ))
                        .withLogSetting(new io.gs2.cdk.core.model.LogSetting(
                            "grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001"
                        ))
        );
    }
}

System.out.println(new SampleStack().yaml());  // Generate Template
public class SampleStack : Gs2Cdk.Core.Model.Stack
{
    public SampleStack() {
        new Gs2Cdk.Gs2Exchange.Model.Namespace(
            stack: this,
            name: "namespace-0001",
            options: new Gs2Cdk.Gs2Exchange.Model.Options.NamespaceOptions
            {
                transactionSetting = new Gs2Cdk.Core.Model.TransactionSetting(
                    options: new Gs2Cdk.Core.Model.TransactionSettingOptions
                    {
                        queueNamespaceId = "grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001"
                    }
                ),
                logSetting = new Gs2Cdk.Core.Model.LogSetting(
                    loggingNamespaceId: "grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001"
                )
            }
        );
    }
}

Debug.Log(new SampleStack().Yaml());  // Generate Template
import core from "@/gs2cdk/core";
import exchange from "@/gs2cdk/exchange";

class SampleStack extends core.Stack
{
    public constructor() {
        super();
        new exchange.model.Namespace(
            this,
            "namespace-0001",
            {
                transactionSetting: new core.TransactionSetting(
                    {
                        queueNamespaceId: "grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001"
                    }
                ),
                logSetting: new core.LogSetting(
                    "grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001"
                )
            }
        );
    }
}

console.log(new SampleStack().yaml());  // Generate Template
from gs2_cdk import Stack, core, exchange

class SampleStack(Stack):

    def __init__(self):
        super().__init__()
        exchange.Namespace(
            stack=self,
            name='namespace-0001',
            options=exchange.NamespaceOptions(
                transaction_setting=core.TransactionSetting(
                    options=core.TransactionSettingOptions(
                        queue_namespace_id='grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001',
                    )
                ),
                log_setting=core.LogSetting(
                    logging_namespace_id='grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001',
                ),
            ),
        )

print(SampleStack().yaml())  # Generate Template

TransactionSetting

Transaction Setting

Transaction Setting controls how transactions are executed, including their consistency, asynchronous processing, and conflict avoidance mechanisms. Combining features like AutoRun, AtomicCommit, asynchronous execution using GS2-Distributor, batch application of script results, and asynchronous Acquire Actions via GS2-JobQueue enables robust transaction management tailored to game logic.

TypeConditionRequiredDefaultValue LimitsDescription
enableAutoRunboolfalseWhether to automatically execute issued transactions on the server side
enableAtomicCommitbool{enableAutoRun} == truefalseWhether to commit the execution of transactions atomically
* Applicable only if enableAutoRun is true
transactionUseDistributorbool{enableAtomicCommit} == truefalseWhether to execute transactions asynchronously
* Applicable only if enableAtomicCommit is true
commitScriptResultInUseDistributorbool{transactionUseDistributor} == truefalseWhether to execute the commit processing of the script result asynchronously
* Applicable only if transactionUseDistributor is true
acquireActionUseJobQueuebool{enableAtomicCommit} == truefalseWhether to use GS2-JobQueue to execute the acquire action
* Applicable only if enableAtomicCommit is true
distributorNamespaceIdstring“grn:gs2:{region}:{ownerId}:distributor:default”~ 1024 charsGS2-Distributor Namespace GRN used to execute transactions
queueNamespaceIdstring“grn:gs2:{region}:{ownerId}:queue:default”~ 1024 charsGS2-JobQueue Namespace GRN used to execute transactions

ScriptSetting

Script Setting

In GS2, you can associate custom scripts with microservice events and execute them. This model holds the settings for triggering script execution.

There are two main ways to execute a script: synchronous execution and asynchronous execution. Synchronous execution blocks processing until the script has finished executing. Instead, you can use the script’s execution results to halt API execution or control the API’s response content.

In contrast, asynchronous execution does not block processing until the script has finished executing. However, because the script result cannot be used to stop the API execution or modify the API response, asynchronous execution does not affect the API response flow and is generally recommended.

There are two types of asynchronous execution methods: GS2-Script and Amazon EventBridge. By using Amazon EventBridge, you can write processing in languages other than Lua.

TypeConditionRequiredDefaultValue LimitsDescription
triggerScriptIdstring~ 1024 charsGS2-Script script GRN executed synchronously when the API is executed
Must be specified in GRN format starting with “grn:gs2:”.
doneTriggerTargetTypeString Enum
enum {
  “none”,
  “gs2_script”,
  “aws”
}
“none”How to execute asynchronous scripts
Specifies the type of script to use for asynchronous execution.
You can choose from “Do not use asynchronous execution (none)”, “Use GS2-Script (gs2_script)”, and “Use Amazon EventBridge (aws)”.
DefinitionDescription
“none”None
“gs2_script”GS2-Script
“aws”Amazon EventBridge
doneTriggerScriptIdstring{doneTriggerTargetType} == “gs2_script”~ 1024 charsGS2-Script script GRN for asynchronous execution
Must be specified in GRN format starting with “grn:gs2:”.
* Applicable only if doneTriggerTargetType is “gs2_script”
doneTriggerQueueNamespaceIdstring{doneTriggerTargetType} == “gs2_script”~ 1024 charsGS2-JobQueue namespace GRN to execute asynchronous execution scripts
If you want to execute asynchronous execution scripts via GS2-JobQueue instead of executing them directly, specify the GS2-JobQueue namespace GRN.
There are not many cases where GS2-JobQueue is required, so you generally do not need to specify it unless you have a specific reason.
* Applicable only if doneTriggerTargetType is “gs2_script”

LogSetting

Log Output Setting

Log Output Setting defines how log data is exported. This type holds the GS2-Log namespace identifier (Namespace ID) used to export log data. Specify the GS2-Log namespace where log data is collected and stored in the GRN format for the Log Namespace ID (loggingNamespaceId). Configuring this setting ensures that log data for API requests and responses occurring within the specified namespace is output to the target GS2-Log namespace. GS2-Log provides real-time logs that can be used for system monitoring, analysis, debugging, and other operational purposes.

TypeConditionRequiredDefaultValue LimitsDescription
loggingNamespaceIdstring
~ 1024 charsGS2-Log namespace GRN to output logs
Must be specified in GRN format starting with “grn:gs2:”.

CurrentRateMaster

Currently active Rate Model master data

This master data describes the definitions of Rate Models currently active within the namespace. GS2 uses JSON format files for managing master data. By uploading these files, the master data settings are updated on the server.

To create JSON files, GS2 provides a master data editor within the management console. Additionally, you can create tools better suited for game operations and export JSON files in the appropriate format.

Request

Resource creation and update requests

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
modeString Enum
enum {
  “direct”,
  “preUpload”
}
“direct”Update mode
DefinitionDescription
“direct”Directly update master data
“preUpload”Upload master data and then update
settingsstring{mode} == “direct”
✓*
~ 5242880 charsMaster Data
* Required if mode is “direct”
uploadTokenstring{mode} == “preUpload”
✓*
~ 1024 charsToken obtained by pre-upload
Used to apply the uploaded master data.
* Required if mode is “preUpload”

GetAttr

Resource creation results that can be retrieved using the !GetAttr tag

TypeDescription
ItemCurrentRateMasterUpdated master data of the currently active Rate Models

Implementation Example

Type: GS2::Exchange::CurrentRateMaster
Properties:
  NamespaceName: namespace-0001
  Mode: direct
  Settings: {
    "version": "2019-08-19",
    "rateModels": [
      {
        "name": "material_n_to_r",
        "timingType": "await",
        "metadata": "N2R",
        "consumeActions": [
          {
            "action": "Gs2Inventory:ConsumeItemSetByUserId",
            "request": {
              "namespaceName": "namespace-0001",
              "inventoryName": "inventory-0001",
              "itemName": "item-0001",
              "consumeCount": 1,
              "itemSetName": "#{itemSetName}",
              "userId": "#{userId}"
            }
          }
        ],
        "lockTime": 50,
        "acquireActions": [
          {
            "action": "Gs2Inventory:AcquireItemSetByUserId",
            "request": {
              "namespaceName": "namespace-0001",
              "inventoryName": "inventory-0001",
              "itemName": "item-0001",
              "acquireCount": 1,
              "expiresAt": 0,
              "createNewItemSet": false,
              "itemSetName": "",
              "userId": "#{userId}"
            }
          }
        ]
      },
      {
        "name": "material_r_to_n",
        "timingType": "await",
        "metadata": "N2R",
        "consumeActions": [
          {
            "action": "Gs2Inventory:ConsumeItemSetByUserId",
            "request": {
              "namespaceName": "namespace-0001",
              "inventoryName": "inventory-0001",
              "itemName": "item-0001",
              "consumeCount": 1,
              "itemSetName": "#{itemSetName}",
              "userId": "#{userId}"
            }
          }
        ],
        "lockTime": 50,
        "acquireActions": [
          {
            "action": "Gs2Inventory:AcquireItemSetByUserId",
            "request": {
              "namespaceName": "namespace-0001",
              "inventoryName": "inventory-0001",
              "itemName": "item-0001",
              "acquireCount": 1,
              "expiresAt": 0,
              "createNewItemSet": false,
              "itemSetName": "",
              "userId": "#{userId}"
            }
          }
        ]
      }
    ],
    "incrementalRateModels": []
    
  }
  UploadToken: null
import (
    "github.com/gs2io/gs2-golang-cdk/core"
    "github.com/gs2io/gs2-golang-cdk/exchange"
    "github.com/gs2io/gs2-golang-cdk/inventory"
    "github.com/openlyinc/pointy"
)


SampleStack := core.NewStack()
exchange.NewNamespace(
    &SampleStack,
    "namespace-0001",
    exchange.NamespaceOptions{},
).MasterData(
    []exchange.RateModel{
        exchange.NewRateModel(
            "material_n_to_r",
            exchange.RateModelTimingTypeAwait,
            exchange.RateModelOptions{
                Metadata: pointy.String("N2R"),
                ConsumeActions: []core.ConsumeAction{
                    inventory.ConsumeItemSetByUserId(
                        "namespace-0001",
                        "inventory-0001",
                        "item-0001",
                        1,
                        "#{itemSetName}",
                        "#{userId}",
                    ),
                },
                LockTime: pointy.Int32(50),
                AcquireActions: []core.AcquireAction{
                    inventory.AcquireItemSetByUserId(
                        "namespace-0001",
                        "inventory-0001",
                        "item-0001",
                        1,
                        0,
                        pointy.Bool(false),
                        "",
                        "#{userId}",
                    ),
                },
            },
        ),
        exchange.NewRateModel(
            "material_r_to_n",
            exchange.RateModelTimingTypeAwait,
            exchange.RateModelOptions{
                Metadata: pointy.String("N2R"),
                ConsumeActions: []core.ConsumeAction{
                    inventory.ConsumeItemSetByUserId(
                        "namespace-0001",
                        "inventory-0001",
                        "item-0001",
                        1,
                        "#{itemSetName}",
                        "#{userId}",
                    ),
                },
                LockTime: pointy.Int32(50),
                AcquireActions: []core.AcquireAction{
                    inventory.AcquireItemSetByUserId(
                        "namespace-0001",
                        "inventory-0001",
                        "item-0001",
                        1,
                        0,
                        pointy.Bool(false),
                        "",
                        "#{userId}",
                    ),
                },
            },
        ),
    },
    []exchange.IncrementalRateModel{
    },
)

println(SampleStack.Yaml())  // Generate Template
class SampleStack extends \Gs2Cdk\Core\Model\Stack
{
    function __construct() {
        parent::__construct();
        (new \Gs2Cdk\Exchange\Model\Namespace_(
            stack: $this,
            name: "namespace-0001"
        ))->masterData(
            [
                new \Gs2Cdk\Exchange\Model\RateModel(
                    name:"material_n_to_r",
                    timingType: \Gs2Cdk\Exchange\Model\Enums\RateModelTimingType::AWAIT,
                    options: new \Gs2Cdk\Exchange\Model\Options\RateModelOptions(
                        metadata:"N2R",
                        consumeActions:[
                            new \Gs2Cdk\Inventory\StampSheet\ConsumeItemSetByUserId(
                                namespaceName: "namespace-0001",
                                inventoryName: "inventory-0001",
                                itemName: "item-0001",
                                consumeCount: 1,
                                itemSetName: "#{itemSetName}",
                                userId: "#{userId}"
                            ),
                        ],
                        lockTime:50,
                        acquireActions:[
                            new \Gs2Cdk\Inventory\StampSheet\AcquireItemSetByUserId(
                                namespaceName: "namespace-0001",
                                inventoryName: "inventory-0001",
                                itemName: "item-0001",
                                acquireCount: 1,
                                expiresAt: 0,
                                createNewItemSet: false,
                                itemSetName: "",
                                userId: "#{userId}"
                            ),
                        ]
                    )
                ),
                new \Gs2Cdk\Exchange\Model\RateModel(
                    name:"material_r_to_n",
                    timingType: \Gs2Cdk\Exchange\Model\Enums\RateModelTimingType::AWAIT,
                    options: new \Gs2Cdk\Exchange\Model\Options\RateModelOptions(
                        metadata:"N2R",
                        consumeActions:[
                            new \Gs2Cdk\Inventory\StampSheet\ConsumeItemSetByUserId(
                                namespaceName: "namespace-0001",
                                inventoryName: "inventory-0001",
                                itemName: "item-0001",
                                consumeCount: 1,
                                itemSetName: "#{itemSetName}",
                                userId: "#{userId}"
                            ),
                        ],
                        lockTime:50,
                        acquireActions:[
                            new \Gs2Cdk\Inventory\StampSheet\AcquireItemSetByUserId(
                                namespaceName: "namespace-0001",
                                inventoryName: "inventory-0001",
                                itemName: "item-0001",
                                acquireCount: 1,
                                expiresAt: 0,
                                createNewItemSet: false,
                                itemSetName: "",
                                userId: "#{userId}"
                            ),
                        ]
                    )
                )
            ],
            [
            ]
        );
    }
}

print((new SampleStack())->yaml());  // Generate Template
class SampleStack extends io.gs2.cdk.core.model.Stack
{
    public SampleStack() {
        super();
        new io.gs2.cdk.exchange.model.Namespace(
            this,
            "namespace-0001"
        ).masterData(
            Arrays.asList(
                new io.gs2.cdk.exchange.model.RateModel(
                    "material_n_to_r",
                    io.gs2.cdk.exchange.model.enums.RateModelTimingType.AWAIT,
                    new io.gs2.cdk.exchange.model.options.RateModelOptions()
                        .withMetadata("N2R")
                        .withConsumeActions(Arrays.asList(
                            new io.gs2.cdk.inventory.stampSheet.ConsumeItemSetByUserId(
                                "namespace-0001",
                                "inventory-0001",
                                "item-0001",
                                1L,
                                "#{itemSetName}",
                                "#{userId}"
                            )
                        ))
                        .withLockTime(50)
                        .withAcquireActions(Arrays.asList(
                            new io.gs2.cdk.inventory.stampSheet.AcquireItemSetByUserId(
                                "namespace-0001",
                                "inventory-0001",
                                "item-0001",
                                1L,
                                0L,
                                false,
                                "",
                                "#{userId}"
                            )
                        ))
                ),
                new io.gs2.cdk.exchange.model.RateModel(
                    "material_r_to_n",
                    io.gs2.cdk.exchange.model.enums.RateModelTimingType.AWAIT,
                    new io.gs2.cdk.exchange.model.options.RateModelOptions()
                        .withMetadata("N2R")
                        .withConsumeActions(Arrays.asList(
                            new io.gs2.cdk.inventory.stampSheet.ConsumeItemSetByUserId(
                                "namespace-0001",
                                "inventory-0001",
                                "item-0001",
                                1L,
                                "#{itemSetName}",
                                "#{userId}"
                            )
                        ))
                        .withLockTime(50)
                        .withAcquireActions(Arrays.asList(
                            new io.gs2.cdk.inventory.stampSheet.AcquireItemSetByUserId(
                                "namespace-0001",
                                "inventory-0001",
                                "item-0001",
                                1L,
                                0L,
                                false,
                                "",
                                "#{userId}"
                            )
                        ))
                )
            ),
            Arrays.asList(
            )
        );
    }
}

System.out.println(new SampleStack().yaml());  // Generate Template
public class SampleStack : Gs2Cdk.Core.Model.Stack
{
    public SampleStack() {
        new Gs2Cdk.Gs2Exchange.Model.Namespace(
            stack: this,
            name: "namespace-0001"
        ).MasterData(
            new Gs2Cdk.Gs2Exchange.Model.RateModel[] {
                new Gs2Cdk.Gs2Exchange.Model.RateModel(
                    name: "material_n_to_r",
                    timingType: Gs2Cdk.Gs2Exchange.Model.Enums.RateModelTimingType.Await,
                    options: new Gs2Cdk.Gs2Exchange.Model.Options.RateModelOptions
                    {
                        metadata = "N2R",
                        consumeActions = new Gs2Cdk.Core.Model.ConsumeAction[]
                        {
                            new Gs2Cdk.Gs2Inventory.StampSheet.ConsumeItemSetByUserId(
                                namespaceName: "namespace-0001",
                                inventoryName: "inventory-0001",
                                itemName: "item-0001",
                                consumeCount: 1,
                                itemSetName: "#{itemSetName}",
                                userId: "#{userId}"
                            )
                        },
                        lockTime = 50,
                        acquireActions = new Gs2Cdk.Core.Model.AcquireAction[]
                        {
                            new Gs2Cdk.Gs2Inventory.StampSheet.AcquireItemSetByUserId(
                                namespaceName: "namespace-0001",
                                inventoryName: "inventory-0001",
                                itemName: "item-0001",
                                acquireCount: 1,
                                expiresAt: 0,
                                createNewItemSet: false,
                                itemSetName: "",
                                userId: "#{userId}"
                            )
                        }
                    }
                ),
                new Gs2Cdk.Gs2Exchange.Model.RateModel(
                    name: "material_r_to_n",
                    timingType: Gs2Cdk.Gs2Exchange.Model.Enums.RateModelTimingType.Await,
                    options: new Gs2Cdk.Gs2Exchange.Model.Options.RateModelOptions
                    {
                        metadata = "N2R",
                        consumeActions = new Gs2Cdk.Core.Model.ConsumeAction[]
                        {
                            new Gs2Cdk.Gs2Inventory.StampSheet.ConsumeItemSetByUserId(
                                namespaceName: "namespace-0001",
                                inventoryName: "inventory-0001",
                                itemName: "item-0001",
                                consumeCount: 1,
                                itemSetName: "#{itemSetName}",
                                userId: "#{userId}"
                            )
                        },
                        lockTime = 50,
                        acquireActions = new Gs2Cdk.Core.Model.AcquireAction[]
                        {
                            new Gs2Cdk.Gs2Inventory.StampSheet.AcquireItemSetByUserId(
                                namespaceName: "namespace-0001",
                                inventoryName: "inventory-0001",
                                itemName: "item-0001",
                                acquireCount: 1,
                                expiresAt: 0,
                                createNewItemSet: false,
                                itemSetName: "",
                                userId: "#{userId}"
                            )
                        }
                    }
                )
            },
            new Gs2Cdk.Gs2Exchange.Model.IncrementalRateModel[] {
            }
        );
    }
}

Debug.Log(new SampleStack().Yaml());  // Generate Template
import core from "@/gs2cdk/core";
import exchange from "@/gs2cdk/exchange";
import inventory from "@/gs2cdk/inventory";

class SampleStack extends core.Stack
{
    public constructor() {
        super();
        new exchange.model.Namespace(
            this,
            "namespace-0001",
        ).masterData(
            [
                new exchange.model.RateModel(
                    "material_n_to_r",
                    exchange.model.RateModelTimingType.AWAIT,
                    {
                        metadata: "N2R",
                        consumeActions: [
                            new inventory.stampSheet.ConsumeItemSetByUserId(
                                "namespace-0001",
                                "inventory-0001",
                                "item-0001",
                                1,
                                "#{itemSetName}",
                                "#{userId}"
                            ),
                        ],
                        lockTime: 50,
                        acquireActions: [
                            new inventory.stampSheet.AcquireItemSetByUserId(
                                "namespace-0001",
                                "inventory-0001",
                                "item-0001",
                                1,
                                0,
                                false,
                                "",
                                "#{userId}"
                            ),
                        ]
                    }
                ),
                new exchange.model.RateModel(
                    "material_r_to_n",
                    exchange.model.RateModelTimingType.AWAIT,
                    {
                        metadata: "N2R",
                        consumeActions: [
                            new inventory.stampSheet.ConsumeItemSetByUserId(
                                "namespace-0001",
                                "inventory-0001",
                                "item-0001",
                                1,
                                "#{itemSetName}",
                                "#{userId}"
                            ),
                        ],
                        lockTime: 50,
                        acquireActions: [
                            new inventory.stampSheet.AcquireItemSetByUserId(
                                "namespace-0001",
                                "inventory-0001",
                                "item-0001",
                                1,
                                0,
                                false,
                                "",
                                "#{userId}"
                            ),
                        ]
                    }
                )
            ],
            [
            ]
        );
    }
}

console.log(new SampleStack().yaml());  // Generate Template
from gs2_cdk import Stack, core, exchange, inventory

class SampleStack(Stack):

    def __init__(self):
        super().__init__()
        exchange.Namespace(
            stack=self,
            name="namespace-0001",
        ).master_data(
            rate_models=[
                exchange.RateModel(
                    name='material_n_to_r',
                    timing_type=exchange.RateModelTimingType.AWAIT,
                    options=exchange.RateModelOptions(
                        metadata = 'N2R',
                        consume_actions = [
                            inventory.ConsumeItemSetByUserId(
                                namespace_name='namespace-0001',
                                inventory_name='inventory-0001',
                                item_name='item-0001',
                                consume_count=1,
                                item_set_name='#{itemSetName}',
                                user_id='#{userId}'
                            ),
                        ],
                        lock_time = 50,
                        acquire_actions = [
                            inventory.AcquireItemSetByUserId(
                                namespace_name='namespace-0001',
                                inventory_name='inventory-0001',
                                item_name='item-0001',
                                acquire_count=1,
                                expires_at=0,
                                create_new_item_set=False,
                                item_set_name="",
                                user_id='#{userId}'
                            ),
                        ]
                    ),
                ),
                exchange.RateModel(
                    name='material_r_to_n',
                    timing_type=exchange.RateModelTimingType.AWAIT,
                    options=exchange.RateModelOptions(
                        metadata = 'N2R',
                        consume_actions = [
                            inventory.ConsumeItemSetByUserId(
                                namespace_name='namespace-0001',
                                inventory_name='inventory-0001',
                                item_name='item-0001',
                                consume_count=1,
                                item_set_name='#{itemSetName}',
                                user_id='#{userId}'
                            ),
                        ],
                        lock_time = 50,
                        acquire_actions = [
                            inventory.AcquireItemSetByUserId(
                                namespace_name='namespace-0001',
                                inventory_name='inventory-0001',
                                item_name='item-0001',
                                acquire_count=1,
                                expires_at=0,
                                create_new_item_set=False,
                                item_set_name="",
                                user_id='#{userId}'
                            ),
                        ]
                    ),
                ),
            ],
            incremental_rate_models=[
            ],
        )

print(SampleStack().yaml())  # Generate Template

RateModel

Exchange Rate Model

Exchange Rate Model is an entity that defines the rate used to exchange one resource for another.

In addition to the rate at which a resource can be exchanged immediately, a rate can also be set at which a resource can be exchanged after a certain amount of time in real time has elapsed. Exchange rates that after a certain period of real time has elapsed can further define the resources required to perform an immediate exchange.

TypeConditionRequiredDefaultValue LimitsDescription
rateModelIdstring
*
~ 1024 charsExchange Rate Model GRN
* Set automatically by the server
namestring
~ 128 charsExchange Rate Model name
Exchange Rate Model-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
metadatastring~ 2048 charsMetadata
Arbitrary values can be set in the metadata.
Since they do not affect GS2’s behavior, they can be used to store information used in the game.
verifyActionsList<VerifyAction>[]0 ~ 10 itemsList of Verify Actions
Precondition checks that must all pass before the exchange is executed. If any verify action fails, the exchange is aborted without consuming resources. Used to enforce conditions such as level requirements or inventory capacity.
consumeActionsList<ConsumeAction>[]0 ~ 10 itemsList of Consume Actions
Defines the resources (cost) that the player must pay to perform this exchange. Multiple consume actions can be specified, allowing complex exchange costs such as requiring both gold and items. These actions are executed as consume actions within a distributed transaction.
timingTypeString Enum
enum {
  “immediate”,
  “await”
}
“immediate”Type of exchange
Determines when rewards are delivered after performing the exchange. immediate delivers rewards instantly upon exchange execution. await requires real-time to elapse before rewards can be claimed, creating a waiting period (e.g., crafting time).
DefinitionDescription
“immediate”Immediate
“await”Waiting for real time to pass
lockTimeint{timingType} == “await”
✓*
0 ~ 538214400Waiting time (minutes) from the execution of the exchange until the reward is actually received
Only applicable when timingType is await. Specifies the number of minutes that must elapse in real time after the exchange is initiated before the player can claim the rewards. The waiting time can be shortened by using the skip mechanism.
* Required if timingType is “await”
acquireActionsList<AcquireAction>[]0 ~ 100 itemsList of Acquire Actions
Defines the resources (rewards) that the player receives upon completing the exchange. Multiple acquire actions can be specified to grant various resource types simultaneously. These actions are executed as acquire actions within a distributed transaction.

AcquireAction

Acquire Action

TypeConditionRequiredDefaultValue LimitsDescription
actionString Enum
enum {
"Gs2AdReward:AcquirePointByUserId",
"Gs2Dictionary:AddEntriesByUserId",
"Gs2Enchant:ReDrawBalanceParameterStatusByUserId",
"Gs2Enchant:SetBalanceParameterStatusByUserId",
"Gs2Enchant:ReDrawRarityParameterStatusByUserId",
"Gs2Enchant:AddRarityParameterStatusByUserId",
"Gs2Enchant:SetRarityParameterStatusByUserId",
"Gs2Enhance:DirectEnhanceByUserId",
"Gs2Enhance:UnleashByUserId",
"Gs2Enhance:CreateProgressByUserId",
"Gs2Exchange:ExchangeByUserId",
"Gs2Exchange:IncrementalExchangeByUserId",
"Gs2Exchange:CreateAwaitByUserId",
"Gs2Exchange:AcquireForceByUserId",
"Gs2Exchange:SkipByUserId",
"Gs2Experience:AddExperienceByUserId",
"Gs2Experience:SetExperienceByUserId",
"Gs2Experience:AddRankCapByUserId",
"Gs2Experience:SetRankCapByUserId",
"Gs2Experience:MultiplyAcquireActionsByUserId",
"Gs2Formation:AddMoldCapacityByUserId",
"Gs2Formation:SetMoldCapacityByUserId",
"Gs2Formation:AcquireActionsToFormProperties",
"Gs2Formation:SetFormByUserId",
"Gs2Formation:AcquireActionsToPropertyFormProperties",
"Gs2Friend:UpdateProfileByUserId",
"Gs2Grade:AddGradeByUserId",
"Gs2Grade:ApplyRankCapByUserId",
"Gs2Grade:MultiplyAcquireActionsByUserId",
"Gs2Guild:IncreaseMaximumCurrentMaximumMemberCountByGuildName",
"Gs2Guild:SetMaximumCurrentMaximumMemberCountByGuildName",
"Gs2Idle:IncreaseMaximumIdleMinutesByUserId",
"Gs2Idle:SetMaximumIdleMinutesByUserId",
"Gs2Idle:ReceiveByUserId",
"Gs2Inbox:SendMessageByUserId",
"Gs2Inventory:AddCapacityByUserId",
"Gs2Inventory:SetCapacityByUserId",
"Gs2Inventory:AcquireItemSetByUserId",
"Gs2Inventory:AcquireItemSetWithGradeByUserId",
"Gs2Inventory:AddReferenceOfByUserId",
"Gs2Inventory:DeleteReferenceOfByUserId",
"Gs2Inventory:AcquireSimpleItemsByUserId",
"Gs2Inventory:SetSimpleItemsByUserId",
"Gs2Inventory:AcquireBigItemByUserId",
"Gs2Inventory:SetBigItemByUserId",
"Gs2JobQueue:PushByUserId",
"Gs2Limit:CountDownByUserId",
"Gs2Limit:DeleteCounterByUserId",
"Gs2LoginReward:DeleteReceiveStatusByUserId",
"Gs2LoginReward:UnmarkReceivedByUserId",
"Gs2Lottery:DrawByUserId",
"Gs2Lottery:ResetBoxByUserId",
"Gs2Mission:RevertReceiveByUserId",
"Gs2Mission:IncreaseCounterByUserId",
"Gs2Mission:SetCounterByUserId",
"Gs2Money:DepositByUserId",
"Gs2Money:RevertRecordReceipt",
"Gs2Money2:DepositByUserId",
"Gs2Quest:CreateProgressByUserId",
"Gs2Schedule:TriggerByUserId",
"Gs2Schedule:ExtendTriggerByUserId",
"Gs2Script:InvokeScript",
"Gs2SerialKey:RevertUseByUserId",
"Gs2SerialKey:IssueOnce",
"Gs2Showcase:DecrementPurchaseCountByUserId",
"Gs2Showcase:ForceReDrawByUserId",
"Gs2SkillTree:MarkReleaseByUserId",
"Gs2Stamina:RecoverStaminaByUserId",
"Gs2Stamina:RaiseMaxValueByUserId",
"Gs2Stamina:SetMaxValueByUserId",
"Gs2Stamina:SetRecoverIntervalByUserId",
"Gs2Stamina:SetRecoverValueByUserId",
"Gs2StateMachine:StartStateMachineByUserId",
}
Type of action to be executed in the Acquire Action
requeststring
~ 524288 charsJSON string of the request used when executing the action

ConsumeAction

Consume Action

TypeConditionRequiredDefaultValue LimitsDescription
actionString Enum
enum {
"Gs2AdReward:ConsumePointByUserId",
"Gs2Dictionary:DeleteEntriesByUserId",
"Gs2Enhance:DeleteProgressByUserId",
"Gs2Exchange:DeleteAwaitByUserId",
"Gs2Experience:SubExperienceByUserId",
"Gs2Experience:SubRankCapByUserId",
"Gs2Formation:SubMoldCapacityByUserId",
"Gs2Grade:SubGradeByUserId",
"Gs2Guild:DecreaseMaximumCurrentMaximumMemberCountByGuildName",
"Gs2Idle:DecreaseMaximumIdleMinutesByUserId",
"Gs2Inbox:OpenMessageByUserId",
"Gs2Inbox:DeleteMessageByUserId",
"Gs2Inventory:ConsumeItemSetByUserId",
"Gs2Inventory:ConsumeSimpleItemsByUserId",
"Gs2Inventory:ConsumeBigItemByUserId",
"Gs2JobQueue:DeleteJobByUserId",
"Gs2Limit:CountUpByUserId",
"Gs2LoginReward:MarkReceivedByUserId",
"Gs2Mission:ReceiveByUserId",
"Gs2Mission:BatchReceiveByUserId",
"Gs2Mission:DecreaseCounterByUserId",
"Gs2Mission:ResetCounterByUserId",
"Gs2Money:WithdrawByUserId",
"Gs2Money:RecordReceipt",
"Gs2Money2:WithdrawByUserId",
"Gs2Money2:VerifyReceiptByUserId",
"Gs2Quest:DeleteProgressByUserId",
"Gs2Ranking2:CreateGlobalRankingReceivedRewardByUserId",
"Gs2Ranking2:CreateClusterRankingReceivedRewardByUserId",
"Gs2Schedule:DeleteTriggerByUserId",
"Gs2SerialKey:UseByUserId",
"Gs2Showcase:IncrementPurchaseCountByUserId",
"Gs2SkillTree:MarkRestrainByUserId",
"Gs2Stamina:DecreaseMaxValueByUserId",
"Gs2Stamina:ConsumeStaminaByUserId",
}
Type of action to be executed in the Consume Action
requeststring
~ 524288 charsJSON string of the request used when executing the action

VerifyAction

Verify Action

TypeConditionRequiredDefaultValue LimitsDescription
actionString Enum
enum {
"Gs2Dictionary:VerifyEntryByUserId",
"Gs2Distributor:IfExpressionByUserId",
"Gs2Distributor:AndExpressionByUserId",
"Gs2Distributor:OrExpressionByUserId",
"Gs2Enchant:VerifyRarityParameterStatusByUserId",
"Gs2Experience:VerifyRankByUserId",
"Gs2Experience:VerifyRankCapByUserId",
"Gs2Grade:VerifyGradeByUserId",
"Gs2Grade:VerifyGradeUpMaterialByUserId",
"Gs2Guild:VerifyCurrentMaximumMemberCountByGuildName",
"Gs2Guild:VerifyIncludeMemberByUserId",
"Gs2Inventory:VerifyInventoryCurrentMaxCapacityByUserId",
"Gs2Inventory:VerifyItemSetByUserId",
"Gs2Inventory:VerifyReferenceOfByUserId",
"Gs2Inventory:VerifySimpleItemByUserId",
"Gs2Inventory:VerifyBigItemByUserId",
"Gs2Limit:VerifyCounterByUserId",
"Gs2Matchmaking:VerifyIncludeParticipantByUserId",
"Gs2Mission:VerifyCompleteByUserId",
"Gs2Mission:VerifyCounterValueByUserId",
"Gs2Ranking2:VerifyGlobalRankingScoreByUserId",
"Gs2Ranking2:VerifyClusterRankingScoreByUserId",
"Gs2Ranking2:VerifySubscribeRankingScoreByUserId",
"Gs2Schedule:VerifyTriggerByUserId",
"Gs2Schedule:VerifyEventByUserId",
"Gs2SerialKey:VerifyCodeByUserId",
"Gs2Stamina:VerifyStaminaValueByUserId",
"Gs2Stamina:VerifyStaminaMaxValueByUserId",
"Gs2Stamina:VerifyStaminaRecoverIntervalMinutesByUserId",
"Gs2Stamina:VerifyStaminaRecoverValueByUserId",
"Gs2Stamina:VerifyStaminaOverflowValueByUserId",
}
Type of action to be executed in the Verify Action
requeststring
~ 524288 charsJSON string of the request used when executing the action

IncrementalRateModel

Incremental Cost Exchange Rate Model

Normal exchange rates always provide exchanges at a constant rate. With incremental exchange rates, you can define a rate that increases in cost as the number of exchanges increases. For example, the first exchange is performed at a rate of 1:1, but the second exchange is performed at a rate of 2:1. By defining such a rate, you can increase the value of the resources obtained by the player as the game progresses.

The number of exchanges can be reset after a certain period of real time has elapsed. This is useful for resetting the number of exchanges on a daily or weekly basis.

TypeConditionRequiredDefaultValue LimitsDescription
incrementalRateModelIdstring
*
~ 1024 charsIncremental Cost Exchange Rate Model GRN
* Set automatically by the server
namestring
~ 128 charsIncremental Cost Exchange Rate Model name
Incremental Cost Exchange Rate Model-specific name. Specified using alphanumeric characters, hyphen (-), underscore (_), and period (.).
metadatastring~ 2048 charsMetadata
Arbitrary values can be set in the metadata.
Since they do not affect GS2’s behavior, they can be used to store information used in the game.
consumeActionConsumeAction
Consume Action (Quantity and Value are overwritten automatically)
Defines the type of resource consumed as cost for the exchange. The actual quantity is calculated dynamically based on the exchange count and the calculation type (linear, power, or script). Only the action type and target resource need to be specified; the quantity field is overwritten automatically.
calculateTypeString Enum
enum {
  “linear”,
  “power”,
  “gs2_script”
}
Calculation method for cost increase amount
Determines how the exchange cost escalates with each exchange. linear calculates cost as baseValue + (coefficientValue * exchangeCount). power calculates cost as coefficientValue * (exchangeCount + 1)^2. gs2_script delegates the calculation to a custom GS2-Script for arbitrary logic.
DefinitionDescription
“linear”Base Value + (Coefficient * Number of Exchanges)
“power”Coefficient * (Number of Exchanges + 1) ^ 2
“gs2_script”Custom logic implemented with GS2-Script
baseValuelong{calculateType} == “linear”
✓*
0 ~ 9223372036854775805Base Value
The initial cost for the first exchange when using the linear calculation type. The total cost is calculated as: baseValue + (coefficientValue * exchangeCount).
* Required if calculateType is “linear”
coefficientValuelong{calculateType} in [“linear”, “power”]
✓*
0 ~ 9223372036854775805Coefficient Value
The multiplier that controls how quickly costs escalate with each exchange. In linear mode, each exchange adds this value to the cost. In power mode, the cost is calculated as: coefficientValue * (exchangeCount + 1)^2.
* Required if calculateType is “linear”,“power”
calculateScriptIdstring{calculateType} == “gs2_script”
✓*
~ 1024 charsGRN of cost calculation script
Script Trigger Reference - calculateCost
* Required if calculateType is “gs2_script”
exchangeCountIdstring
~ 1024 charsGS2-Limit Usage Limit Model GRN for managing exchange execution counts
References a GS2-Limit limit model that tracks how many times each user has performed this incremental exchange. The count is used to calculate the escalating cost and can be reset periodically (e.g., daily or weekly) using GS2-Limit’s reset timing.
maximumExchangeCountint21474836460 ~ 2147483646Maximum number of exchanges
The maximum number of times this incremental exchange can be performed by a user. Once the exchange count reaches this limit, further exchanges are denied until the count is reset via GS2-Limit.
acquireActionsList<AcquireAction>[]0 ~ 100 itemsList of Acquire Actions
Defines the resources (rewards) that the player receives upon completing the incremental exchange. The rewards remain constant regardless of the exchange count; only the cost increases with each exchange.