How can I choose my own smart contract addresses on RSK before deploying it? - solidity

I have noticed that some smart contracts
have addresses that start with 0x0000, 0x1234, or0x1337 - and I'm not sure how the deployers managed to do this.
​
Is it possible to do this on RSK?

Building upon the previous answer,
using the CREATE2 opcode -
it is not only possible to predict the address
that a smart contract will be deployed at,
but also (partially) choose the address
that you would like it to be deployed at.
For example, if you want a vanity address that starts
with 4 leading zeroes, you use the following helper function,
which checks for a match of the required vanity address:
function hasLeadingZeros(address = '0x0000', zeros = 4) {
for (let i = 2; i <= zeros + 1; i += 1) {
if (address.charAt(i) !== '0') return false;
}
return true;
}
The next helper function uses trial and error,
since keccak256 as with other hashes are 1-way functions,
to determine which salt parameter will result
in obtaining a required vanity address.
function getSaltForVanityAddress(deployerAddress, initCodeHash) {
let salt = 0;
let vanityAddress = '';
let saltHash;
while (!hasLeadingZeros(vanityAddress)) {
salt += 1;
saltHash = ethers.utils.keccak256(salt);
vanityAddress = ethers.utils.getCreate2Address(
deployerAddress,
saltHash,
initCodeHash,
);
}
return saltHash;
}
By combine the above, you can use
factory.deployCreate2(salt);
to deploy a smart contract with the address needed.
Here is a test case to illustrate:
it('Should deploy Child to the address starting with four zeros', async () => {
const Child = await ethers.getContractFactory('Child');
const { data: initCode } =
Child.getDeployTransaction(deployer.address);
const initCodeHash = ethers.utils.keccak256(initCode);
const salt = getSaltForVanityAddress(factory.address, initCodeHash);
const deployTx = await factory.deployCreate2(salt);
const txReceipt = await deployTx.wait();
const deployEvent = txReceipt.events.find(
(event) => event.event === 'ContractDeployed',
);
expect(hasLeadingZeros(
deployEvent.args.childContract)
).to.be.true;
console.log(
`Found salt '${salt}' such that the\ndeployed s/c address is ${deployEvent.args.childContract}`,
);
});
Found salt '0xb20ba450430132a5f0191bd27fc7e8018b39435484af81bbdf289296ae61ea75' such that the
deployed s/c address is 0x0000b36619Df7e2816577549b78CBB8b189e8d6B
✔ Should deploy Child to the address starting with four zeros (4973ms)

Related

Get all transactions for an NFT on Solana

I want to collect all transactions for an NFT.
For example, you can display all transactions here:
https://explorer.solana.com/address/2Nzt8TYeAfgJDftKzkb7rgYShVvyXTR7cPVvpqaZ2a4V
or here:
https://solscan.io/token/2Nzt8TYeAfgJDftKzkb7rgYShVvyXTR7cPVvpqaZ2a4V#txs
But is there any way to do this with the API?
I checked
solana-py: https://michaelhly.github.io/solana-py/
and solscan api: https://public-api.solscan.io/docs/
But I could not find a way to do it.
You can use the getSignaturesForAddress RPC method on the mint address and walk backward to get all the transactions.
Here is an example in JS:
import {
Connection,
clusterApiUrl,
ConfirmedSignatureInfo,
PublicKey,
} from "#solana/web3.js";
const connection = new Connection(clusterApiUrl("mainnet-beta"));
export const getTxs = async (connection: Connection, pubkey: PublicKey) => {
const txs: ConfirmedSignatureInfo[] = [];
// Walk backward
let lastTransactions = await connection.getConfirmedSignaturesForAddress2(
pubkey
);
let before = lastTransactions[lastTransactions.length - 1].signature;
txs.push(...lastTransactions);
while (true) {
const newTransactions = await connection.getConfirmedSignaturesForAddress2(
pubkey,
{
before,
}
);
if (newTransactions.length === 0) break;
txs.push(...newTransactions);
before = newTransactions[newTransactions.length - 1].signature;
}
return txs;
};
getTxs(
connection,
new PublicKey("2Nzt8TYeAfgJDftKzkb7rgYShVvyXTR7cPVvpqaZ2a4V")
);
The equivalent method in Solana.py is this one https://michaelhly.github.io/solana-py/rpc/api/#solana.rpc.api.Client.get_signatures_for_address

Buy NFT from wallet1 which has all minted nft to the user wallet connected with phantom, Javascript, Solana

