Skip to content

Commit

Permalink
Merge branch 'dev' into fix-mangata-weight-to-fee
Browse files Browse the repository at this point in the history
  • Loading branch information
imstar15 committed Dec 4, 2023
2 parents 11adbb4 + 36c4322 commit d135a0e
Show file tree
Hide file tree
Showing 15 changed files with 382 additions and 188 deletions.
Binary file modified .yarn/install-state.gz
Binary file not shown.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,14 @@ Run the following command to install the necessary dependencies:
yarn # Please use yarn to install dependencies due to the use of Yarn Workspace
```

### Running Foundational Tests
### Maintaining dependencies across packages
The packages are referring each other by source code, so when one is updated, the new version will be used by other packages. For example, ./packages/sdk/package.json has the following dependency:
```
"@oak-network/adapter": "../adapter",
"@oak-network/config": "../config"
```

### Running Functional Tests
By default, the tests are configured to target your local development environment. Before running any commands, please follow the steps in the [Quickstart: run Local Network with Zombienet](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9946#/accounts) guide to build and run a local relay chain and parachain.

Once the Turing Dev network is running, you should be able to see it on [polkadot.js.org/apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9946#/accounts).
Expand Down
4 changes: 3 additions & 1 deletion packages/adapter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
"clean": "tsc --build --clean"
},
"dependencies": {
"@oak-network/config": "workspace:^1.0.0",
"@oak-network/config": "../config",
"@polkadot/api": "^10.9.1",
"@polkadot/keyring": "^12.6.1",
"@polkadot/types": "^10.11.1",
"@polkadot/util": "^12.6.1",
"@polkadot/util-crypto": "^12.6.1",
"bn.js": "^5.2.1",
"lodash": "^4.17.21",
"web3-validator": "^2.0.3"
Expand Down
78 changes: 75 additions & 3 deletions packages/adapter/src/chains/oak.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,23 @@ import type { SubmittableExtrinsic, AddressOrPair } from "@polkadot/api/types";
import type { u32, u128, Option } from "@polkadot/types";
import type { WeightV2 } from "@polkadot/types/interfaces";
import type { KeyringPair } from "@polkadot/keyring/types";
import { Weight, XcmInstructionNetworkType } from "@oak-network/config";
import {
Weight,
XcmInstructionNetworkType,
Chain,
XToken,
} from "@oak-network/config";
import { ISubmittableResult } from "@polkadot/types/types";
import { ChainAdapter } from "./chainAdapter";
import { getDerivativeAccountV2, sendExtrinsic } from "../util";
import { SendExtrinsicResult } from "../types";
import {
getDerivativeAccountV2,
isValidAddress,
sendExtrinsic,
getDecimalBN,
} from "../util";
import { AccountType, SendExtrinsicResult } from "../types";
import { WEIGHT_REF_TIME_PER_SECOND } from "../constants";
import { InvalidAddress } from "../errors";

export interface AutomationPriceTriggerParams {
chain: string;
Expand Down Expand Up @@ -105,6 +117,61 @@ export class OakAdapter extends ChainAdapter {
.div(WEIGHT_REF_TIME_PER_SECOND);
}

/**
*
* @param destConfig
* @param token The key of the Asset such as "tur", or "sdn"
* @param recipient
* @param amount
* @returns
*/
public transferMultiasset(
destConfig: Chain,
token: string,
recipient: string,
amount: string | number,
):
| SubmittableExtrinsic<"promise", ISubmittableResult>
| SubmittableExtrinsic<"rxjs", ISubmittableResult>
| undefined {
const asset = _.find(this.chainConfig.assets, (item) => item.key === token);
if (_.isUndefined(asset)) throw new Error(`Asset ${token} not found`);

const amountBN = new BN(amount).mul(getDecimalBN(asset.decimals));

const accountId = destConfig.isEthereum
? { [AccountType.AccountKey20]: { key: recipient, network: null } }
: { [AccountType.AccountId32]: { id: recipient, network: null } };

if (!isValidAddress(recipient, destConfig.isEthereum)) {
throw new InvalidAddress(recipient);
}

// const weightLimit: XcmV3WeightLimit = { isUnlimited: true };

return this.api?.tx.xTokens.transferMultiasset(
{
V3: {
fun: { Fungible: amountBN },
id: { Concrete: asset.location },
},
},
{
V3: {
interior: {
X2: [{ Parachain: destConfig.paraId }, accountId],
},
parents: 1,
},
},
"Unlimited",
);
}

public getAssetBySymbol(symbol: string): XToken | undefined {
return _.find(this.chainConfig.assets, (asset) => asset.symbol === symbol);
}

/**
* Execute a cross-chain transfer
* @param destination The location of the destination chain
Expand All @@ -125,6 +192,11 @@ export class OakAdapter extends ChainAdapter {
if (_.isUndefined(key)) throw new Error("chainConfig.key not set");
const api = this.getApi();

// if isEthereum accountId20: {key: recipient, network: null}
// if (!validateAddress(address, useAccountKey20 ? "ethereum" : "substract")) {
// throw new InvalidAddress(address);
// }

const extrinsic = api.tx.xTokens.transferMultiasset(
{
V3: {
Expand Down
52 changes: 42 additions & 10 deletions packages/adapter/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import { KeyringPair } from "@polkadot/keyring/types";
import type { SubmittableExtrinsic } from "@polkadot/api/types";
import type { HexString } from "@polkadot/util/types";
import { TypeRegistry } from "@polkadot/types";
import { blake2AsU8a } from "@polkadot/util-crypto";
import {
blake2AsU8a,
encodeAddress,
decodeAddress,
} from "@polkadot/util-crypto";
import { isAddress as isEthereumAddress } from "web3-validator";
import BN from "bn.js";
import { AccountType, SendExtrinsicResult } from "./types";

/**
Expand Down Expand Up @@ -58,7 +64,7 @@ export const sendExtrinsic = async (
);

if (status.isFinalized) {
resolve({ events, blockHash: status.asFinalized.toString() });
resolve({ blockHash: status.asFinalized.toString(), events });
}
}
},
Expand All @@ -80,13 +86,13 @@ export const getDerivativeAccountV2 = (
{ locationType = "XcmV2MultiLocation", network = "Any" } = {},
): HexString => {
const account =
hexToU8a(accountId).length == 20
? { AccountKey20: { network, key: accountId } }
: { AccountId32: { network, id: accountId } };
hexToU8a(accountId).length === 20
? { AccountKey20: { key: accountId, network } }
: { AccountId32: { id: accountId, network } };

const location = {
parents: 1,
interior: { X2: [{ Parachain: paraId }, account] },
parents: 1,
};
const multilocation = api.createType(locationType, location);
const toHash = new Uint8Array([
Expand All @@ -111,7 +117,7 @@ export const getDerivativeAccountV3 = (
deriveAccountType: AccountType = AccountType.AccountId32,
): HexString => {
const accountType =
hexToU8a(accountId).length == 20 ? "AccountKey20" : "AccountId32";
hexToU8a(accountId).length === 20 ? "AccountKey20" : "AccountId32";
const decodedAddress = hexToU8a(accountId);

// Calculate Hash Component
Expand Down Expand Up @@ -148,9 +154,9 @@ export const getDerivativeAccountV3 = (
export function convertAbsoluteLocationToRelative(absoluteLocation: any): any {
const { interior } = absoluteLocation;
const key = _.keys(interior)[0] as string;
const sectionCount = parseInt(key.substring(1));
const sectionCount = parseInt(key.substring(1), 10);
if (sectionCount === 1) {
return { parents: 0, interior: "Here" };
return { interior: "Here", parents: 0 };
}
const newInterior: Record<string, any> = {};
const newArray = interior[key].filter(
Expand All @@ -160,5 +166,31 @@ export function convertAbsoluteLocationToRelative(absoluteLocation: any): any {
const newXKey = `X${newArray.length}`;
newInterior[newXKey] = newArray.length === 1 ? newArray[0] : newArray;
}
return { parents: 0, interior: newInterior };
return { interior: newInterior, parents: 0 };
}

function isSubstrateAddress(address: string) {
try {
encodeAddress(decodeAddress(address));

return true;
} catch (e) {
// ignore error
}

return false;
}

export function isValidAddress(address: string, isEthereum: boolean) {
return isEthereum ? isEthereumAddress(address) : isSubstrateAddress(address);
}

/**
* Return a BN object for the power of 10, for example getDecimalBN(10) returns new BN(10,000,000,000)
* @param {*} decimals The decimals number of a token
*/
export function getDecimalBN(decimals: number | string) {
const base = new BN(10, 10);
const power = new BN(decimals, 10);
return base.pow(power);
}
10 changes: 9 additions & 1 deletion packages/config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
"license": "Apache-2.0",
"main": "./build/index.js",
"scripts": {
"build": "tsc"
"build": "tsc --build",
"clean": "tsc --build --clean"
},
"devDependencies": {
"@types/bn.js": "^5",
"typescript": "^5.3.2"
},
"dependencies": {
"bn.js": "^5.2.1"
}
}
91 changes: 47 additions & 44 deletions packages/config/src/chains/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,57 +4,60 @@ import { createChain } from "./types/Chain";
import { DevTokens } from "../tokens";

const shibuya = createChain({
key: "shibuya",
name: "Shibuya",
assets: [{ asset: DevTokens.sby, isNative: true }],
endpoint: "ws://127.0.0.1:9948",
relayChain: "local",
xcm: {
network: "rococo",
instructionWeight: new Weight(new BN("1000000000"), new BN(64 * 1024)),
},
assets: [{ asset: DevTokens.sby, isNative: true }],
endpoint: "ws://127.0.0.1:9948",
isEthereum: true,
key: "shibuya",
name: "Shibuya",
relayChain: "local",
xcm: {
instructionWeight: new Weight(new BN("1000000000"), new BN(64 * 1024)),
network: "rococo",
},
});

const turingLocal = createChain({
key: "turing-local",
name: "Turing Local",
assets: [
{ asset: DevTokens.tur, isNative: true },
{ asset: DevTokens.sby, isNative: false },
],
endpoint: "ws://127.0.0.1:9946",
relayChain: "local",
xcm: {
network: "rococo",
instructionWeight: new Weight(new BN("1000000000"), new BN(0)),
},
assets: [
{ asset: DevTokens.tur, isNative: true },
{ asset: DevTokens.sby, isNative: false },
],
endpoint: "ws://127.0.0.1:9946",
key: "turing-local",
name: "Turing Local",
relayChain: "local",
xcm: {
instructionWeight: new Weight(new BN("1000000000"), new BN(0)),
network: "rococo",
},
});

const mangataLocal = createChain({
key: "mangata-local",
name: "Mangata Local",
assets: [
{ asset: DevTokens.mgr, isNative: true },
{ asset: DevTokens.tur, isNative: false },
],
endpoint: "ws://127.0.0.1:9947",
relayChain: "local",
xcm: {
network: "rococo",
instructionWeight: new Weight(new BN("150000000"), new BN("0")),
},
assets: [
{ asset: DevTokens.mgr, isNative: true },
{ asset: DevTokens.tur, isNative: false },
],
endpoint: "ws://127.0.0.1:9947",
key: "mangata-local",
name: "Mangata Local",
relayChain: "local",
xcm: {
instructionWeight: new Weight(new BN("150000000"), new BN("0")),
network: "rococo",
},
});

const moonbaseLocal = createChain({
key: "moonbase-local",
name: "Moonbase Local",
assets: [{ asset: DevTokens.moonbaseLocal, isNative: true }],
endpoint: "ws://127.0.0.1:9949",
relayChain: "local",
xcm: {
network: "rococo",
instructionWeight: new Weight(new BN("250000000"), new BN("10000")),
},
});
assets: [{ asset: DevTokens.moonbaseLocal, isNative: true }],
endpoint: "ws://127.0.0.1:9949",
isEthereum: true,
key: "moonbase-local",
name: "Moonbase Local",
relayChain: "local",
xcm: {
instructionWeight: new Weight(new BN("250000000"), new BN("10000")),
network: "rococo",
},
});

export default { turingLocal, shibuya, mangataLocal, moonbaseLocal };
// eslint-disable-next-line import/no-default-export
export default { mangataLocal, moonbaseLocal, shibuya, turingLocal };
1 change: 1 addition & 0 deletions packages/config/src/chains/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ export {
PolkadotChains,
Weight,
};

export type { Chain, XcmConfig };
Loading

0 comments on commit d135a0e

Please sign in to comment.