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

feat: prepare sway scripts for mainnet #280

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 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
5 changes: 5 additions & 0 deletions .changeset/few-rivers-fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fuel-bridge/test-utils': minor
---

Improve sway scripts
6 changes: 4 additions & 2 deletions packages/test-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
"scripts": {
"build": "tsup",
"build:watch": "tsup --watch",
"deploy:bridge": "pnpm ts-node src/scripts/bridge.ts",
"deploy:relay": "pnpm ts-node src/scripts/relay-deposit.ts"
"bridge:deploy": "pnpm ts-node src/scripts/deploy-bridge.ts",
"bridge:upgrade": "pnpm ts-node src/scripts/upgrade-bridge.ts",
"bridge:transfer-ownership": "pnpm ts-node src/scripts/transfer-bridge-ownership.ts",
"bridge:relay": "pnpm ts-node src/scripts/relay-deposit.ts"
},
"peerDependencies": {
"fuels": "0.94.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import {
WalletUnlocked,
ZeroBytes32,
} from 'fuels';
import { password } from '@inquirer/prompts';

const { L1_TOKEN_GATEWAY, L2_SIGNER, L2_RPC } = process.env;
let { L1_TOKEN_GATEWAY, L2_SIGNER, L2_RPC } = process.env;

// This helper avoids an exception in the case that the contract
// was already deployed, and returns the contract instead
Expand All @@ -37,6 +38,11 @@ function fetchIfDeployed(provider: Provider, wallet: WalletUnlocked) {

const main = async () => {
const provider = await Provider.create(L2_RPC, { resourceCacheTTL: -1 });

if (!L2_SIGNER) {
L2_SIGNER = await password({ message: 'Enter private key' });
}

const wallet = Wallet.fromPrivateKey(L2_SIGNER, provider);

console.log('\t> L2 Bridge deployment script initiated');
Expand Down
83 changes: 52 additions & 31 deletions packages/test-utils/src/scripts/relay-deposit.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* This is a stand-alone script that deploys the
* fetches a deposit messages and relays it to the bridge
* This is a stand-alone script that
* fetches a deposit message and relays it to the bridge
*/

import { Proxy } from '@fuel-bridge/fungible-token';
Expand All @@ -16,6 +16,7 @@ import {
getPredicateRoot,
hexlify,
} from 'fuels';
import { password } from '@inquirer/prompts';
import {
FUEL_MESSAGE_TIMEOUT_MS,
debug,
Expand All @@ -25,11 +26,16 @@ import {

const TOKEN_RECIPIENT_DATA_OFFSET = 160;

const { L2_SIGNER, L2_RPC, L2_BRIDGE_ID, L2_MESSAGE_NONCE, L2_TOKEN_RECEIVER } =
let { L2_SIGNER, L2_RPC, L2_BRIDGE_ID, L2_MESSAGE_NONCE, L2_TOKEN_RECEIVER } =
process.env;

const main = async () => {
const provider = await Provider.create(L2_RPC, { resourceCacheTTL: -1 });

if (!L2_SIGNER) {
L2_SIGNER = await password({ message: 'Enter private key' });
}

const wallet = Wallet.fromPrivateKey(L2_SIGNER, provider);

const proxy = new Proxy(L2_BRIDGE_ID, wallet);
Expand All @@ -43,47 +49,58 @@ const main = async () => {
.proxy_target()
.dryRun()
.then((result) => {
debug('bridge_proxy.target() succeeded, assuming proxy');
debug(`.proxy_target() returned ${result.value.bits}, assuming proxy`);
return result.value.bits;
})
.catch(() => {
debug('bridge.proxy_target() errored, assuming not proxy');
debug('.proxy_target() errored, assuming not proxy');
return null;
});

const predicateRoot = getPredicateRoot(contractMessagePredicate);

let nonce: BN;
let endCursor: string | undefined;

if (L2_MESSAGE_NONCE) nonce = new BN(L2_MESSAGE_NONCE);
else {
const response = await provider.getMessages(predicateRoot);
if (!response.messages || response.messages.length === 0) {
console.log('No messages in the predicate');
return;
else
while (true) {
const response = await provider.getMessages(predicateRoot, {
after: endCursor,
});

if (!response.messages || response.messages.length === 0) {
console.log('No messages in the predicate');
return;
}

const { messages } = response;

const message = messages.find((message) => {
const hex = hexlify(message.data).replace('0x', '');
const recipient = hex.substring(
TOKEN_RECIPIENT_DATA_OFFSET * 2,
TOKEN_RECIPIENT_DATA_OFFSET * 2 + 64 // Recipient is 32 bytes
);
const expectedRecipient = L2_TOKEN_RECEIVER || wallet.address.toB256();

return recipient === expectedRecipient.replace('0x', '');
});

if (!message) {
if (response.pageInfo.hasNextPage) {
endCursor = response.pageInfo.endCursor;
continue;
} else {
console.log('No messages for the recipient');
return;
}
}

nonce = new BN(message.nonce);
break;
}

const { messages } = response;

const message = messages.find((message) => {
const hex = hexlify(message.data).replace('0x', '');
const recipient = hex.substring(
TOKEN_RECIPIENT_DATA_OFFSET * 2,
TOKEN_RECIPIENT_DATA_OFFSET * 2 + 64 // Recipient is 32 bytes
);
const expectedRecipient = L2_TOKEN_RECEIVER || wallet.address.toB256();

return recipient === expectedRecipient.replace('0x', '');
});

if (!message) {
console.log('No messages for the recipient');
return;
}

nonce = new BN(message.nonce);
}

const message = await waitForMessage(
provider,
new Account(predicateRoot).address,
Expand All @@ -105,6 +122,10 @@ const main = async () => {

if (txResult.status === TransactionStatus.success) {
console.log('\t> Transaction succeeded');
console.log(
'\t > Minted asset IDs: ',
txResult.mintedAssets.map((asset) => asset.assetId)
);
} else {
console.log('\t> Transaction errored');
}
Expand Down
73 changes: 73 additions & 0 deletions packages/test-utils/src/scripts/transfer-bridge-ownership.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* This is a stand-alone script that upgrades the bridge
*/

import { Proxy } from '@fuel-bridge/fungible-token';

import { Provider, Wallet } from 'fuels';
import { password } from '@inquirer/prompts';
import { debug } from '../utils';

let { L2_SIGNER, L2_RPC, L2_BRIDGE_ID, L2_NEW_OWNER } = process.env;

const main = async () => {
const provider = await Provider.create(L2_RPC, { resourceCacheTTL: -1 });

if (!L2_SIGNER) {
L2_SIGNER = await password({ message: 'Enter private key' });
}

const wallet = Wallet.fromPrivateKey(L2_SIGNER, provider);

const proxy = new Proxy(L2_BRIDGE_ID, wallet);

console.log('\t> L2 Bridge deployment script initiated');
console.log('\t> Loaded wallet', wallet.address.toB256());
console.log('\t> Balance: ', (await wallet.getBalance()).toString());

debug('Detecting if the bridge is a proxy...');
let owner: string | null = await proxy.functions
._proxy_owner()
.dryRun()
.then((result) => {
debug('bridge._proxy.owner() succeeded, assuming proxy');
return result.value.Initialized.Address.bits;
})
.catch((e) => {
debug(`bridge._proxy_owner() failed with error: `);
debug(`${JSON.stringify(e, undefined, 2)}`);
return null;
});

if (owner === null) {
console.log('Could not fetch the bridge owner, is it a proxy?');
return;
}

if (
owner.replace('0x', '').toLowerCase() !==
wallet.address.toB256().replace('0x', '').toLowerCase()
) {
console.log(`Owner mismatch, contract owned by ${owner}`);
return;
}

const addressInput = { bits: L2_NEW_OWNER };
const addressIdentityInput = { Address: addressInput };
const tx = await proxy.functions
._proxy_change_owner(addressIdentityInput)
.call();

console.log('\tTransaction ID: ', tx.transactionId);
await tx.waitForResult();
};

main()
.then(() => {
console.log('\t> Finished');
process.exit(0);
})
.catch((e) => {
console.error(e);
process.exit(1);
});
111 changes: 111 additions & 0 deletions packages/test-utils/src/scripts/upgrade-bridge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* This is a stand-alone script that upgrades the bridge
*/

import {
Proxy,
BridgeFungibleTokenFactory,
BridgeFungibleToken,
} from '@fuel-bridge/fungible-token';

import {
DeployContractResult,
Provider,
Wallet,
WalletUnlocked,
ZeroBytes32,
} from 'fuels';
import { password } from '@inquirer/prompts';
import { debug } from '../utils';

let { L1_TOKEN_GATEWAY, L2_SIGNER, L2_RPC, L2_BRIDGE_ID } = process.env;

// This helper avoids an exception in the case that the contract
// was already deployed, and returns the contract instead
function fetchIfDeployed(provider: Provider, wallet: WalletUnlocked) {
return async (tx: DeployContractResult) => {
const contract = await provider.getContract(tx.contractId);

if (!contract) return tx.waitForResult();
else {
await tx.waitForResult().catch(() => {});
return {
contract: new BridgeFungibleToken(contract.id, wallet),
};
}
};
}

const main = async () => {
const provider = await Provider.create(L2_RPC, { resourceCacheTTL: -1 });
if (!L2_SIGNER) {
L2_SIGNER = await password({ message: 'Enter private key' });
}
const wallet = Wallet.fromPrivateKey(L2_SIGNER, provider);

const proxy = new Proxy(L2_BRIDGE_ID, wallet);

console.log('\t> L2 Bridge deployment script initiated');
console.log('\t> Loaded wallet', wallet.address.toB256());
console.log('\t> Balance: ', (await wallet.getBalance()).toString());

debug('Detecting if the bridge is a proxy...');
let owner: string | null = await proxy.functions
._proxy_owner()
.dryRun()
.then((result) => {
debug('bridge._proxy.owner() succeeded, assuming proxy');
return result.value.Initialized.Address.bits;
})
.catch((e) => {
debug(`bridge._proxy_owner() failed with error: `);
debug(`${JSON.stringify(e, undefined, 2)}`);
return null;
});

if (owner === null) {
console.log('Could not fetch the bridge owner, is it a proxy?');
return;
}

if (
owner.replace('0x', '').toLowerCase() !==
wallet.address.toB256().replace('0x', '').toLowerCase()
) {
console.log(`Owner mismatch, contract owned by ${owner}`);
return;
}

const implConfigurables: any = {
BRIDGED_TOKEN_GATEWAY:
'0x000000000000000000000000' +
L1_TOKEN_GATEWAY.replace('0x', '').toLowerCase(),
};

const implementation = await BridgeFungibleTokenFactory.deploy(wallet, {
configurableConstants: implConfigurables,
salt: ZeroBytes32,
})
.then(fetchIfDeployed(provider, wallet))
.then(({ contract }) => contract);

console.log('Implementation at ', implementation.id.toB256());

const contractIdentityInput = { bits: implementation.id.toB256() };
const tx = await proxy.functions
.set_proxy_target(contractIdentityInput)
.call();

console.log('\tTransaction ID: ', tx.transactionId);
await tx.waitForResult();
};

main()
.then(() => {
console.log('\t> Finished');
process.exit(0);
})
.catch((e) => {
console.error(e);
process.exit(1);
});
6 changes: 4 additions & 2 deletions packages/test-utils/src/utils/fuels/relayCommonMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ type CommonMessageDetails = {
) => Promise<ScriptTransactionRequest>;
};

// Update for mainnet gas costs
const PREDICATE_GAS_LIMIT = 10000000;

// Details for relaying common messages with certain predicate roots
function getCommonRelayableMessages(provider: Provider) {
// Create a predicate for common messages
Expand Down Expand Up @@ -150,7 +153,7 @@ function getCommonRelayableMessages(provider: Provider) {
});
transaction.witnesses.push(ZeroBytes32);

transaction.gasLimit = bn(500_000);
transaction.gasLimit = bn(PREDICATE_GAS_LIMIT);

debug(
'-------------------------------------------------------------------'
Expand Down Expand Up @@ -229,7 +232,6 @@ export async function relayCommonMessage(
}

estimated_tx.maxFee = fees.maxFee;
estimated_tx.gasLimit = fees.gasLimit.mul(4).div(3);

const simulation = await relayer.simulateTransaction(estimated_tx);
debug(simulation);
Expand Down
Loading
Loading