Here is my code to transfer nft from Alice Account (which has my all minted nfts) and feePayer account which will buy from the Alice Wallet. Well this works perfectly fine like this. But the problem is when the same transection I try to sign and send with phantom wallet it gives me an error (You can check it by the commented line 101 to 108) when I uncomment the phantom signAndSend method code and try to execute it, it gives me error RPC req rejected but the same is successfully done with the connection.sendTransaction.
That was problem 1,
Now problem 2 is that
In this case, I had used feePayer which had the keypair already, but if I want to make it as user connects with connectWallet button, ill had only publicKey of the user. Now in that situaion how can i make the the nft transfer from Alice wallet to the user who connected and clicked on buy?
JS Code:
const sendNft = async () => {
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"3DdVyZuANr5en2PQymCPmoFBMsfdhjaRHqnk3ejW*************************************************"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
bs58.decode(
"2YQDdnfxiHPKu9GypLX1yXaQTQojvDSPgFkDxrU*************************************************"
)
);
const mintPubkey = new PublicKey(
"A8SJfwzKJAaMrY6Lb9FxZCfmVMVLcjKvRuzAiNiU6of5"
);
const getProvider = async () => {
if ("solana" in window) {
// opens wallet to connect to
await window.solana.connect();
const provider = window.solana;
if (provider.isPhantom) {
console.log("Is Phantom installed? ", provider.isPhantom);
return provider;
}
} else {
window.open("https://www.phantom.app/", "_blank");
}
};
window.solana.on("connect", () => console.log("connected!"))
const network = "https://api.devnet.solana.com";
const connection = new Connection(network);
var prodivder = await getProvider();
console.log(prodivder.publicKey.toString())
var provider = await getProvider()
console.log(provider)
// calculate ATA
let accountAlice = await Token.getAssociatedTokenAddress(
ASSOCIATED_TOKEN_PROGRAM_ID, // always ASSOCIATED_TOKEN_PROGRAM_ID
TOKEN_PROGRAM_ID, // always TOKEN_PROGRAM_ID
mintPubkey, // mint
alice.publicKey // owner
);
console.log(`ATA: ${accountAlice.toBase58()}`);
let tx3 = new Transaction().add(
Token.createAssociatedTokenAccountInstruction(
ASSOCIATED_TOKEN_PROGRAM_ID, // always ASSOCIATED_TOKEN_PROGRAM_ID
TOKEN_PROGRAM_ID, // always TOKEN_PROGRAM_ID
mintPubkey, // mint
accountAlice, // ata
alice.publicKey, // owner of token account
alice.publicKey // fee payer
)
);
// calculate ATA
let accountPayer = await Token.getAssociatedTokenAddress(
ASSOCIATED_TOKEN_PROGRAM_ID, // always ASSOCIATED_TOKEN_PROGRAM_ID
TOKEN_PROGRAM_ID, // always TOKEN_PROGRAM_ID
mintPubkey, // mint
feePayer.publicKey // owner
);
console.log(`ATA: ${accountPayer.toBase58()}`);
let tx2 = new Transaction().add(
Token.createAssociatedTokenAccountInstruction(
ASSOCIATED_TOKEN_PROGRAM_ID, // always ASSOCIATED_TOKEN_PROGRAM_ID
TOKEN_PROGRAM_ID, // always TOKEN_PROGRAM_ID
mintPubkey, // mint
accountPayer, // ata
feePayer.publicKey, // owner of token account
feePayer.publicKey // fee payer
)
);
// console.log(`txhash: ${await connection.sendTransaction(tx2, [feePayer])}`);
let tx = new Transaction().add(
Token.createTransferCheckedInstruction(
TOKEN_PROGRAM_ID, // always TOKEN_PROGRAM_ID
accountAlice, // from (should be a token account)
mintPubkey, // mint
accountPayer, // to (should be a token account)
alice.publicKey, // owner of from
[], // for multisig account, leave empty.
1, // amount, if your deciamls is 8, send 10^8 for 1 token
0 // decimals
)
);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Commenting out this, thus is the phantom codes
tx2.recentBlockhash = (await connection.getRecentBlockhash()).blockhash;
tx2.feePayer = feePayer.publicKey;
const { signature } = await window.solana.signAndSendTransaction(tx2);
await connection.confirmTransaction(signature);
// phantom code ends
console.log(`txhash: ${await connection.sendTransaction(tx, [feePayer, alice /* fee payer + owner */])}`);
};

Write rows to BigQuery via nodejs BigQuery Storage Write API

