Skip to content

Commit

Permalink
EVM with SDK-2 (#174)
Browse files Browse the repository at this point in the history
* add evm docs

* make small fixes
  • Loading branch information
Maksandre authored Sep 18, 2024
1 parent 440ccd2 commit 8b61f78
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 24 deletions.
52 changes: 37 additions & 15 deletions docs/build/evm/accounts.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,55 @@
# Account mirrors
# Account

There are two types of accounts in Unique Network:

- Native substrate accounts. Generic substrate account looks like `5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY`
- Ethereum accounts, a 42-character hexadecimal string starting with `0x`
- Native substrate accounts. The generic substrate account looks like `5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY`.
- Ethereum accounts, a 42-character hexadecimal string starting with `0x`.

Because of different formats, substrate and ethereum addresses cannot interact directly. For example, you cannot send tokens from Metamask to the substrate address; it requires the ethereum format.
Because of different formats, substrate and ethereum addresses cannot interact directly. For example, you cannot send tokens with Metamask to the Substrate address.

However, it is possible to mix these two worlds thanks to account mirroring.

## Account mirrors
### Account mirrors

Mirroring is a mechanism that allows you to get address representation in a different format—substrate for ethereum address and ethereum for substrate.

You can play around with address converter in the [reference section](../../../../reference/tools.md).
You can play around with the address converter in the [reference section](../../../../reference/tools.md).

For example:

- Ethereum mirror for `5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY` is `0xd43593c715Fdd31c61141ABd04a99FD6822c8558`
- Substrate mirror for `0x1B8EeEC6eD7e9C6B98291A8274c006e251902Ef3` is `5FkhL2YH6rZD2AspxMBoUfFnA4GwWVKHVTbL1kChhYMvSq7B`
- Ethereum mirror for `5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY` is `0xd43593c715Fdd31c61141ABd04a99FD6822c8558`. When a substrate account calls contracts, the `msg.sender` will be its mirror.
- Substrate mirror for `0xd43593c715Fdd31c61141ABd04a99FD6822c8558 ` is `5FrLxJsyJ5x9n2rmxFwosFraxFCKcXZDngRLNectCn64UjtZ`

::: warning
It is not possible to calculate the original account from the mirror account. This is a one-way mapping because of the different sizes between EVM and Substrate accounts.
:::

#### Here are the primary use cases for mirrors

1. If you want to send tokens from a substrate account to an ethereum account, send them to the latter's substrate mirror.

2. The opposite operation works with one tradeoff. Tokens sent to the ethereum mirror of a substrate account will not directly top up the substrate account's balance. However, the substrate account can "withdraw" tokens from its ethereum mirror using the `api.tx.evm.withdraw` method.

The other question appears here. If the caller is a mirror, the beneficiary of a contract execution would also be the mirror, not the original Substrate address. For example, as a result of a `swap` on a DEX, all the tokens would be transferred to the mirror. How can this be solved?

> It is very important to note that you can not get the original account from the mirror account. Because of the different sizes, this is a one-way mapping.
#### Substrate account can transfer from its mirror

Here is the primary use case for mirrors:
- Native tokens, such as `UNQ` or `OPL`, can be withdrawn with `evm::withdraw` extrinsic
- All native `NFTs`, `Fungible`, and `ReFungible` can be transferred using [transferFrom](./tokens.md#transfer).

1. If you want to send tokens from substrate account to ethereum account - send it to it's substrate mirror.
However, this is not a great experience, so Unique provides a `CrossAddress` structure for Solidity.

2. The opposite operation works with one tradeoff. Tokens sent to the ethereum mirror of a substrate account will not directly top up the substrate account's balance. However, the substrate account can "withdraw" tokens from its ethereum mirror using `api.tx.evm.withdraw` method.
### Using `CrossAddress`

This struct represents an EVM or Substrate account in Solidity. It has two properties: `sub` for a Substrate account and `eth` for an EVM account. Only one property can be filled.

```Solidity
struct CrossAddress {
address eth;
uint256 sub;
}
```

- For the EVM account, set the `eth` property with the EVM address (0x...), and the `sub` should be 0.
- For the Substrate account, set the `sub` property with the substrate public key in the decimal format. The `eth` property should be equal to Ethereum zero address (0x000...00000);

## Code example

Expand All @@ -42,5 +65,4 @@ const subMirror = Address.mirror.ethereumToSubstrate('0x1B8EeEC6eD7e9C6B98291A82
// 5FkhL2YH6rZD2AspxMBoUfFnA4GwWVKHVTbL1kChhYMvSq7B
```


The following articles will teach you more advanced concepts that make the developer and user experience smoother.
21 changes: 18 additions & 3 deletions docs/build/sdk/v2/collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,11 +244,26 @@ Setting sponsorship of a collection should be done in several steps.

### Setting collection sponsor

First, we need to specify an account that will pay transaction fees.
Firstly, we need to specify an account that will pay transaction fees.

```ts:no-line-numbers
await sdk.collection.setSponsor({ collectionId, sponsor: alice.address });
```

<!-- TODO add confirm sponsorship -->
<!-- TODO add setting limits -->
Secondly, the specified account should confirm sponsorship

```ts:no-line-numbers
await sdk.collection.confirmSponsorship({ collectionId });
```

Finally, set sponsoring rate limits

```ts:no-line-numbers
await sdk.collection.setLimits({
collectionId,
limits: {
sponsorApproveTimeout: 0,
sponsorTransferTimeout: 0,
},
});
```
2 changes: 1 addition & 1 deletion docs/build/sdk/v2/dapps.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ To get started with the boilerplate, follow these steps:
... or just clone the repo with the following command:

```sh:no-line-numbers
git clone [<repository-url>](https://github.com/UniqueNetwork/unique-react-template)
git clone git@github.com:UniqueNetwork/unique-react-template.git
```

2. Install dependencies:
Expand Down
56 changes: 56 additions & 0 deletions docs/build/sdk/v2/evm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# EVM and Smart Contracts

Unique Network supports EVM tools and provides interfaces for native Collections and NFTs. In this article, you will learn how to interact with smart contracts using Unique SDK and Substrate accounts.

Learn [EVM section](../../evm/index.md) to better understand how EVM and substrate work together.

## How does it work

There is one question may appear at this moment:

EVM does not understand the Substrate address format – so what address will be `msg.sender`?

Unique provides an account mirroring mechanism to make it possible to call EVM smart contracts. Learn about it in the [EVM section](../../evm/accounts.md)

## Code examples

To call the contract, use `evm.send`:

```ts
// We assume you already know how to initialize SDK at this point
const sdk = UniqueChain(sdkConfig);

// Define an ABI object or import one from artifacts
const abi = [
{
inputs: [
{
internalType: "address",
name: "to",
type: "address",
},
{
internalType: "uint256",
name: "tokenId",
type: "uint256",
},
],
name: "transfer",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
];

const contractAddress = "0x123...";
const recipient = "0x456...";

const { extrinsicOutput } = await sdk.evm.send({
contract: {
abi,
address: contractAddress,
},
functionName: "transfer",
functionArgs: [recipient, 20],
});
```
6 changes: 3 additions & 3 deletions docs/build/sdk/v2/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ const account = Sr25519Account.fromUri(mnemonic);
// set "account" as a default signer
const sdk = UniqueChain({
baseUrl: "https://rest.unique.network/v2/opal",
account,
baseUrl: "https://rest.unique.network/v2/opal",
account,
});
```

Expand All @@ -62,7 +62,7 @@ const sdk = UniqueChain({
...
const balanceQuery = await sdk.balance.get({address: account.address});
console.log("Account's total balance:", balanceRequest.total);
console.log("Account's total balance:", balanceQuery.total);
```

The Unique SDK currently supports the following modules:
Expand Down
2 changes: 1 addition & 1 deletion docs/build/sdk/v2/sponsoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ At this point, every action with tokens of this collection, such as transfer or

## Setting limits

You may want to set limits on sponsorship to prevent your sponsorship account from being drained. We already discussed how to set limits in the [collection section](collections.md#collection-limits). Let's take a closet look on sponsorship-related limits.
You may want to set limits on sponsorship to prevent your sponsorship account from being drained. We already discussed how to set limits in the [collection section](collections.md#collection-limits). Let's take a closer look on sponsorship-related limits.

<!-- TODO setVariableMetadata is not the case anymore -->

Expand Down
3 changes: 2 additions & 1 deletion docs/build/sdk/v2/tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,4 +317,5 @@ In Unique Network every collection and token have unique ID. At the same time th

The concept of collections and token addresses is particularly useful when working with [smart contracts](../../evm/index.md).
:::


Under the hood all nested tokens are allowed to transferFrom for the topmost token owner. So the `unnest` is just a synthetic sugar, and you can transfer nested tokens directly to whatever address you want. See [transfer](#transfer)

0 comments on commit 8b61f78

Please sign in to comment.