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

Dev #2

Merged
merged 5 commits into from
Feb 6, 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
53 changes: 53 additions & 0 deletions .github/workflows/publish-npm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Publish to NPM

on:
push:
tags:
# package-major.minor.patch - required
# -beta.build - optional
- '*-*.*.*'

jobs:
build:
runs-on: ubuntu-latest

steps:
- id: get-package
run: |
PACKAGE_NAME=$(echo ${GITHUB_REF#refs/tags/} | cut -d- -f1)
ALLOWED_PACKAGES=("phaser") # Add more package names if needed
if [[ " ${ALLOWED_PACKAGES[@]} " =~ " ${PACKAGE_NAME} " ]]; then
echo "::set-output name=package::${PACKAGE_NAME}"
else
echo "Invalid package name ${PACKAGE_NAME}."
exit 1
fi
shell: bash

- uses: actions/checkout@v4

- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'

- name: Check version
run: |
TAG_VERSION=$(echo ${GITHUB_REF#refs/tags/${{ steps.get-package.outputs.package }}-})
PACKAGE_VERSION=$(node -p "require('./packages/${{ steps.get-package.outputs.package }}/package.json').version")
if [[ "${TAG_VERSION}" != "${PACKAGE_VERSION}" ]]; then
echo "Tag version ${TAG_VERSION} does not match package version ${PACKAGE_VERSION}."
exit 1
fi

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build --workspace @barinbritva/${{ steps.get-package.outputs.package }}-sdk

- name: Publish
run: cd packages/${{ steps.get-package.outputs.package }} && npm publish --access=public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
48 changes: 24 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# gamefi-sdk
# game-engines-sdk

TON bindings and utilities for game engines:
TON blockchain bindings and utilities for game engines:
* Phaser.io
* Cocos2d (coming soon)

# Getting started
Installation:
```sh
npm install --save @ton-community/gamefi-phaser
npm install --save @barinbritva/phaser-sdk
```

Creating GameFi instance:
Expand Down Expand Up @@ -44,40 +44,40 @@ This can be used for:

| Method | Description |
| -------- | -------- |
| [create](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#create) | creates a GameFi instance |
| [create](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#create) | creates a GameFi instance |

`GameFi` instance methods:

| Method | Description |
| -------- | -------- |
| [createConnectButton](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#createConnectButton) | creates a button to connect a wallet. |
| [connectWallet](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#connectWallet) | connect wallet manually (without build-in UIs) |
| [onWalletChange](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#onWalletChange) | watch weather wallet was connected or disconnected |
| [disconnectWallet](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#disconnectWallet) | disconnect wallet manually (without build-in UIs) |
| [buy](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#buy) | buy from in-game shop with jetton or TON |
| [send](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#send) | transfer jetton or TON to another wallet address |
| [getNftCollection](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#getNftCollection) | get collection data |
| [getNftAddressByIndex](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#getNftAddressByIndex) | get NFT address by its index in a collection |
| [getNftItem](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#getNftItem) | get NFT data by address |
| [getNftItemByIndex](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#getNftItemByIndex) | get NFT data by its index in a collection |
| [createConnectButton](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#createConnectButton) | creates a button to connect a wallet. |
| [connectWallet](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#connectWallet) | connect wallet manually (without build-in UIs) |
| [onWalletChange](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#onWalletChange) | watch weather wallet was connected or disconnected |
| [disconnectWallet](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#disconnectWallet) | disconnect wallet manually (without build-in UIs) |
| [buy](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#buy) | buy from in-game shop with jetton or TON |
| [send](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#send) | transfer jetton or TON to another wallet address |
| [getNftCollection](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#getNftCollection) | get collection data |
| [getNftAddressByIndex](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#getNftAddressByIndex) | get NFT address by its index in a collection |
| [getNftItem](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#getNftItem) | get NFT data by address |
| [getNftItemByIndex](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#getNftItemByIndex) | get NFT data by its index in a collection |
| [transferNftItem](docs/classes/GameFi.html#transferNftItem) | transfer NFT to another wallet address |
| [getJetton](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#getJetton) | get jetton data |
| [transferJetton](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#transferJetton) | transfer jetton to another wallet address |
| [getJetton](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#getJetton) | get jetton data |
| [transferJetton](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#transferJetton) | transfer jetton to another wallet address |

`GameFi` instance props:

| Prop | Description |
| -------- | -------- |
| [tonClient](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#tonClient) | ton client instance in case you need to use it |
| [walletConnector](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#walletConnector) | wallet connector instance in case you need to use it |
| [wallet](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#wallet) | user's connected wallet |
| [walletAccount](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#walletAccount) | user's connected account |
| [walletAddress](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#walletAddress) | user's connected wallet address |
| [merchantAddress](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#merchantAddress) | in-game shop's address to receive TON |
| [merchantJettonAddress](https://barinbritva.github.io/ton-gamefi/classes/GameFi.html#merchantJettonAddress) | in-game shop's jetton used as in-game currency |
| [tonClient](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#tonClient) | ton client instance in case you need to use it |
| [walletConnector](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#walletConnector) | wallet connector instance in case you need to use it |
| [wallet](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#wallet) | user's connected wallet |
| [walletAccount](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#walletAccount) | user's connected account |
| [walletAddress](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#walletAddress) | user's connected wallet address |
| [merchantAddress](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#merchantAddress) | in-game shop's address to receive TON |
| [merchantJettonAddress](https://barinbritva.github.io/game-engines-sdk/classes/GameFi.html#merchantJettonAddress) | in-game shop's jetton used as in-game currency |

# Use cases
To learn complex use cases read [TON GameFi article](https://gist.github.com/barinbritva/b3db1605f2667b7562b53a23877c0e73) and check out the source code of demo [Flappy Bird game](https://github.com/ton-community/flappy-bird).

# References
The full [typedoc references](https://barinbritva.github.io/ton-gamefi/index.html).
The full [typedoc references](https://barinbritva.github.io/game-engines-sdk/index.html).
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"name": "ton-gamefi",
"private": true,
"name": "@barinbritva/game-engines-sdk",
"engines": {
"node": ">=18.0.0",
"npm": ">=9.0.0"
Expand Down
30 changes: 30 additions & 0 deletions packages/common/content-resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {DefaultContentResolver, ContentResolver} from './content';

export interface IpfsGateway {
(id: string): string;
}

export interface UrlProxy {
(url: string): string;
}

export interface ProxyContentResolverParams {
ipfsGateway?: IpfsGateway;
urlProxy?: UrlProxy;
}

export class ProxyContentResolver extends DefaultContentResolver {
readonly urlProxy: UrlProxy;
public static readonly replaceable: string = '%URL%';

constructor({ipfsGateway, urlProxy}: ProxyContentResolverParams = {}) {
super(ipfsGateway);
this.urlProxy = urlProxy == null ? (url) => url : urlProxy;
}

public override resolve(url: string): Promise<Buffer> {
return super.resolve(this.urlProxy(url));
}
}

export {ContentResolver};
2 changes: 1 addition & 1 deletion packages/common/external.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export {getHttpEndpoint} from '@orbs-network/ton-access';
export {Sender, SenderArguments, SendMode, storeStateInit} from '@ton/core';

// add export of TonClientParameters to @ton/ton package
export interface TonClientOptions {
export interface TonClientParams {
endpoint: string;
timeout?: number;
apiKey?: string;
Expand Down
77 changes: 60 additions & 17 deletions packages/common/game-fi.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import {TonClient, getHttpEndpoint, TonClientOptions, TonConnectUI, Address} from './external';
import {WalletConnector, WalletConnectorOptions, Wallet, Account, WalletApp} from './interfaces';
import {TonClient, getHttpEndpoint, TonClientParams, TonConnectUI, Address} from './external';
import {WalletConnector, WalletConnectorParams, Wallet, Account, WalletApp} from './interfaces';
import {TonConnectSender} from './ton-connect-sender';
import {NftCollectionManager} from './nft-collection';
import {
IpfsGateway,
ProxyContentResolver,
ProxyContentResolverParams,
UrlProxy,
ContentResolver
} from './content-resolver';
import {NftItemManager, NftTransferRequest} from './nft-item';
import {JettonManager, JettonTransferRequest} from './jetton';
import {PaymentManager, TonTransferRequest} from './payment';
Expand All @@ -10,15 +17,20 @@ export type NftTransferParams = Omit<NftTransferRequest, 'from'>;
export type SendParams = Omit<TonTransferRequest, 'from'> | Omit<JettonTransferRequest, 'from'>;
export type BuyParams =
| Omit<TonTransferRequest, 'from' | 'to'>
| Omit<JettonTransferRequest, 'from' | 'to'>;
| (Omit<JettonTransferRequest, 'from' | 'to' | 'jetton'> & {jetton?: true});

export type Network = 'mainnet' | 'testnet';

export interface MerchantInitialization {
export interface MerchantParams {
tonAddress: Address | string;
jettonAddress: Address | string;
}

export interface ContentResolverParams {
ipfsGateway?: IpfsGateway;
urlProxy?: UrlProxy | string;
}

export interface GameFiInitializationParams {
/**
* @defaultValue testnet
Expand All @@ -30,16 +42,24 @@ export interface GameFiInitializationParams {
* like Phaser `createConnectButton` or draw connect button by yourself.
* @defaultValue headless mode
*/
connector?: WalletConnector | WalletConnectorOptions;
connector?: WalletConnector | WalletConnectorParams;
/**
* TonClient instance or only its params.
*/
client?: TonClient | TonClientOptions;
client?: TonClient | TonClientParams;
/**
* Loading collections, NFTs, etc. information requires requests to external resources.
* Some of those resources may block direct requests from browsers by CORS policies.
* Pass function or template string which will be used to generate proxy URL. For example:
* `http://localhost:3000/cors-passthrough?url=%URL%` - %URL% will be replaced by URL
* your proxy server should follow.
*/
contentResolver?: ContentResolverParams;
/**
* TON wallet address and jetton wallet address of in-game shop.
* In-game purchases will be send to those addresses.
*/
merchant?: MerchantInitialization;
merchant?: MerchantParams;
}

export interface Merchant {
Expand All @@ -50,6 +70,7 @@ export interface Merchant {
export interface GameFiConstructorParams {
walletConnector: WalletConnector;
tonClient: TonClient;
contentResolver: ContentResolver;
merchant?: Merchant;
}

Expand All @@ -61,6 +82,7 @@ export interface GameFiConstructorParams {
export abstract class GameFiBase {
public readonly walletConnector: WalletConnector;
public readonly tonClient: TonClient;
public readonly contentResolver: ContentResolver;
public readonly merchant?: Merchant;

private readonly nftCollectionManager: NftCollectionManager;
Expand All @@ -71,13 +93,18 @@ export abstract class GameFiBase {
constructor(params: GameFiConstructorParams) {
this.walletConnector = params.walletConnector;
this.tonClient = params.tonClient;
this.contentResolver = params.contentResolver;
if (params.merchant != null) {
this.merchant = params.merchant;
}

const transactionSender = new TonConnectSender(this.walletConnector);
this.nftCollectionManager = new NftCollectionManager(this.tonClient);
this.nftItemManager = new NftItemManager(this.tonClient, transactionSender);
this.nftItemManager = new NftItemManager(
this.tonClient,
transactionSender,
this.contentResolver
);
this.jettonManager = new JettonManager(this.tonClient, transactionSender);
this.paymentManager = new PaymentManager(this.jettonManager, transactionSender);
}
Expand Down Expand Up @@ -135,19 +162,37 @@ export abstract class GameFiBase {
if (client instanceof TonClient) {
tonClient = client;
} else {
let clientOptions: TonClientOptions;
let clientParams: TonClientParams;
if (client == null) {
const endpoint = await getHttpEndpoint({
network
});
clientOptions = {endpoint};
clientParams = {endpoint};
} else {
clientOptions = client;
clientParams = client;
}
tonClient = new TonClient(clientOptions);
tonClient = new TonClient(clientParams);
}

return {walletConnector, tonClient};
const contentResolverParams: ProxyContentResolverParams = {};
if (params.contentResolver != null) {
const {ipfsGateway, urlProxy} = params.contentResolver;
if (ipfsGateway != null) {
contentResolverParams.ipfsGateway = ipfsGateway;
}
if (urlProxy != null) {
if (typeof urlProxy === 'string') {
contentResolverParams.urlProxy = (url) => {
return urlProxy.replace(ProxyContentResolver.replaceable, url);
};
} else {
contentResolverParams.urlProxy = urlProxy;
}
}
}
const contentResolver = new ProxyContentResolver(contentResolverParams);

return {walletConnector, tonClient, contentResolver};
}

/**
Expand Down Expand Up @@ -271,9 +316,7 @@ export abstract class GameFiBase {
return typeof instance === 'object' && instance != null && 'openModal' in instance;
}

protected static createConnectUiWorkaround(
options: WalletConnectorOptions = {}
): WalletConnector {
protected static createConnectUiWorkaround(params: WalletConnectorParams = {}): WalletConnector {
// we need 100% TonConnectUI functionality, but without visual parts
// to reuse the logic, but not to implement fork, use the workaround
// todo remove this workaround
Expand All @@ -295,7 +338,7 @@ export abstract class GameFiBase {
document.body.appendChild(widgetRoot);

return new TonConnectUI({
...options,
...params,
buttonRootId: buttonRoot.id,
widgetRootId: widgetRoot.id
});
Expand Down
Loading