It seems quite new, but just hoping someone here has been able to use nodejs to write directly to BigQuery storage using #google-cloud/bigquery-storage.
There is an explanation of how the overall backend API works and how to write a collection of rows atomically using BigQuery Write API but no such documentation for nodejs yet. A recent release 2.7.0 documents the addition of said feature but there is no documentation, and the code is not easily understood.
There is an open issue requesting an example but thought I'd try my luck to see if anyone has been able to use this API yet.
Suppose you have a BigQuery table called student with three columns id,name and age. Following steps will get you to load data into the table with nodejs storage write api.
Define student.proto file as follows
syntax = "proto2";
message Student {
required int64 id = 1;
optional string name = 2;
optional int64 age = 3;
}
Run the following at the command prompt
protoc --js_out=import_style=commonjs,binary:. student.proto
It should generate student_pb.js file in the current directory.
Write the following js code in the current directory and run it
const {BigQueryWriteClient} = require('#google-cloud/bigquery-storage').v1;
const st = require('./student_pb.js')
const type = require('#google-cloud/bigquery-storage').protos.google.protobuf.FieldDescriptorProto.Type
const mode = require('#google-cloud/bigquery-storage').protos.google.cloud.bigquery.storage.v1.WriteStream.Type
const storageClient = new BigQueryWriteClient();
const parent = `projects/${project}/datasets/${dataset}/tables/student`
var writeStream = {type: mode.PENDING}
var student = new st.Student()
var protoDescriptor = {}
protoDescriptor.name = 'student'
protoDescriptor.field = [{'name':'id','number':1,'type':type.TYPE_INT64},{'name':'name','number':2,'type':type.TYPE_STRING},{'name':'age','number':3,'type':type.TYPE_INT64}]
async function run() {
try {
var request = {
parent,
writeStream
}
var response = await storageClient.createWriteStream(request);
writeStream = response[0].name
var serializedRows = []
//Row 1
student.setId(1)
student.setName('st1')
student.setAge(15)
serializedRows.push(student.serializeBinary())
//Row 2
student.setId(2)
student.setName('st2')
student.setAge(15)
serializedRows.push(student.serializeBinary())
var protoRows = {
serializedRows
}
var proto_data = {
writerSchema: {protoDescriptor},
rows: protoRows
}
// Construct request
request = {
writeStream,
protoRows: proto_data
};
// Insert rows
const stream = await storageClient.appendRows();
stream.on('data', response => {
console.log(response);
});
stream.on('error', err => {
throw err;
});
stream.on('end', async () => {
/* API call completed */
try {
var response = await storageClient.finalizeWriteStream({name: writeStream})
response = await storageClient.batchCommitWriteStreams({parent,writeStreams: [writeStream]})
}
catch(err) {
console.log(err)
}
});
stream.write(request);
stream.end();
}
catch(err) {
console.log(err)
}
}
run();
Make sure your environment variables are set correctly to point to the file containing google cloud credentials.
Change project and dataset values accordingly.

How to send a message when a trello card is moved to a certain list

