Skip to content

Commit

Permalink
Unity SDK docs, phase 2 (#212)
Browse files Browse the repository at this point in the history
* First draft of Unity quickstart

* Working with listeners

* Next steps

* It uses Beacon

* Handle wallet setup in another topic

* Trim setup steps

* Wallet connection in simpler  terms

* tweaks

* indenting

* Getting token balances

* typo

* unnecessary comma

* events

* Managing tokens

* Getting token info

* Smarter filtering

* Looking up tokens on a block explorer

* Put the beacon info in the right place

* account that originates is the admin

* These are capitalized

* the destination account

* Distinguish convenience method from entrypoint

* Consistency

* clarifications

* Basic signing

* Correct way to install per Berk

* typo

* Clarify signing, but still not quite sure of it

* Link to instructions for setting up a wallet

* Clarify VerifySignedPayload

* First draft of Unity quickstart

* Re-enable Unity overview page

* walletconnection scene

* Contract scene

* Transfer scene

* Update walletconnection scene

* transfer scene update;

* wip

* info about prefabs

* dappmetadata object

* API, MessageReceiver, and TokenContract objects

* link to messagereceiver object

* TODO about IPFS and metadata

* New automated wallet type selection

* Metadata is predefined due to limitation in Beacon

* typo

* How to handle ipfs

* New TezosAuthenticator prefab

* Can also use IPFS directly

* link to install instructions

* Remove qr code info now that the prefab handles it all for you

* Trim down getting info about wallets

* Got this backwards somehow

* Trim these sections to focus on the code

* Trim signing section

* basic info on kukai, more needed

* Working on connection reference

* This is tzip-10, not 7

* Consistency in headings

* New IPFS upload scene

* Move scenes to a separate page

* IPFS upload scene

* WIP docs for API object

* Docs for dappmetadata object

* WIP docs for messagereceiver object

* WIP docs for TokenContract object

* They are read-only

* Not all of these fields are implemented

* Correction

* Working now

* oops

* Move Deploy up top

* Clarify which classes these objects come from

* Clarify signing response

* Handle JSON data

* Getting more info from the block explorer to populate the token object

* Tweaks

* Info for container topic

* Per Berk, don't use the constructors

* Spacing

* What's a counter?

* Put prefabs and objects in different sections

* GetContractMetadata is working now

* Tweaks

* Reference link

* Rework scenes to be more of what unity devs need

* Simplify

* This hash may change

* Location of the source

* OriginateContract method

* links

* Put unity docs in their own section

* Separate section for Unity SDK

* Remove reference to MainThreadExecutor

* Simplified code in quickstart

Co-authored-by: Can Berk T. <[email protected]>

* Clarify signing code in quickstart

Co-authored-by: Can Berk T. <[email protected]>

* Lost a closing fence here

* Updated scene info

* Update screencaps to not show mobile border

* reorganize images into a unity folder

* Move prefabs up because they are important

* update info on prefabs

* TezosConfig object

* updates to tutorial scenes

* SDKInitialized event

* AccountConnected and AccountDisconnected are now WalletConnected

* MessageReceiver is now EventManager

* timeout property

* Updated tutorial scene setup

* changes to quickstart tasks

* New SOs im place of the TezosConfig object

* WIP page on connecting to accounts

* Working on connecting accounts

* Not sure if this is exactly what devs need

* Explain connection methods

* Task-based topics on contracts and tokens

* Correct links after rebase and  refactor

* Details about getting the contract address

* Calling the contract

* link to list of entrypoints

* Link to list of entrypoints

* Simplify

* Trying to get the right way to encode complex params

* I've been using an overcomplicated way of calling contracts

* Merge calling contracts sections and expand param encoding section

* Complex param example: update_operators

* Revert changes that should be in phase 1

* Keep change from phase 1

* example scene => tutorial scene

* Remove imports from code examples

* Remove MainThreadExecutor prefab

* No underscores, for consistency

* reorganize images into a unity folder

* tweaks

* AccountConnected and AccountDisconnected are now WalletConnected

* MessageReceiver is now EventManager

* Updates based on release version changes

* rebase fail

* QRCodeView is now QrCodeGenerator

Co-authored-by: Can Berk T. <[email protected]>

---------

Co-authored-by: Can Berk T. <[email protected]>
  • Loading branch information
timothymcmackin and oskar-ziller authored Jan 25, 2024
1 parent c2ffabd commit dc18ff7
Show file tree
Hide file tree
Showing 5 changed files with 540 additions and 0 deletions.
80 changes: 80 additions & 0 deletions docs/unity/connecting-accounts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
title: Connecting accounts
authors: Tim McMackin
last_update:
date: 11 January 2024
---

Connecting to a user's wallet is a prerequisite to working with Tezos in any application.
Accessing the wallet allows your project to see the tokens in it and to prompt the user to submit transactions, but it does not give your project direct control over the wallet.
Users still confirm or reject all transactions in their wallet application, so you must handle both of these use cases.

Using a wallet application in this way saves you from having to implement payment processing and security in your application.
Game developers can also use the wallet and its account as a unique account identifier and as the user's inventory.

For an example of connecting to wallets, see the [WalletConnection tutorial scene](./scenes#wallet-connection-scene).

## Best practices

When working with wallets, be sure to follow the advice in [Best practices and avoiding flaws](../dApps/best-practices) for wallet connections.
For example, don't force the user to connect their wallet as soon as the application loads.
Instead, let them see the application first.
Also, provide a prominent disconnect button to allow users to disconnect one account and connect a different one.

## The `TezosAuthenticator` prefab

The `TezosAuthenticator` prefab provides the tools that you need to connect to user's Tezos wallets in a Unity project.
You can copy the `TezosAuthenticator` and `TezosManager` prefabs to your scene, and the `TezosAuthenticator` prefab automatically adds features that connect to users' wallets.

## Connection methods

This table shows the ways that the SDK can connect to wallets and which platforms they are appropriate for:

Connection method | Description | Web platform (WebGL) | Mobile apps | Standalone applications
--- | --- | --- | --- | ---
QR code | Users scan a QR code with a wallet app | Yes | No | Yes
Deep link | The application opens the user's wallet app directly | Yes | Yes | No
Social wallets | The application opens the user's Kukai web-based wallet | Yes | No | No

Regardless of the connection method, the Tezos SDK for Unity runs the `WalletConnected` or `WalletConnectionFailed` event, as appropriate.
For more information about events, see the [Unity SDK EventManager object](./reference/EventManager).

<!-- TODO info about handshakes? -->
<!-- TODO info about persistent Beacon connections; do developers need to know where to store them? Do they put them in a database or something? -->

### QR code connections

This method generates a QR code that a user scans with their wallet application:

1. The Unity application calls the [`Wallet.Connect()`](./reference/Wallet#connect) method with the `walletProvider` parameter set to `WalletProviderType.beacon` to send a connection request to a wallet application via the [TZIP-10 protocol](https://gitlab.com/tezos/tzip/-/tree/master/proposals/tzip-10).
1. The wallet returns a handshake that includes pairing information for the wallet, which triggers the `HandshakeReceived` event.
1. From the handshake information, the SDK generates a QR code.
The `TezosAuthenticator` prefab handles the QR code generation with the `QrCodeGenerator` class.
1. The user scans the QR code with their wallet app and approves the connection.
1. The SDK receives the connection approval, which triggers the `WalletConnected` event and includes information about the connected account.

### Deep link connections

Deep link connections open the user's wallet app directly, which can be a mobile app or a browser extension.
This method relies on the Beacon SDK to interact with wallet apps:

1. The Unity WebGL application calls the [`Wallet.Connect()`](./reference/Wallet#connect) method with the `walletProvider` parameter set to `WalletProviderType.beacon`.
The Beacon SDK detects that it is running in a web application and opens a popup window with the wallets that Beacon can connect to:

<img src="/img/unity/unity-connecting-beacon-popup.png" alt="Beacon popup window with wallet types including Temple and Umami" style={{width: 300}} />

1. The [Beacon](https://walletbeacon.io/) SDK handles the process of connecting to the wallet.
1. The SDK receives the connection approval, which triggers the `WalletConnected` event and includes information about the connected account.

### Social connections

Social wallets exist as accounts managed by web apps such as [Kukai](https://kukai.app/).

To connect to a social wallet, the Unity WebGL application calls [`Wallet.Connect()`](./reference/Wallet#connect) with the `walletProvider` parameter set to `WalletProviderType.kukai`.

<!-- TODO Get this working and cover the steps -->

## Disconnecting

It's important to provide a disconnect button so the user can disconnect when they are finished with the application or if they want to connect with a different account.
To disconnect the active wallet, call the [`Wallet.Disconnect()`](./reference/Wallet#disconnect) method.
300 changes: 300 additions & 0 deletions docs/unity/managing-contracts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
---
title: Managing contracts
authors: Tim McMackin
last_update:
date: 18 December 2023
---

Smart contracts are backend programs that run on the Tezos blockchains.
Smart contracts can do many tasks, but for gaming they have two main purposes:

- They handle tokens, which are digital assets stored on the blockchain
- They provide backend logic that users can trust because it cannot change

For more information about contracts, see [Smart contracts](../smart-contracts).

You can create your own smart contracts or use the built-in contract that the SDK provides for managing tokens in Unity projects.

The Contract tutorial scene shows how to deploy a copy of the built-in contract from a Unity project.

## The built-in contract

The SDK includes a built-in contract that you can use to manage tokens for your Unity projects.

The contract has entrypoints that allow you to create and transfer tokens.
See [Managing tokens](./managing-tokens).

The Michelson source code of the built-in contract is in the `Resources/Contracts` folder of the SDK, but it isn't very human-readable.
For a list of the entrypoints in the contract, see [TokenContract object](./reference/TokenContract).

## Deploying the built-in contract

To deploy the built-in contract, call the [`TokenContract.Deploy()`](./reference/TokenContract#deploy) method and pass a callback function:

```csharp
public void DeployContract()
{
TezosManager
.Instance
.Tezos
.TokenContract
.Deploy(OnContractDeployed);
}

private void OnContractDeployed(string contractAddress)
{
Debug.Log(contractAddress);
}
```

The project sends the deployment transaction to the connected wallet, which must approve the transaction and pay the related fees.
The callback function receives the address of the deployed contract, which the project uses to send requests to the contract.
It can take a few minutes for the contract to deploy and be confirmed in multiple blocks on the blockchain.

The address that deployed the contract becomes the administrator of the contract and is the only account that can create tokens.

The SDK provides information about the contract such as its address in the [`TokenContract`](./reference/TokenContract) object.
You can use block explorers such as [Better Call Dev](https://better-call.dev/) to see information about the deployed contract.

For information about using the built-in contract, see [Managing tokens](./managing-tokens).

## Getting the contract address

When you deploy a contract with the [`TokenContract.Deploy()`](./reference/TokenContract#deploy) method, the SDK saves the contract address by running this code:

```csharp
PlayerPrefs.SetString("CurrentContract:" + Tezos.Wallet.GetActiveAddress(), contractAddress);
```

Then during SDK initialization, the SDK saves the address to the [`TokenContract.Address`](./reference/TokenContract) property.

To retrieve the address of contracts that you haven't deployed through the project, you can use the [`API.GetOriginatedContractsForOwner()`](./reference/API#getoriginatedcontractsforowner) method.

## Calling contracts

The built-in contract has convenience methods for minting and transferring tokens; see [Managing tokens](./managing-tokens).

To call the contract's other entrypoints, use the [`Wallet.CallContract()`](./reference/Wallet#callcontract) method.
For example, to call the contract's `set_administrator` entrypoint to set a new administrator account, use this code:

```csharp
TezosManager.Instance.Tezos.Wallet.CallContract(
contractAddress: TezosManager.Instance.Tezos.TokenContract.Address,
entryPoint: "set_administrator",
input: new MichelineString(newAdminAddress).ToJson()
);
```

For information about the entrypoints in the built-in contract, see [Unity SDK TokenContract object](./reference/TokenContract#entrypoints).

You can call any other contract by using its address, entrypoint name, and parameter value, as in this example:

```csharp
TezosManager.Instance.Tezos.Wallet.CallContract(
contractAddress: address,
entryPoint: entryPointName,
input: new MichelineInt(12).ToJson()
);
```

This example passes the value 12 to the entrypoint in the variable `entryPointName`.

Note that the parameter is encoded as a Michelson value.
For information about encoding more complex parameters, see [Encoding parameters](#encoding-parameters).

To get the hash of the transaction, use the `ContractCallCompleted` event.

## Encoding parameters

When you call contract entrypoints or views with the `Wallet.CallContract()` or `Wallet.ReadView()` methods, you must encode the parameter as a Micheline value.
For example, if an entrypoint accepts two integers and one string as parameters, you must pass a list of two `Netezos.Encoding.MichelineInt` values and one `Netezos.Encoding.MichelineString` value:

```csharp
var input = new MichelinePrim
{
Prim = PrimType.Pair,
Args = new List<IMicheline>
{
new MichelineInt(1),
new MichelineInt(2),
new MichelineString("My string value")
}
}.ToJson();

TezosManager.Instance.Tezos.Wallet.CallContract(
contractAddress: address,
entryPoint: entryPointName,
input: input
);
```

You can also use the value of the parameters in Michelson JSON.
The previous example looks like this with a JSON parameter value:

```csharp
var input = @"{
""prim"": ""Pair"",
""args"": [
{
""int"": ""1""
},
{
""prim"": ""Pair"",
""args"": [
{
""int"": ""2""
},
{
""string"": ""My string value""
}
]
}
]
}";

TezosManager.Instance.Tezos.Wallet.CallContract(
contractAddress: address,
entryPoint: entryPointName,
input: input
);
```

Some block explorers allow you to fill in parameter values for an entrypoint and then download the Michelson JSON to use in your code.

You can build more complex parameters out of `Netezos.Encoding` objects.
For example, the built-in contract has an entrypoint named `update_operators`, which is an FA2 standard entrypoint that gives an account control over another account's tokens.
It accepts a list of changes to make to token operators, each including these fields in this order:

- Either "add_operator" or "remove_operator"
- The address of the operator, which will be able to control the owner's tokens of the specified ID.
- The ID of the token
- The address of the token owner

This is the Michelson parameter type for the endpoint:

```
(list %update_operators (or
(pair %add_operator (address %owner)
(pair (address %operator)
(nat %token_id)))
(pair %remove_operator (address %owner)
(pair
(address %operator)
(nat %token_id)))))
```

In this case, you set the "add_operator" value by passing a `PrimType.Left` Michelson primitive or the "remove_operator" value by passing a `PrimType.Right` primitive.
The values in the primitive are a series of nested pairs called a [right comb](../smart-contracts/data-types/complex-data-types#right-combs), as in this example:

```json
{
"prim": "LEFT",
"args": [
{
"prim": "Pair",
"args": [
{
"string": "tz1QCVQinE8iVj1H2fckqx6oiM85CNJSK9Sx"
},
{
"prim": "Pair",
"args": [
{
"string": "tz1hQKqRPHmxET8du3fNACGyCG8kZRsXm2zD"
},
{
"int": "1"
}
]
}
]
}
]
}
```

The code to create a list of these elements to pass to the entrypoint looks like this:

```csharp
var operatorAddress = "tz1hQKqRPHmxET8du3fNACGyCG8kZRsXm2zD";
var ownerAddress = "tz1QCVQinE8iVj1H2fckqx6oiM85CNJSK9Sx";
int[] tokenIds = {1, 2, 3};

var operatorArray = new MichelineArray();
foreach (var tokenId in tokenIds)
{
operatorArray.Add(new MichelinePrim
{
Prim = PrimType.Left,
Args = new List<IMicheline>
{
new MichelinePrim
{
Prim = PrimType.Pair,
Args = new List<IMicheline>
{
new MichelineString(ownerAddress),
new MichelinePrim
{
Prim = PrimType.Pair,
Args = new List<IMicheline>
{
new MichelineString(operatorAddress),
new MichelineInt(tokenId)
}
}

}
}
}
});
};

TezosManager.Instance.Tezos.Wallet.CallContract(
contractAddress: address,
entryPoint: "update_operators",
input: operatorArray.ToJson()
);
```

## Deploying other contracts

To deploy a contract from Unity, you must compile the contract to Michelson in JSON format.
For example, to compile a contract in LIGO to Michelson JSON, run this code:

```bash
ligo compile contract MyContract.jsligo \
-m MyContract -o MyContract.json --michelson-format json
```

Then, ensure that the code of the code and initial storage value of the contract are wrapped in `code` and `storage` fields at the root of the file, as in this example:

```json
{
"code": [
{
"prim": "parameter",
"args": [
...
},
],
"storage": {
"int": "0"
}
}
```

To deploy the contract from the Unity project, use the [`Wallet.OriginateContract()`](./reference/Wallet#originatecontract) method, as in this example:

```csharp
var contractJSON = Resources.Load<TextAsset>("Contracts/MyContract").text;
TezosManager.Instance.Tezos.Wallet.OriginateContract(contractJSON);
```

To get the address of the deployed contract, use the `ContractCallCompleted` event.


<!-- TODO:
- Can you deploy a contract for each user?
- Managing multiple contracts?
-->
Loading

0 comments on commit dc18ff7

Please sign in to comment.