I’m currently making a bot that informs me when a card is moved to the list titled Passed Applications.
I have already made the code and it basically sends a message once a card is moved to the specific list, however, it will randomly send a message and pull a card minutes/hours after it has already been pulled and sent the message.
What I’ve done so far is:
trello.js
var Trello = require("node-trello"),
EventEmitter = require("events").EventEmitter,
extend = require("extend"),
config,
trello,
timer,
e;
module.exports = function(options) {
var defaults = {
pollFrequency: 1000 * 60,
minId: 0,
trello: {
key: "",
token: "",
boards: []
},
start: true
};
e = new EventEmitter();
config = extend(true, defaults, options);
trello = new Trello(
process.env.TRELLO_API_KEY,
process.env.TRELLO_OAUTH_TOKEN
);
if (config.start) {
process.nextTick(function() {
start(config.pollFrequency, true);
});
}
function start(frequency, immediate) {
if (timer) {
return;
}
frequency = frequency || config.pollFrequency;
timer = setInterval(poll, frequency);
if (immediate) {
poll();
}
}
function poll() {
config.trello.boards.forEach(function(boardId) {
getBoardActivity(boardId);
});
}
function getBoardActivity(boardId) {
trello.get("/1/boards/" + boardId + "/actions", function(err, resp) {
if (err) {
return e.emit("trelloError", err);
}
var boardActions = resp.reverse();
var actionId;
for (var ix in boardActions) {
actionId = parseInt(boardActions[ix].id, 16);
if (actionId <= config.minId) {
continue;
}
var eventType = boardActions[ix].type;
e.emit(eventType, boardActions[ix], boardId);
}
config.minId = Math.max(config.minId, actionId);
e.emit("maxId", config.minId);
});
}
index.js
const conf = JSON.parse(fs.readFileSync("trelloconfig.json"));
let latestActivityID = fs.existsSync("./latestActivityID") ?
fs.readFileSync("./latestActivityID") :
0;
const eventEnabled = type =>
conf.enabledEvents.length > 0 ? conf.enabledEvents.includes(type) : true;
const TrelloEvents = require("./trello.js");
const events = new TrelloEvents({
pollFrequency: 60000,
minId: latestActivityID,
start: false,
trello: {
boards: conf.boardIDs,
key: process.env.TRELLO_API_KEY,
token: process.env.TRELLO_OAUTH_TOKEN
}
});
client.on("ready", () => {
events.start();
console.log(`[STATUS CHANGE] ${client.user.username} is now online.`);
client.user.setActivity("Cookout Grill");
});
events.on("updateCard", (event, board) => {
if (event.data.old.hasOwnProperty("idList")) {
if (!eventEnabled(`cardListChanged`)) return;
if (event.data.listAfter.name === "Passed Applications") {
let robloxId = event.data.card.name.split(" | ")[0];
client.channels.get("730839109236424756").send(robloxId);
if (database.find(x => x.RobloxUser === robloxId)) {
let data = database.find(x => x.RobloxUser === robloxId);
const person = client.users.get(data.DiscordID);
let embed = new discord.RichEmbed()
.setThumbnail(
"https://www.roblox.com/bust-thumbnail/image?userId=" +
data.RobloxID +
"&width=420&height=420&format=png"
)
.setTitle("APPLICATION RESULTS | Passed")
.setColor("3ef72d")
.setFooter("Cookout Grill", client.user.avatarURL)
.setDescription(
"Greetings, **" +
data.RobloxUser +
"**!\n\nAfter extensive review by our Management Team, we have decided to accept your Trainee Application at Cookout Grill. We believe that your application showed that you’re ready to become a staff member at our establishment.\n\nWe would like to congratulate you on passing your Trainee Application. Your application met our critical expectations and requirements in order to pass.\n\nIn order to work your way up throughout the staff ranks, you must attend a training at [Cookout Grill’s Training Center](https://www.roblox.com/groups/5634772/Cookout-Grill#!/about) during the specific session times. If you’re unable to attend one of our designated sessions, feel free to schedule a private session with a member of our Management Team.\n\nWe wish you the best of luck in continuing throughout the staff ranks at Cookout Grill. If you have any further questions, please do not hesitate to create a ticket in our main Discord Server."
)
.addField("**NEW RANK**", "`Trainee`");
person.send(embed);
roblox.message(
event.data.card.name.split(" | ")[1],
"APPLICATION RESULTS | Passed",
"Greetings, **" +
data.RobloxUser +
"**!\n\nAfter extensive review by our Management Team, we have decided to accept your Trainee Application at Cookout Grill.\n\nWe would like to congratulate you on passing your Trainee Application. Your application met our critical expectations and requirements in order to pass.\n\nIn order to work your way up throughout the staff ranks, you must attend a training at Cookout Grill’s Training Center during the specific session times. If you’re unable to attend one of our designated sessions, feel free to schedule a private session with a member of our Management Team.\n\nWe wish you the best of luck in continuing throughout the staff ranks at Cookout Grill."
);
}
let embed2 = new discord.RichEmbed()
.setTitle(`Card list changed!`)
.setDescription(
`**CARD:** ${
event.data.card.name
} — **[CARD LINK](https://trello.com/c/${
event.data.card.shortLink
})**\n\n**EVENT:** Card moved to list __${
event.data.listAfter.name
}__ from list __${event.data.listBefore.name}__ by **[${
conf.realNames
? event.memberCreator.fullName
: event.memberCreator.username
}](https://trello.com/${event.memberCreator.username})**`
);
client.channels.get("730839109236424756").send(embed2);
Trello.addCommentToCard(
event.data.card.id,
"User has been ranked.",
function(error, trelloCard) {
console.log(error);
}
);
} else return;
} else return;
});

Using API tags for a library

I'm currently creating a library for an API. The endpoints have optional tags, and so I'm trying to create a way to use them in the functions.
import * as request from "request";
class Api {
key: string;
constructor(userInput: string) {
this.key = userInput;
}
champions(tags: object) {
Object.keys(tags).forEach(function(key) {
console.log(key + " = " + tags[key])
})
request(`https://api.champion.gg/v2/champions?api_key=${this.key}&${tags}`, function (error, response, body) {
if(!error && response.statusCode == 200) {
let info = JSON.parse(body)
}
});
}
}
var test = new Api("key")
test.champions({"champData": ["kda", "damage"], "rawr": ["xd", "lmao"]})
So far, the combining of Object.keys and forEach has allowed me to get the response of champData=kda,damage and rawr=xd,lmao, however, I need to be able to assign these to a variable that's usable in the URL. How can I get this to work?
Another issue that may occur later on is that, between each tag, there needs to be an & symbol, but not at the end. I apologize for throwing multiple problems into one, but because this is my first experience with something like this, I'm having many issues.
You can use Object.entries() and URLSearchParams()
const tags = {a:1, b:2, c:3};
const params = new URLSearchParams();
const key = "def";
Object.entries(tags).forEach(([key, prop]) => params.set(key, prop));
const url = `https://api.champion.gg/v2/champions?api_key=${key}&${params.toString()}`;
console.log(url);